uriplaylistbin: add properties reporting the current state of the playlist

This commit is contained in:
Guillaume Desmottes 2021-12-22 11:38:43 +01:00
parent 9783d01a35
commit b7c08933aa
2 changed files with 134 additions and 25 deletions

View file

@ -7,7 +7,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::{Mutex, MutexGuard};
use gst::glib; use gst::glib;
use gst::prelude::*; use gst::prelude::*;
@ -123,6 +123,10 @@ struct State {
streaming: Vec<Item>, streaming: Vec<Item>,
// items which have been fully played, waiting to be cleaned up // items which have been fully played, waiting to be cleaned up
done: Vec<Item>, done: Vec<Item>,
// read-only properties
current_iteration: u32,
current_uri_index: u64,
} }
impl State { impl State {
@ -141,6 +145,8 @@ impl State {
blocked: None, blocked: None,
streaming: vec![], streaming: vec![],
done: vec![], done: vec![],
current_iteration: 0,
current_uri_index: 0,
} }
} }
@ -717,6 +723,24 @@ impl ObjectImpl for UriPlaylistBin {
1, 1,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
glib::ParamSpecUInt::new(
"current-iteration",
"Current iteration",
"The index of the current playlist iteration, or 0 if the iterations property is 0 (unlimited playlist)",
0,
u32::MAX,
0,
glib::ParamFlags::READABLE,
),
glib::ParamSpecUInt64::new(
"current-uri-index",
"Current URI",
"The index from the uris property of the current URI being played",
0,
u64::MAX,
0,
glib::ParamFlags::READABLE,
),
] ]
}); });
@ -769,6 +793,22 @@ impl ObjectImpl for UriPlaylistBin {
let settings = self.settings.lock().unwrap(); let settings = self.settings.lock().unwrap();
settings.iterations.to_value() settings.iterations.to_value()
} }
"current-iteration" => {
let state = self.state.lock().unwrap();
state
.as_ref()
.map(|state| state.current_iteration)
.unwrap_or(0)
.to_value()
}
"current-uri-index" => {
let state = self.state.lock().unwrap();
state
.as_ref()
.map(|state| state.current_uri_index)
.unwrap_or(0)
.to_value()
}
_ => unimplemented!(), _ => unimplemented!(),
} }
} }
@ -980,6 +1020,8 @@ impl UriPlaylistBin {
// unblock last item // unblock last item
state.unblock_item(element); state.unblock_item(element);
self.update_current(state_guard);
return Ok(()); return Ok(());
} }
}; };
@ -1115,6 +1157,8 @@ impl UriPlaylistBin {
} }
state.waiting_for_stream_collection = None; state.waiting_for_stream_collection = None;
self.update_current(state_guard);
} }
} }
Ok(()) Ok(())
@ -1431,6 +1475,8 @@ impl UriPlaylistBin {
item.set_blocked(); item.set_blocked();
state.blocked = Some(item); state.blocked = Some(item);
self.update_current(state_guard);
true true
} else { } else {
false false
@ -1571,5 +1617,40 @@ impl UriPlaylistBin {
); );
} }
} }
self.update_current(self.state.lock().unwrap());
}
fn update_current(&self, mut state_guard: MutexGuard<Option<State>>) {
let (uris_len, infinite) = {
let settings = self.settings.lock().unwrap();
(settings.uris.len(), settings.iterations == 0)
};
if let Some(state) = state_guard.as_mut() {
// first streaming item is the one actually being played
if let Some(current) = state.streaming.get(0) {
let (mut current_iteration, current_uri_index) = (
(current.index() / uris_len) as u32,
(current.index() % uris_len) as u64,
);
if infinite {
current_iteration = 0;
}
let element = self.instance();
if current_iteration != state.current_iteration {
state.current_iteration = current_iteration;
element.notify("current-iteration");
}
if current_uri_index != state.current_uri_index {
state.current_uri_index = current_uri_index;
element.notify("current-uri-index");
}
}
}
} }
} }

View file

@ -76,7 +76,7 @@ fn test(
n_streams: u32, n_streams: u32,
iterations: u32, iterations: u32,
check_streams: bool, check_streams: bool,
) -> Vec<gst::Message> { ) -> (Vec<gst::Message>, u32, u64) {
init(); init();
let playlist_len = medias.len() * (iterations as usize); let playlist_len = medias.len() * (iterations as usize);
@ -99,6 +99,9 @@ fn test(
playlist.set_property("uris", &uris); playlist.set_property("uris", &uris);
playlist.set_property("iterations", &iterations); playlist.set_property("iterations", &iterations);
assert_eq!(playlist.property::<u32>("current-iteration"), 0);
assert_eq!(playlist.property::<u64>("current-uri-index"), 0);
let mq_clone = mq.clone(); let mq_clone = mq.clone();
playlist.connect_pad_added(move |_playlist, src_pad| { playlist.connect_pad_added(move |_playlist, src_pad| {
let mq_sink = mq_clone.request_pad_simple("sink_%u").unwrap(); let mq_sink = mq_clone.request_pad_simple("sink_%u").unwrap();
@ -185,9 +188,12 @@ fn test(
} }
} }
let current_iteration = playlist.property::<u32>("current-iteration");
let current_uri_index = playlist.property::<u64>("current-uri-index");
pipeline.set_state(gst::State::Null).unwrap(); pipeline.set_state(gst::State::Null).unwrap();
events (events, current_iteration, current_uri_index)
} }
fn assert_eos(msg: gst::Message) { fn assert_eos(msg: gst::Message) {
@ -234,66 +240,88 @@ fn assert_stream_selected(msg: gst::Message, n_streams: usize) -> gst::Object {
#[test] #[test]
fn single_audio() { fn single_audio() {
let events = test(vec![TestMedia::ogg()], 1, 1, true).into_iter(); let (events, current_iteration, current_uri_index) = test(vec![TestMedia::ogg()], 1, 1, true);
assert_eos(events.last().unwrap()); assert_eos(events.into_iter().last().unwrap());
assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 0);
} }
#[test] #[test]
fn single_video() { fn single_video() {
let events = test(vec![TestMedia::mkv()], 2, 1, true).into_iter(); let (events, current_iteration, current_uri_index) = test(vec![TestMedia::mkv()], 2, 1, true);
assert_eos(events.last().unwrap()); assert_eos(events.into_iter().last().unwrap());
assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 0);
} }
#[test] #[test]
fn multi_audio() { fn multi_audio() {
let events = test( let (events, current_iteration, current_uri_index) = test(
vec![TestMedia::ogg(), TestMedia::ogg(), TestMedia::ogg()], vec![TestMedia::ogg(), TestMedia::ogg(), TestMedia::ogg()],
1, 1,
1, 1,
true, true,
) );
.into_iter(); assert_eos(events.into_iter().last().unwrap());
assert_eos(events.last().unwrap()); assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 2);
} }
#[test] #[test]
fn multi_audio_video() { fn multi_audio_video() {
let events = test(vec![TestMedia::mkv(), TestMedia::mkv()], 2, 1, true).into_iter(); let (events, current_iteration, current_uri_index) =
assert_eos(events.last().unwrap()); test(vec![TestMedia::mkv(), TestMedia::mkv()], 2, 1, true);
assert_eos(events.into_iter().last().unwrap());
assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 1);
} }
#[test] #[test]
fn iterations() { fn iterations() {
let events = test(vec![TestMedia::mkv(), TestMedia::mkv()], 2, 2, true).into_iter(); let (events, current_iteration, current_uri_index) =
assert_eos(events.last().unwrap()); test(vec![TestMedia::mkv(), TestMedia::mkv()], 2, 2, true);
assert_eos(events.into_iter().last().unwrap());
assert_eq!(current_iteration, 1);
assert_eq!(current_uri_index, 1);
} }
#[test] #[test]
fn nb_streams_increasing() { fn nb_streams_increasing() {
let events = test(vec![TestMedia::ogg(), TestMedia::mkv()], 2, 1, false).into_iter(); let (events, current_iteration, current_uri_index) =
assert_eos(events.last().unwrap()); test(vec![TestMedia::ogg(), TestMedia::mkv()], 2, 1, false);
assert_eos(events.into_iter().last().unwrap());
assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 1);
} }
#[test] #[test]
fn missing_file() { fn missing_file() {
let events = test( let (events, current_iteration, current_uri_index) = test(
vec![TestMedia::ogg(), TestMedia::missing_file()], vec![TestMedia::ogg(), TestMedia::missing_file()],
1, 1,
1, 1,
false, false,
) );
.into_iter(); assert_error(
assert_error(events.last().unwrap(), TestMedia::missing_file()); events.into_iter().last().unwrap(),
TestMedia::missing_file(),
);
assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 0);
} }
#[test] #[test]
fn missing_http() { fn missing_http() {
let events = test( let (events, current_iteration, current_uri_index) = test(
vec![TestMedia::ogg(), TestMedia::missing_http()], vec![TestMedia::ogg(), TestMedia::missing_http()],
1, 1,
1, 1,
false, false,
) );
.into_iter(); assert_error(
assert_error(events.last().unwrap(), TestMedia::missing_http()); events.into_iter().last().unwrap(),
TestMedia::missing_http(),
);
assert_eq!(current_iteration, 0);
assert_eq!(current_uri_index, 0);
} }