threadshare: introduce TaskImpl trait

TaskImpl is the trait for specific Task behaviour. It is the basis
of a new Task model. The main motivation for this model is to ease
threadsafe implementations of state transitions.

See https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/298
This commit is contained in:
François Laignel 2020-04-20 21:35:06 +02:00
parent b3138ad041
commit 1bea2ad279
16 changed files with 3437 additions and 2138 deletions

View file

@ -21,7 +21,7 @@ gst-net = { package = "gstreamer-net", git = "https://gitlab.freedesktop.org/gst
gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" } gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" } gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
pin-project = "0.4" pin-project = "0.4"
tokio = { git = "https://github.com/fengalin/tokio", tag = "tokio-0.2.12-throttling", features = ["io-util", "macros", "rt-core", "sync", "stream", "time", "tcp", "udp", "rt-util"] } tokio = { git = "https://github.com/fengalin/tokio", branch = "fengalin/throttling", features = ["io-util", "macros", "rt-core", "sync", "stream", "time", "tcp", "udp", "rt-util"] }
futures = "0.3" futures = "0.3"
lazy_static = "1.0" lazy_static = "1.0"
rand = "0.7" rand = "0.7"

View file

@ -17,6 +17,7 @@
// Boston, MA 02110-1335, USA. // Boston, MA 02110-1335, USA.
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::future::BoxFuture;
use futures::lock::Mutex as FutMutex; use futures::lock::Mutex as FutMutex;
use futures::prelude::*; use futures::prelude::*;
@ -37,7 +38,7 @@ use std::sync::Mutex as StdMutex;
use std::u32; use std::u32;
use crate::runtime::prelude::*; use crate::runtime::prelude::*;
use crate::runtime::{Context, PadSrc, PadSrcRef, Task}; use crate::runtime::{Context, PadSrc, PadSrcRef, PadSrcWeak, Task, TaskState};
const DEFAULT_CONTEXT: &str = ""; const DEFAULT_CONTEXT: &str = "";
const DEFAULT_CONTEXT_WAIT: u32 = 0; const DEFAULT_CONTEXT_WAIT: u32 = 0;
@ -167,16 +168,12 @@ impl AppSrcPadHandler {
.caps = caps; .caps = caps;
} }
fn reset_state(&self) { async fn reset_state(&self) {
*self.0.state.try_lock().expect("State locked elsewhere") = Default::default(); *self.0.state.lock().await = Default::default();
} }
fn set_need_segment(&self) { async fn set_need_segment(&self) {
self.0 self.0.state.lock().await.need_segment = true;
.state
.try_lock()
.expect("State locked elsewhere")
.need_segment = true;
} }
async fn push_prelude(&self, pad: &PadSrcRef<'_>, _element: &gst::Element) { async fn push_prelude(&self, pad: &PadSrcRef<'_>, _element: &gst::Element) {
@ -209,7 +206,7 @@ impl AppSrcPadHandler {
} }
async fn push_item( async fn push_item(
self, &self,
pad: &PadSrcRef<'_>, pad: &PadSrcRef<'_>,
element: &gst::Element, element: &gst::Element,
item: StreamItem, item: StreamItem,
@ -224,6 +221,12 @@ impl AppSrcPadHandler {
pad.push(buffer).await pad.push(buffer).await
} }
StreamItem::Event(event) => { StreamItem::Event(event) => {
match event.view() {
gst::EventView::Eos(_) => {
// Let the caller push the event
Err(gst::FlowError::Eos)
}
_ => {
gst_log!(CAT, obj: pad.gst_pad(), "Forwarding {:?}", event); gst_log!(CAT, obj: pad.gst_pad(), "Forwarding {:?}", event);
pad.push_event(event).await; pad.push_event(event).await;
Ok(gst::FlowSuccess::Ok) Ok(gst::FlowSuccess::Ok)
@ -231,6 +234,8 @@ impl AppSrcPadHandler {
} }
} }
} }
}
}
impl PadSrcHandler for AppSrcPadHandler { impl PadSrcHandler for AppSrcPadHandler {
type ElementImpl = AppSrc; type ElementImpl = AppSrc;
@ -239,7 +244,7 @@ impl PadSrcHandler for AppSrcPadHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
appsrc: &AppSrc, appsrc: &AppSrc,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -248,11 +253,11 @@ impl PadSrcHandler for AppSrcPadHandler {
let ret = match event.view() { let ret = match event.view() {
EventView::FlushStart(..) => { EventView::FlushStart(..) => {
appsrc.flush_start(element); appsrc.task.flush_start();
true true
} }
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
appsrc.flush_stop(element); appsrc.task.flush_stop();
true true
} }
EventView::Reconfigure(..) => true, EventView::Reconfigure(..) => true,
@ -316,11 +321,112 @@ impl PadSrcHandler for AppSrcPadHandler {
} }
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug)]
enum AppSrcState { struct AppSrcTask {
Paused, element: gst::Element,
RejectBuffers, src_pad: PadSrcWeak,
Started, src_pad_handler: AppSrcPadHandler,
receiver: mpsc::Receiver<StreamItem>,
}
impl AppSrcTask {
fn new(
element: &gst::Element,
src_pad: &PadSrc,
src_pad_handler: &AppSrcPadHandler,
receiver: mpsc::Receiver<StreamItem>,
) -> Self {
AppSrcTask {
element: element.clone(),
src_pad: src_pad.downgrade(),
src_pad_handler: src_pad_handler.clone(),
receiver,
}
}
}
impl AppSrcTask {
fn flush(&mut self) {
// Purge the channel
while let Ok(Some(_item)) = self.receiver.try_next() {}
}
}
impl TaskImpl for AppSrcTask {
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let item = self.receiver.next().await;
let item = match item {
Some(item) => item,
None => {
gst_error!(CAT, obj: &self.element, "SrcPad channel aborted");
gst_element_error!(
&self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason: channel aborted"]
);
return Err(gst::FlowError::Flushing);
}
};
let pad = self.src_pad.upgrade().expect("PadSrc no longer exists");
let res = self
.src_pad_handler
.push_item(&pad, &self.element, item)
.await;
match res {
Ok(_) => {
gst_log!(CAT, obj: &self.element, "Successfully pushed item");
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: &self.element, "EOS");
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: &self.element, "Flushing");
}
Err(err) => {
gst_error!(CAT, obj: &self.element, "Got error {}", err);
gst_element_error!(
&self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
}
res.map(drop)
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task");
self.flush();
self.src_pad_handler.reset_state().await;
gst_log!(CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
fn flush_start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Starting task flush");
self.flush();
self.src_pad_handler.set_need_segment().await;
gst_log!(CAT, obj: &self.element, "Task flush started");
}
.boxed()
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -328,17 +434,15 @@ struct AppSrc {
src_pad: PadSrc, src_pad: PadSrc,
src_pad_handler: AppSrcPadHandler, src_pad_handler: AppSrcPadHandler,
task: Task, task: Task,
state: StdMutex<AppSrcState>,
sender: StdMutex<Option<mpsc::Sender<StreamItem>>>, sender: StdMutex<Option<mpsc::Sender<StreamItem>>>,
receiver: StdMutex<Option<Arc<FutMutex<mpsc::Receiver<StreamItem>>>>>,
settings: StdMutex<Settings>, settings: StdMutex<Settings>,
} }
impl AppSrc { impl AppSrc {
fn push_buffer(&self, element: &gst::Element, mut buffer: gst::Buffer) -> bool { fn push_buffer(&self, element: &gst::Element, mut buffer: gst::Buffer) -> bool {
let state = self.state.lock().unwrap(); let state = self.task.lock_state();
if *state == AppSrcState::RejectBuffers { if *state != TaskState::Started && *state != TaskState::Paused {
gst_debug!(CAT, obj: element, "Rejecting buffer due to pad state"); gst_debug!(CAT, obj: element, "Rejecting buffer due to element state");
return false; return false;
} }
@ -411,188 +515,51 @@ impl AppSrc {
let (sender, receiver) = mpsc::channel(max_buffers); let (sender, receiver) = mpsc::channel(max_buffers);
*self.sender.lock().unwrap() = Some(sender); *self.sender.lock().unwrap() = Some(sender);
*self.receiver.lock().unwrap() = Some(Arc::new(FutMutex::new(receiver)));
self.task.prepare(context).map_err(|err| { self.src_pad_handler.prepare(settings.caps.clone());
self.task
.prepare(
AppSrcTask::new(element, &self.src_pad, &self.src_pad_handler, receiver),
context,
)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
) )
})?; })?;
self.src_pad_handler.prepare(settings.caps.clone());
gst_debug!(CAT, obj: element, "Prepared"); gst_debug!(CAT, obj: element, "Prepared");
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Unpreparing"); gst_debug!(CAT, obj: element, "Unpreparing");
*self.sender.lock().unwrap() = None; *self.sender.lock().unwrap() = None;
*self.receiver.lock().unwrap() = None;
self.task.unprepare().unwrap(); self.task.unprepare().unwrap();
gst_debug!(CAT, obj: element, "Unprepared"); gst_debug!(CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
let mut state = self.state.lock().unwrap();
gst_debug!(CAT, obj: element, "Stopping"); gst_debug!(CAT, obj: element, "Stopping");
self.flush(element);
self.src_pad_handler.reset_state();
*state = AppSrcState::RejectBuffers;
gst_debug!(CAT, obj: element, "Stopped");
Ok(())
}
fn flush(&self, element: &gst::Element) {
gst_log!(CAT, obj: element, "Flushing");
self.task.stop(); self.task.stop();
gst_debug!(CAT, obj: element, "Stopped");
let receiver = self.receiver.lock().unwrap();
let mut receiver = receiver
.as_ref()
.unwrap()
.try_lock()
.expect("receiver locked elsewhere");
// Purge the channel
loop {
match receiver.try_next() {
Ok(Some(_item)) => {
gst_log!(CAT, obj: element, "Dropping pending item");
}
Err(_) => {
gst_log!(CAT, obj: element, "No more pending item");
break;
}
Ok(None) => {
panic!("Channel sender dropped");
}
}
}
self.src_pad_handler.set_need_segment();
gst_log!(CAT, obj: element, "Flushed");
}
fn start(&self, element: &gst::Element) -> Result<(), ()> {
let mut state = self.state.lock().unwrap();
if *state == AppSrcState::Started {
gst_debug!(CAT, obj: element, "Already started");
return Ok(());
} }
fn start(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Starting"); gst_debug!(CAT, obj: element, "Starting");
self.task.start();
self.start_task(element);
*state = AppSrcState::Started;
gst_debug!(CAT, obj: element, "Started"); gst_debug!(CAT, obj: element, "Started");
Ok(())
} }
fn start_task(&self, element: &gst::Element) { fn pause(&self, element: &gst::Element) {
let src_pad_handler = self.src_pad_handler.clone();
let pad_weak = self.src_pad.downgrade();
let element = element.clone();
let receiver = Arc::clone(self.receiver.lock().unwrap().as_ref().expect("No receiver"));
self.task.start(move || {
let src_pad_handler = src_pad_handler.clone();
let pad_weak = pad_weak.clone();
let element = element.clone();
let receiver = Arc::clone(&receiver);
async move {
let item = receiver.lock().await.next().await;
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
let item = match item {
Some(item) => item,
None => {
gst_log!(CAT, obj: pad.gst_pad(), "SrcPad channel aborted");
return glib::Continue(false);
}
};
match src_pad_handler.push_item(&pad, &element, item).await {
Ok(_) => {
gst_log!(CAT, obj: pad.gst_pad(), "Successfully pushed item");
glib::Continue(true)
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: pad.gst_pad(), "EOS");
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
glib::Continue(false)
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: pad.gst_pad(), "Flushing");
glib::Continue(false)
}
Err(err) => {
gst_error!(CAT, obj: pad.gst_pad(), "Got error {}", err);
gst_element_error!(
&element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
glib::Continue(false)
}
}
}
});
}
fn flush_stop(&self, element: &gst::Element) {
let mut state = self.state.lock().unwrap();
if *state == AppSrcState::Started {
gst_debug!(CAT, obj: element, "Already started");
return;
}
gst_debug!(CAT, obj: element, "Stopping Flush");
self.flush(element);
self.start_task(element);
*state = AppSrcState::Started;
gst_debug!(CAT, obj: element, "Flush Stopped");
}
fn flush_start(&self, element: &gst::Element) {
let mut state = self.state.lock().unwrap();
gst_debug!(CAT, obj: element, "Starting Flush");
self.task.cancel();
*state = AppSrcState::RejectBuffers;
gst_debug!(CAT, obj: element, "Flush Started");
}
fn pause(&self, element: &gst::Element) -> Result<(), ()> {
let mut state = self.state.lock().unwrap();
gst_debug!(CAT, obj: element, "Pausing"); gst_debug!(CAT, obj: element, "Pausing");
self.task.pause(); self.task.pause();
*state = AppSrcState::Paused;
gst_debug!(CAT, obj: element, "Paused"); gst_debug!(CAT, obj: element, "Paused");
Ok(())
} }
} }
@ -671,9 +638,7 @@ impl ObjectSubclass for AppSrc {
), ),
src_pad_handler, src_pad_handler,
task: Task::default(), task: Task::default(),
state: StdMutex::new(AppSrcState::RejectBuffers),
sender: StdMutex::new(None), sender: StdMutex::new(None),
receiver: StdMutex::new(None),
settings: StdMutex::new(Settings::default()), settings: StdMutex::new(Settings::default()),
} }
} }
@ -749,10 +714,10 @@ impl ElementImpl for AppSrc {
})?; })?;
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
self.pause(element).map_err(|_| gst::StateChangeError)?; self.pause(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -764,13 +729,13 @@ impl ElementImpl for AppSrc {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToPlaying => { gst::StateChange::PausedToPlaying => {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
_ => (), _ => (),
} }

View file

@ -67,7 +67,6 @@ impl DataQueueItem {
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DataQueueState { pub enum DataQueueState {
Paused,
Started, Started,
Stopped, Stopped,
} }
@ -137,18 +136,6 @@ impl DataQueue {
inner.wake(); inner.wake();
} }
pub fn pause(&self) {
let mut inner = self.0.lock().unwrap();
if inner.state == DataQueueState::Paused {
gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already Paused");
return;
}
gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Pausing data queue");
assert_eq!(DataQueueState::Started, inner.state);
inner.state = DataQueueState::Paused;
inner.wake();
}
pub fn stop(&self) { pub fn stop(&self) {
let mut inner = self.0.lock().unwrap(); let mut inner = self.0.lock().unwrap();
if inner.state == DataQueueState::Stopped { if inner.state == DataQueueState::Stopped {
@ -163,7 +150,6 @@ impl DataQueue {
pub fn clear(&self) { pub fn clear(&self) {
let mut inner = self.0.lock().unwrap(); let mut inner = self.0.lock().unwrap();
assert_eq!(inner.state, DataQueueState::Paused);
gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Clearing data queue"); gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Clearing data queue");
let src_pad = inner.src_pad.clone(); let src_pad = inner.src_pad.clone();
@ -259,10 +245,6 @@ impl DataQueue {
return Some(item); return Some(item);
} }
}, },
DataQueueState::Paused => {
gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue Paused");
return None;
}
DataQueueState::Stopped => { DataQueueState::Stopped => {
gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue Stopped"); gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue Stopped");
return None; return None;

View file

@ -662,7 +662,7 @@ impl PadSinkHandler for SinkHandler {
gst_log!(CAT, obj: pad.gst_pad(), "Handling {:?}", event); gst_log!(CAT, obj: pad.gst_pad(), "Handling {:?}", event);
if let EventView::FlushStart(..) = event.view() { if let EventView::FlushStart(..) = event.view() {
jb.task.cancel(); jb.task.flush_start();
} }
gst_log!(CAT, obj: pad.gst_pad(), "Forwarding {:?}", event); gst_log!(CAT, obj: pad.gst_pad(), "Forwarding {:?}", event);
@ -699,7 +699,7 @@ impl PadSinkHandler for SinkHandler {
.unwrap(); .unwrap();
} }
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
jb.flush_stop(&element); jb.task.flush_stop();
} }
EventView::Eos(..) => { EventView::Eos(..) => {
let mut state = jb.state.lock().unwrap(); let mut state = jb.state.lock().unwrap();
@ -966,7 +966,7 @@ impl PadSrcHandler for SrcHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
jb: &JitterBuffer, jb: &JitterBuffer,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -975,10 +975,10 @@ impl PadSrcHandler for SrcHandler {
match event.view() { match event.view() {
EventView::FlushStart(..) => { EventView::FlushStart(..) => {
jb.task.cancel(); jb.task.flush_start();
} }
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
jb.flush_stop(element); jb.task.flush_stop();
} }
_ => (), _ => (),
} }
@ -1104,6 +1104,203 @@ impl Default for State {
} }
} }
struct JitterBufferTask {
element: gst::Element,
src_pad_handler: SrcHandler,
sink_pad_handler: SinkHandler,
}
impl JitterBufferTask {
fn new(
element: &gst::Element,
src_pad_handler: &SrcHandler,
sink_pad_handler: &SinkHandler,
) -> Self {
JitterBufferTask {
element: element.clone(),
src_pad_handler: src_pad_handler.clone(),
sink_pad_handler: sink_pad_handler.clone(),
}
}
}
impl TaskImpl for JitterBufferTask {
fn start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Starting task");
self.src_pad_handler.clear();
self.sink_pad_handler.clear();
let jb = JitterBuffer::from_instance(&self.element);
*jb.state.lock().unwrap() = State::default();
gst_log!(CAT, obj: &self.element, "Task started");
}
.boxed()
}
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let jb = JitterBuffer::from_instance(&self.element);
let (latency, context_wait) = {
let settings = jb.settings.lock().unwrap();
(
settings.latency_ms as u64 * gst::MSECOND,
settings.context_wait as u64 * gst::MSECOND,
)
};
loop {
let delay_fut = {
let mut state = jb.state.lock().unwrap();
let (_, next_wakeup) = self.src_pad_handler.get_next_wakeup(
&self.element,
&state,
latency,
context_wait,
);
let (delay_fut, abort_handle) = match next_wakeup {
Some((_, delay)) if delay == Duration::from_nanos(0) => (None, None),
_ => {
let (delay_fut, abort_handle) = abortable(async move {
match next_wakeup {
Some((_, delay)) => {
runtime::time::delay_for(delay).await;
}
None => {
future::pending::<()>().await;
}
};
});
let next_wakeup =
next_wakeup.map(|w| w.0).unwrap_or(gst::CLOCK_TIME_NONE);
(Some(delay_fut), Some((next_wakeup, abort_handle)))
}
};
state.wait_handle = abort_handle;
delay_fut
};
// Got aborted, reschedule if needed
if let Some(delay_fut) = delay_fut {
gst_debug!(CAT, obj: &self.element, "Waiting");
if let Err(Aborted) = delay_fut.await {
gst_debug!(CAT, obj: &self.element, "Waiting aborted");
return Ok(());
}
}
let (head_pts, head_seq) = {
let state = jb.state.lock().unwrap();
//
// Check earliest PTS as we have just taken the lock
let (now, next_wakeup) = self.src_pad_handler.get_next_wakeup(
&self.element,
&state,
latency,
context_wait,
);
gst_debug!(
CAT,
obj: &self.element,
"Woke up at {}, earliest_pts {}",
now,
state.earliest_pts
);
if let Some((next_wakeup, _)) = next_wakeup {
if next_wakeup > now {
// Reschedule and wait a bit longer in the next iteration
return Ok(());
}
} else {
return Ok(());
}
let (head_pts, head_seq) = state.jbuf.borrow().peek();
(head_pts, head_seq)
};
let res = self.src_pad_handler.pop_and_push(&self.element).await;
{
let mut state = jb.state.lock().unwrap();
state.last_res = res;
if head_pts == state.earliest_pts && head_seq == state.earliest_seqnum {
let (earliest_pts, earliest_seqnum) = state.jbuf.borrow().find_earliest();
state.earliest_pts = earliest_pts;
state.earliest_seqnum = earliest_seqnum;
}
if res.is_ok() {
// Return and reschedule if the next packet would be in the future
// Check earliest PTS as we have just taken the lock
let (now, next_wakeup) = self.src_pad_handler.get_next_wakeup(
&self.element,
&state,
latency,
context_wait,
);
if let Some((next_wakeup, _)) = next_wakeup {
if next_wakeup > now {
// Reschedule and wait a bit longer in the next iteration
return Ok(());
}
} else {
return Ok(());
}
}
}
if let Err(err) = res {
match err {
gst::FlowError::Eos => {
gst_debug!(CAT, obj: &self.element, "Pushing EOS event");
let event = gst::Event::new_eos().build();
let _ = jb.src_pad.push_event(event).await;
}
gst::FlowError::Flushing => gst_debug!(CAT, obj: &self.element, "Flushing"),
err => gst_error!(CAT, obj: &self.element, "Error {}", err),
}
return Err(err);
}
}
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task");
let jb = JitterBuffer::from_instance(&self.element);
let mut jb_state = jb.state.lock().unwrap();
if let Some((_, abort_handle)) = jb_state.wait_handle.take() {
abort_handle.abort();
}
self.src_pad_handler.clear();
self.sink_pad_handler.clear();
*jb_state = State::default();
gst_log!(CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
}
struct JitterBuffer { struct JitterBuffer {
sink_pad: PadSink, sink_pad: PadSink,
src_pad: PadSrc, src_pad: PadSrc,
@ -1139,7 +1336,12 @@ impl JitterBuffer {
Context::acquire(&settings.context, settings.context_wait).unwrap() Context::acquire(&settings.context, settings.context_wait).unwrap()
}; };
self.task.prepare(context).map_err(|err| { self.task
.prepare(
JitterBufferTask::new(element, &self.src_pad_handler, &self.sink_pad_handler),
context,
)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
@ -1159,187 +1361,15 @@ impl JitterBuffer {
fn start(&self, element: &gst::Element) { fn start(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Starting"); gst_debug!(CAT, obj: element, "Starting");
self.task.start();
*self.state.lock().unwrap() = State::default();
self.sink_pad_handler.clear();
self.src_pad_handler.clear();
self.start_task(element);
gst_debug!(CAT, obj: element, "Started"); gst_debug!(CAT, obj: element, "Started");
} }
fn start_task(&self, element: &gst::Element) {
let src_pad_handler = self.src_pad_handler.clone();
let element = element.clone();
self.task.start(move || {
let src_pad_handler = src_pad_handler.clone();
let element = element.clone();
async move {
let jb = JitterBuffer::from_instance(&element);
let (latency, context_wait) = {
let settings = jb.settings.lock().unwrap();
(
settings.latency_ms as u64 * gst::MSECOND,
settings.context_wait as u64 * gst::MSECOND,
)
};
loop {
let delay_fut = {
let mut state = jb.state.lock().unwrap();
let (_, next_wakeup) = src_pad_handler.get_next_wakeup(
&element,
&state,
latency,
context_wait,
);
let (delay_fut, abort_handle) = match next_wakeup {
Some((_, delay)) if delay == Duration::from_nanos(0) => (None, None),
_ => {
let (delay_fut, abort_handle) = abortable(async move {
match next_wakeup {
Some((_, delay)) => {
runtime::time::delay_for(delay).await;
}
None => {
future::pending::<()>().await;
}
};
});
let next_wakeup =
next_wakeup.map(|w| w.0).unwrap_or(gst::CLOCK_TIME_NONE);
(Some(delay_fut), Some((next_wakeup, abort_handle)))
}
};
state.wait_handle = abort_handle;
delay_fut
};
// Got aborted, reschedule if needed
if let Some(delay_fut) = delay_fut {
gst_debug!(CAT, obj: &element, "Waiting");
if let Err(Aborted) = delay_fut.await {
gst_debug!(CAT, obj: &element, "Waiting aborted");
return glib::Continue(true);
}
}
let (head_pts, head_seq) = {
let state = jb.state.lock().unwrap();
//
// Check earliest PTS as we have just taken the lock
let (now, next_wakeup) = src_pad_handler.get_next_wakeup(
&element,
&state,
latency,
context_wait,
);
gst_debug!(
CAT,
obj: &element,
"Woke up at {}, earliest_pts {}",
now,
state.earliest_pts
);
if let Some((next_wakeup, _)) = next_wakeup {
if next_wakeup > now {
// Reschedule and wait a bit longer in the next iteration
return glib::Continue(true);
}
} else {
return glib::Continue(true);
}
let (head_pts, head_seq) = state.jbuf.borrow().peek();
(head_pts, head_seq)
};
let res = src_pad_handler.pop_and_push(&element).await;
{
let mut state = jb.state.lock().unwrap();
state.last_res = res;
if head_pts == state.earliest_pts && head_seq == state.earliest_seqnum {
let (earliest_pts, earliest_seqnum) =
state.jbuf.borrow().find_earliest();
state.earliest_pts = earliest_pts;
state.earliest_seqnum = earliest_seqnum;
}
if res.is_ok() {
// Return and reschedule if the next packet would be in the future
// Check earliest PTS as we have just taken the lock
let (now, next_wakeup) = src_pad_handler.get_next_wakeup(
&element,
&state,
latency,
context_wait,
);
if let Some((next_wakeup, _)) = next_wakeup {
if next_wakeup > now {
// Reschedule and wait a bit longer in the next iteration
return glib::Continue(true);
}
} else {
return glib::Continue(true);
}
}
}
match res {
Ok(_) => (),
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: &element, "Pushing EOS event",);
let event = gst::Event::new_eos().build();
let _ = jb.src_pad.push_event(event).await;
return glib::Continue(false);
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: &element, "Flushing",);
return glib::Continue(false);
}
Err(err) => {
gst_error!(CAT, obj: &element, "Error {}", err,);
return glib::Continue(false);
}
}
}
}
});
}
fn stop(&self, element: &gst::Element) { fn stop(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Stopping"); gst_debug!(CAT, obj: element, "Stopping");
if let Some((_, abort_handle)) = self.state.lock().unwrap().wait_handle.take() {
abort_handle.abort();
}
self.task.stop(); self.task.stop();
self.src_pad_handler.clear();
self.sink_pad_handler.clear();
*self.state.lock().unwrap() = State::default();
gst_debug!(CAT, obj: element, "Stopped"); gst_debug!(CAT, obj: element, "Stopped");
} }
fn flush_stop(&self, element: &gst::Element) {
self.task.stop();
self.start(element);
}
} }
impl ObjectSubclass for JitterBuffer { impl ObjectSubclass for JitterBuffer {

View file

@ -41,7 +41,7 @@ use crate::runtime::{
Context, PadSink, PadSinkRef, PadSinkWeak, PadSrc, PadSrcRef, PadSrcWeak, Task, Context, PadSink, PadSinkRef, PadSinkWeak, PadSrc, PadSrcRef, PadSrcWeak, Task,
}; };
use super::dataqueue::{DataQueue, DataQueueItem, DataQueueState}; use super::dataqueue::{DataQueue, DataQueueItem};
lazy_static! { lazy_static! {
static ref PROXY_CONTEXTS: StdMutex<HashMap<String, Weak<StdMutex<ProxyContextInner>>>> = static ref PROXY_CONTEXTS: StdMutex<HashMap<String, Weak<StdMutex<ProxyContextInner>>>> =
@ -357,7 +357,7 @@ impl PadSinkHandler for ProxySinkPadHandler {
}; };
if let EventView::FlushStart(..) = event.view() { if let EventView::FlushStart(..) = event.view() {
proxysink.stop(&element).unwrap(); proxysink.stop(&element);
} }
if let Some(src_pad) = src_pad { if let Some(src_pad) = src_pad {
@ -391,7 +391,7 @@ impl PadSinkHandler for ProxySinkPadHandler {
let _ = let _ =
element.post_message(&gst::Message::new_eos().src(Some(&element)).build()); element.post_message(&gst::Message::new_eos().src(Some(&element)).build());
} }
EventView::FlushStop(..) => proxysink.start(&element).unwrap(), EventView::FlushStop(..) => proxysink.start(&element),
_ => (), _ => (),
} }
@ -421,25 +421,13 @@ lazy_static! {
} }
impl ProxySink { impl ProxySink {
fn schedule_pending_queue( async fn schedule_pending_queue(&self, element: &gst::Element) {
&self,
element: &gst::Element,
pending_queue: &mut PendingQueue,
) -> impl Future<Output = ()> {
gst_log!(SINK_CAT, obj: element, "Scheduling pending queue now");
pending_queue.scheduled = true;
let element = element.clone();
async move {
let sink = Self::from_instance(&element);
loop { loop {
let more_queue_space_receiver = { let more_queue_space_receiver = {
let proxy_ctx = sink.proxy_ctx.lock().unwrap(); let proxy_ctx = self.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared(); let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
gst_log!(SINK_CAT, obj: &element, "Trying to empty pending queue"); gst_log!(SINK_CAT, obj: element, "Trying to empty pending queue");
let ProxyContextInner { let ProxyContextInner {
pending_queue: ref mut pq, pending_queue: ref mut pq,
@ -464,7 +452,7 @@ impl ProxySink {
receiver receiver
} else { } else {
gst_log!(SINK_CAT, obj: &element, "Pending queue is empty now"); gst_log!(SINK_CAT, obj: element, "Pending queue is empty now");
*pq = None; *pq = None;
return; return;
} }
@ -475,17 +463,16 @@ impl ProxySink {
receiver receiver
} }
} else { } else {
gst_log!(SINK_CAT, obj: &element, "Flushing, dropping pending queue"); gst_log!(SINK_CAT, obj: element, "Flushing, dropping pending queue");
*pq = None; *pq = None;
return; return;
} }
}; };
gst_log!(SINK_CAT, obj: &element, "Waiting for more queue space"); gst_log!(SINK_CAT, obj: element, "Waiting for more queue space");
let _ = more_queue_space_receiver.await; let _ = more_queue_space_receiver.await;
} }
} }
}
async fn enqueue_item( async fn enqueue_item(
&self, &self,
@ -563,7 +550,10 @@ impl ProxySink {
); );
if schedule_now { if schedule_now {
let wait_fut = self.schedule_pending_queue(element, pending_queue); gst_log!(SINK_CAT, obj: element, "Scheduling pending queue now");
pending_queue.scheduled = true;
let wait_fut = self.schedule_pending_queue(element);
Some(wait_fut) Some(wait_fut)
} else { } else {
gst_log!(SINK_CAT, obj: element, "Scheduling pending queue later"); gst_log!(SINK_CAT, obj: element, "Scheduling pending queue later");
@ -624,15 +614,13 @@ impl ProxySink {
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(SINK_CAT, obj: element, "Unpreparing"); gst_debug!(SINK_CAT, obj: element, "Unpreparing");
*self.proxy_ctx.lock().unwrap() = None; *self.proxy_ctx.lock().unwrap() = None;
gst_debug!(SINK_CAT, obj: element, "Unprepared"); gst_debug!(SINK_CAT, obj: element, "Unprepared");
Ok(())
} }
fn start(&self, element: &gst::Element) -> Result<(), ()> { fn start(&self, element: &gst::Element) {
let proxy_ctx = self.proxy_ctx.lock().unwrap(); let proxy_ctx = self.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared(); let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
@ -647,11 +635,9 @@ impl ProxySink {
shared_ctx.last_res = Ok(gst::FlowSuccess::Ok); shared_ctx.last_res = Ok(gst::FlowSuccess::Ok);
gst_debug!(SINK_CAT, obj: element, "Started"); gst_debug!(SINK_CAT, obj: element, "Started");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
let proxy_ctx = self.proxy_ctx.lock().unwrap(); let proxy_ctx = self.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared(); let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
@ -661,8 +647,6 @@ impl ProxySink {
shared_ctx.last_res = Err(gst::FlowError::Flushing); shared_ctx.last_res = Err(gst::FlowError::Flushing);
gst_debug!(SINK_CAT, obj: element, "Stopped"); gst_debug!(SINK_CAT, obj: element, "Stopped");
Ok(())
} }
} }
@ -762,10 +746,10 @@ impl ElementImpl for ProxySink {
})?; })?;
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -773,7 +757,7 @@ impl ElementImpl for ProxySink {
let success = self.parent_change_state(element, transition)?; let success = self.parent_change_state(element, transition)?;
if transition == gst::StateChange::ReadyToPaused { if transition == gst::StateChange::ReadyToPaused {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
Ok(success) Ok(success)
@ -792,7 +776,7 @@ impl ProxySrcPadHandler {
{ {
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap(); let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared(); let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
if let Some(ref mut pending_queue) = shared_ctx.pending_queue { if let Some(pending_queue) = shared_ctx.pending_queue.as_mut() {
pending_queue.notify_more_queue_space(); pending_queue.notify_more_queue_space();
} }
} }
@ -822,7 +806,7 @@ impl PadSrcHandler for ProxySrcPadHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
proxysrc: &ProxySrc, proxysrc: &ProxySrc,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -841,8 +825,8 @@ impl PadSrcHandler for ProxySrcPadHandler {
}; };
match event.view() { match event.view() {
EventView::FlushStart(..) => proxysrc.stop(element).unwrap(), EventView::FlushStart(..) => proxysrc.task.flush_start(),
EventView::FlushStop(..) => proxysrc.flush_stop(element), EventView::FlushStop(..) => proxysrc.task.flush_stop(),
_ => (), _ => (),
} }
@ -903,6 +887,138 @@ impl PadSrcHandler for ProxySrcPadHandler {
} }
} }
#[derive(Debug)]
struct ProxySrcTask {
element: gst::Element,
src_pad: PadSrcWeak,
dataqueue: DataQueue,
}
impl ProxySrcTask {
fn new(element: &gst::Element, src_pad: &PadSrc, dataqueue: DataQueue) -> Self {
ProxySrcTask {
element: element.clone(),
src_pad: src_pad.downgrade(),
dataqueue,
}
}
}
impl TaskImpl for ProxySrcTask {
fn start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(SRC_CAT, obj: &self.element, "Starting task");
let proxysrc = ProxySrc::from_instance(&self.element);
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Ok(gst::FlowSuccess::Ok);
if let Some(pending_queue) = shared_ctx.pending_queue.as_mut() {
pending_queue.notify_more_queue_space();
}
self.dataqueue.start();
gst_log!(SRC_CAT, obj: &self.element, "Task started");
}
.boxed()
}
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let item = self.dataqueue.next().await;
let item = match item {
Some(item) => item,
None => {
gst_log!(SRC_CAT, obj: &self.element, "DataQueue Stopped");
return Err(gst::FlowError::Flushing);
}
};
let pad = self.src_pad.upgrade().expect("PadSrc no longer exists");
let proxysrc = ProxySrc::from_instance(&self.element);
let res = ProxySrcPadHandler::push_item(&pad, &proxysrc, item).await;
match res {
Ok(()) => {
gst_log!(SRC_CAT, obj: &self.element, "Successfully pushed item");
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Ok(gst::FlowSuccess::Ok);
}
Err(gst::FlowError::Flushing) => {
gst_debug!(SRC_CAT, obj: &self.element, "Flushing");
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Err(gst::FlowError::Flushing);
}
Err(gst::FlowError::Eos) => {
gst_debug!(SRC_CAT, obj: &self.element, "EOS");
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Err(gst::FlowError::Eos);
}
Err(err) => {
gst_error!(SRC_CAT, obj: &self.element, "Got error {}", err);
gst_element_error!(
&self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Err(err);
}
}
res
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(SRC_CAT, obj: &self.element, "Stopping task");
let proxysrc = ProxySrc::from_instance(&self.element);
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
self.dataqueue.clear();
self.dataqueue.stop();
shared_ctx.last_res = Err(gst::FlowError::Flushing);
if let Some(mut pending_queue) = shared_ctx.pending_queue.take() {
pending_queue.notify_more_queue_space();
}
gst_log!(SRC_CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
fn flush_start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(SRC_CAT, obj: &self.element, "Starting task flush");
let proxysrc = ProxySrc::from_instance(&self.element);
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
self.dataqueue.clear();
shared_ctx.last_res = Err(gst::FlowError::Flushing);
gst_log!(SRC_CAT, obj: &self.element, "Task flush started");
}
.boxed()
}
}
#[derive(Debug)] #[derive(Debug)]
struct ProxySrc { struct ProxySrc {
src_pad: PadSrc, src_pad: PadSrc,
@ -971,9 +1087,11 @@ impl ProxySrc {
*self.proxy_ctx.lock().unwrap() = Some(proxy_ctx); *self.proxy_ctx.lock().unwrap() = Some(proxy_ctx);
*self.dataqueue.lock().unwrap() = Some(dataqueue); *self.dataqueue.lock().unwrap() = Some(dataqueue.clone());
self.task.prepare(ts_ctx).map_err(|err| { self.task
.prepare(ProxySrcTask::new(element, &self.src_pad, dataqueue), ts_ctx)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
@ -985,7 +1103,7 @@ impl ProxySrc {
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(SRC_CAT, obj: element, "Unpreparing"); gst_debug!(SRC_CAT, obj: element, "Unpreparing");
{ {
@ -1000,154 +1118,24 @@ impl ProxySrc {
*self.proxy_ctx.lock().unwrap() = None; *self.proxy_ctx.lock().unwrap() = None;
gst_debug!(SRC_CAT, obj: element, "Unprepared"); gst_debug!(SRC_CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
// Keep the lock on the `dataqueue` until `stop` is complete
// so as to prevent race conditions due to concurrent FlushStart/Stop.
// Note that this won't deadlock as `ProxySrc::dataqueue` guards a pointer to
// the `dataqueue` used within the `src_pad`'s `Task`.
let dataqueue = self.dataqueue.lock().unwrap();
gst_debug!(SRC_CAT, obj: element, "Stopping"); gst_debug!(SRC_CAT, obj: element, "Stopping");
self.task.stop(); self.task.stop();
let dataqueue = dataqueue.as_ref().unwrap();
dataqueue.clear();
dataqueue.stop();
gst_debug!(SRC_CAT, obj: element, "Stopped"); gst_debug!(SRC_CAT, obj: element, "Stopped");
Ok(())
}
fn start(&self, element: &gst::Element) -> Result<(), ()> {
let dataqueue = self.dataqueue.lock().unwrap();
let dataqueue = dataqueue.as_ref().unwrap();
if dataqueue.state() == DataQueueState::Started {
gst_debug!(SRC_CAT, obj: element, "Already started");
return Ok(());
} }
fn start(&self, element: &gst::Element) {
gst_debug!(SRC_CAT, obj: element, "Starting"); gst_debug!(SRC_CAT, obj: element, "Starting");
self.task.start();
self.start_unchecked(element, dataqueue);
gst_debug!(SRC_CAT, obj: element, "Started"); gst_debug!(SRC_CAT, obj: element, "Started");
Ok(())
} }
fn start_unchecked(&self, element: &gst::Element, dataqueue: &DataQueue) { fn pause(&self, element: &gst::Element) {
dataqueue.start();
{
let proxy_ctx = self.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
if let Some(pending_queue) = shared_ctx.pending_queue.as_mut() {
pending_queue.notify_more_queue_space();
}
}
self.start_task(element, dataqueue);
}
fn start_task(&self, element: &gst::Element, dataqueue: &DataQueue) {
let pad_weak = self.src_pad.downgrade();
let dataqueue = dataqueue.clone();
let element = element.clone();
self.task.start(move || {
let pad_weak = pad_weak.clone();
let mut dataqueue = dataqueue.clone();
let element = element.clone();
async move {
let item = dataqueue.next().await;
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
let item = match item {
Some(item) => item,
None => {
gst_log!(SRC_CAT, obj: pad.gst_pad(), "DataQueue Stopped or Paused");
return glib::Continue(false);
}
};
let proxysrc = ProxySrc::from_instance(&element);
match ProxySrcPadHandler::push_item(&pad, &proxysrc, item).await {
Ok(_) => {
gst_log!(SRC_CAT, obj: pad.gst_pad(), "Successfully pushed item");
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Ok(gst::FlowSuccess::Ok);
glib::Continue(true)
}
Err(gst::FlowError::Flushing) => {
gst_debug!(SRC_CAT, obj: pad.gst_pad(), "Flushing");
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Err(gst::FlowError::Flushing);
glib::Continue(false)
}
Err(gst::FlowError::Eos) => {
gst_debug!(SRC_CAT, obj: pad.gst_pad(), "EOS");
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Err(gst::FlowError::Eos);
glib::Continue(false)
}
Err(err) => {
gst_error!(SRC_CAT, obj: pad.gst_pad(), "Got error {}", err);
gst_element_error!(
element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
let proxy_ctx = proxysrc.proxy_ctx.lock().unwrap();
let mut shared_ctx = proxy_ctx.as_ref().unwrap().lock_shared();
shared_ctx.last_res = Err(err);
glib::Continue(false)
}
}
}
});
}
fn flush_stop(&self, element: &gst::Element) {
// Keep the lock on the `dataqueue` until `flush_stop` is complete
// so as to prevent race conditions due to concurrent state transitions.
// Note that this won't deadlock as `ProxySrc::dataqueue` guards a pointer to
// the `dataqueue` used within the `src_pad`'s `Task`.
let dataqueue = self.dataqueue.lock().unwrap();
let dataqueue = dataqueue.as_ref().unwrap();
if dataqueue.state() == DataQueueState::Started {
gst_debug!(SRC_CAT, obj: element, "Already started");
return;
}
gst_debug!(SRC_CAT, obj: element, "Stopping Flush");
self.task.stop();
self.start_unchecked(element, dataqueue);
gst_debug!(SRC_CAT, obj: element, "Stopped Flush");
}
fn pause(&self, element: &gst::Element) -> Result<(), ()> {
let dataqueue = self.dataqueue.lock().unwrap();
gst_debug!(SRC_CAT, obj: element, "Pausing"); gst_debug!(SRC_CAT, obj: element, "Pausing");
dataqueue.as_ref().unwrap().pause();
self.task.pause(); self.task.pause();
gst_debug!(SRC_CAT, obj: element, "Paused"); gst_debug!(SRC_CAT, obj: element, "Paused");
Ok(())
} }
} }
@ -1276,10 +1264,10 @@ impl ElementImpl for ProxySrc {
})?; })?;
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
self.pause(element).map_err(|_| gst::StateChangeError)?; self.pause(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -1291,13 +1279,13 @@ impl ElementImpl for ProxySrc {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToPlaying => { gst::StateChange::PausedToPlaying => {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
_ => (), _ => (),
} }

View file

@ -35,9 +35,9 @@ use std::sync::Mutex as StdMutex;
use std::{u32, u64}; use std::{u32, u64};
use crate::runtime::prelude::*; use crate::runtime::prelude::*;
use crate::runtime::{Context, PadSink, PadSinkRef, PadSrc, PadSrcRef, Task}; use crate::runtime::{Context, PadSink, PadSinkRef, PadSrc, PadSrcRef, PadSrcWeak, Task};
use super::dataqueue::{DataQueue, DataQueueItem, DataQueueState}; use super::dataqueue::{DataQueue, DataQueueItem};
const DEFAULT_MAX_SIZE_BUFFERS: u32 = 200; const DEFAULT_MAX_SIZE_BUFFERS: u32 = 200;
const DEFAULT_MAX_SIZE_BYTES: u32 = 1024 * 1024; const DEFAULT_MAX_SIZE_BYTES: u32 = 1024 * 1024;
@ -185,7 +185,7 @@ impl PadSinkHandler for QueuePadSinkHandler {
&self, &self,
pad: &PadSinkRef, pad: &PadSinkRef,
queue: &Queue, queue: &Queue,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -193,7 +193,7 @@ impl PadSinkHandler for QueuePadSinkHandler {
gst_debug!(CAT, obj: pad.gst_pad(), "Handling non-serialized {:?}", event); gst_debug!(CAT, obj: pad.gst_pad(), "Handling non-serialized {:?}", event);
if let EventView::FlushStart(..) = event.view() { if let EventView::FlushStart(..) = event.view() {
queue.stop(&element).unwrap(); queue.task.flush_start();
} }
gst_log!(CAT, obj: pad.gst_pad(), "Forwarding non-serialized {:?}", event); gst_log!(CAT, obj: pad.gst_pad(), "Forwarding non-serialized {:?}", event);
@ -218,7 +218,7 @@ impl PadSinkHandler for QueuePadSinkHandler {
let queue = Queue::from_instance(&element); let queue = Queue::from_instance(&element);
if let EventView::FlushStop(..) = event.view() { if let EventView::FlushStop(..) = event.view() {
queue.flush_stop(&element); queue.task.flush_stop();
} }
gst_log!(CAT, obj: pad.gst_pad(), "Queuing serialized {:?}", event); gst_log!(CAT, obj: pad.gst_pad(), "Queuing serialized {:?}", event);
@ -256,11 +256,9 @@ struct QueuePadSrcHandler;
impl QueuePadSrcHandler { impl QueuePadSrcHandler {
async fn push_item( async fn push_item(
pad: &PadSrcRef<'_>, pad: &PadSrcRef<'_>,
element: &gst::Element, queue: &Queue,
item: DataQueueItem, item: DataQueueItem,
) -> Result<(), gst::FlowError> { ) -> Result<(), gst::FlowError> {
let queue = Queue::from_instance(element);
if let Some(pending_queue) = queue.pending_queue.lock().unwrap().as_mut() { if let Some(pending_queue) = queue.pending_queue.lock().unwrap().as_mut() {
pending_queue.notify_more_queue_space(); pending_queue.notify_more_queue_space();
} }
@ -290,7 +288,7 @@ impl PadSrcHandler for QueuePadSrcHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
queue: &Queue, queue: &Queue,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -298,8 +296,8 @@ impl PadSrcHandler for QueuePadSrcHandler {
gst_log!(CAT, obj: pad.gst_pad(), "Handling {:?}", event); gst_log!(CAT, obj: pad.gst_pad(), "Handling {:?}", event);
match event.view() { match event.view() {
EventView::FlushStart(..) => queue.stop(element).unwrap(), EventView::FlushStart(..) => queue.task.flush_start(),
EventView::FlushStop(..) => queue.flush_stop(element), EventView::FlushStop(..) => queue.task.flush_stop(),
_ => (), _ => (),
} }
@ -346,6 +344,129 @@ impl PadSrcHandler for QueuePadSrcHandler {
} }
} }
#[derive(Debug)]
struct QueueTask {
element: gst::Element,
src_pad: PadSrcWeak,
dataqueue: DataQueue,
}
impl QueueTask {
fn new(element: &gst::Element, src_pad: &PadSrc, dataqueue: DataQueue) -> Self {
QueueTask {
element: element.clone(),
src_pad: src_pad.downgrade(),
dataqueue,
}
}
}
impl TaskImpl for QueueTask {
fn start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Starting task");
let queue = Queue::from_instance(&self.element);
let mut last_res = queue.last_res.lock().unwrap();
self.dataqueue.start();
*last_res = Ok(gst::FlowSuccess::Ok);
gst_log!(CAT, obj: &self.element, "Task started");
}
.boxed()
}
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let item = self.dataqueue.next().await;
let item = match item {
Some(item) => item,
None => {
gst_log!(CAT, obj: &self.element, "DataQueue Stopped");
return Err(gst::FlowError::Flushing);
}
};
let pad = self.src_pad.upgrade().expect("PadSrc no longer exists");
let queue = Queue::from_instance(&self.element);
let res = QueuePadSrcHandler::push_item(&pad, &queue, item).await;
match res {
Ok(()) => {
gst_log!(CAT, obj: &self.element, "Successfully pushed item");
*queue.last_res.lock().unwrap() = Ok(gst::FlowSuccess::Ok);
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: &self.element, "Flushing");
*queue.last_res.lock().unwrap() = Err(gst::FlowError::Flushing);
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: &self.element, "EOS");
*queue.last_res.lock().unwrap() = Err(gst::FlowError::Eos);
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
}
Err(err) => {
gst_error!(CAT, obj: &self.element, "Got error {}", err);
gst_element_error!(
&self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
*queue.last_res.lock().unwrap() = Err(err);
}
}
res
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task");
let queue = Queue::from_instance(&self.element);
let mut last_res = queue.last_res.lock().unwrap();
self.dataqueue.stop();
self.dataqueue.clear();
if let Some(mut pending_queue) = queue.pending_queue.lock().unwrap().take() {
pending_queue.notify_more_queue_space();
}
*last_res = Err(gst::FlowError::Flushing);
gst_log!(CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
fn flush_start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Starting task flush");
let queue = Queue::from_instance(&self.element);
let mut last_res = queue.last_res.lock().unwrap();
self.dataqueue.clear();
if let Some(mut pending_queue) = queue.pending_queue.lock().unwrap().take() {
pending_queue.notify_more_queue_space();
}
*last_res = Err(gst::FlowError::Flushing);
gst_log!(CAT, obj: &self.element, "Task flush started");
}
.boxed()
}
}
#[derive(Debug)] #[derive(Debug)]
struct Queue { struct Queue {
sink_pad: PadSink, sink_pad: PadSink,
@ -405,28 +526,16 @@ impl Queue {
/* Schedules emptying of the pending queue. If there is an upstream /* Schedules emptying of the pending queue. If there is an upstream
* TaskContext, the new task is spawned, it is otherwise * TaskContext, the new task is spawned, it is otherwise
* returned, for the caller to block on */ * returned, for the caller to block on */
fn schedule_pending_queue( async fn schedule_pending_queue(&self, element: &gst::Element) {
&self,
element: &gst::Element,
pending_queue: &mut Option<PendingQueue>,
) -> impl Future<Output = ()> {
gst_log!(CAT, obj: element, "Scheduling pending queue now");
pending_queue.as_mut().unwrap().scheduled = true;
let element = element.clone();
async move {
let queue = Self::from_instance(&element);
loop { loop {
let more_queue_space_receiver = { let more_queue_space_receiver = {
let dataqueue = queue.dataqueue.lock().unwrap(); let dataqueue = self.dataqueue.lock().unwrap();
if dataqueue.is_none() { if dataqueue.is_none() {
return; return;
} }
let mut pending_queue_grd = queue.pending_queue.lock().unwrap(); let mut pending_queue_grd = self.pending_queue.lock().unwrap();
gst_log!(CAT, obj: &element, "Trying to empty pending queue"); gst_log!(CAT, obj: element, "Trying to empty pending queue");
if let Some(pending_queue) = pending_queue_grd.as_mut() { if let Some(pending_queue) = pending_queue_grd.as_mut() {
let mut failed_item = None; let mut failed_item = None;
@ -443,21 +552,20 @@ impl Queue {
receiver receiver
} else { } else {
gst_log!(CAT, obj: &element, "Pending queue is empty now"); gst_log!(CAT, obj: element, "Pending queue is empty now");
*pending_queue_grd = None; *pending_queue_grd = None;
return; return;
} }
} else { } else {
gst_log!(CAT, obj: &element, "Flushing, dropping pending queue"); gst_log!(CAT, obj: element, "Flushing, dropping pending queue");
return; return;
} }
}; };
gst_log!(CAT, obj: &element, "Waiting for more queue space"); gst_log!(CAT, obj: element, "Waiting for more queue space");
let _ = more_queue_space_receiver.await; let _ = more_queue_space_receiver.await;
} }
} }
}
async fn enqueue_item( async fn enqueue_item(
&self, &self,
@ -503,7 +611,10 @@ impl Queue {
); );
if schedule_now { if schedule_now {
let wait_fut = self.schedule_pending_queue(element, &mut pending_queue); gst_log!(CAT, obj: element, "Scheduling pending queue now");
pending_queue.as_mut().unwrap().scheduled = true;
let wait_fut = self.schedule_pending_queue(element);
Some(wait_fut) Some(wait_fut)
} else { } else {
gst_log!(CAT, obj: element, "Scheduling pending queue later"); gst_log!(CAT, obj: element, "Scheduling pending queue later");
@ -551,7 +662,7 @@ impl Queue {
}, },
); );
*self.dataqueue.lock().unwrap() = Some(dataqueue); *self.dataqueue.lock().unwrap() = Some(dataqueue.clone());
let context = let context =
Context::acquire(&settings.context, settings.context_wait).map_err(|err| { Context::acquire(&settings.context, settings.context_wait).map_err(|err| {
@ -561,7 +672,9 @@ impl Queue {
) )
})?; })?;
self.task.prepare(context).map_err(|err| { self.task
.prepare(QueueTask::new(element, &self.src_pad, dataqueue), context)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
@ -573,7 +686,7 @@ impl Queue {
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Unpreparing"); gst_debug!(CAT, obj: element, "Unpreparing");
self.task.unprepare().unwrap(); self.task.unprepare().unwrap();
@ -584,129 +697,18 @@ impl Queue {
*self.last_res.lock().unwrap() = Ok(gst::FlowSuccess::Ok); *self.last_res.lock().unwrap() = Ok(gst::FlowSuccess::Ok);
gst_debug!(CAT, obj: element, "Unprepared"); gst_debug!(CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
let dataqueue = self.dataqueue.lock().unwrap();
gst_debug!(CAT, obj: element, "Stopping"); gst_debug!(CAT, obj: element, "Stopping");
*self.last_res.lock().unwrap() = Err(gst::FlowError::Flushing);
self.task.stop(); self.task.stop();
if let Some(dataqueue) = dataqueue.as_ref() {
dataqueue.pause();
dataqueue.clear();
dataqueue.stop();
}
if let Some(mut pending_queue) = self.pending_queue.lock().unwrap().take() {
pending_queue.notify_more_queue_space();
}
gst_debug!(CAT, obj: element, "Stopped"); gst_debug!(CAT, obj: element, "Stopped");
Ok(())
}
fn start(&self, element: &gst::Element) -> Result<(), ()> {
let dataqueue = self.dataqueue.lock().unwrap();
let dataqueue = dataqueue.as_ref().unwrap();
if dataqueue.state() == DataQueueState::Started {
gst_debug!(CAT, obj: element, "Already started");
return Ok(());
} }
fn start(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Starting"); gst_debug!(CAT, obj: element, "Starting");
self.task.start();
dataqueue.start();
*self.last_res.lock().unwrap() = Ok(gst::FlowSuccess::Ok);
self.start_task(element, dataqueue);
gst_debug!(CAT, obj: element, "Started"); gst_debug!(CAT, obj: element, "Started");
Ok(())
}
fn start_task(&self, element: &gst::Element, dataqueue: &DataQueue) {
let pad_weak = self.src_pad.downgrade();
let dataqueue = dataqueue.clone();
let element = element.clone();
self.task.start(move || {
let pad_weak = pad_weak.clone();
let mut dataqueue = dataqueue.clone();
let element = element.clone();
async move {
let item = dataqueue.next().await;
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
let item = match item {
Some(item) => item,
None => {
gst_log!(CAT, obj: pad.gst_pad(), "DataQueue Stopped");
return glib::Continue(false);
}
};
let queue = Queue::from_instance(&element);
match QueuePadSrcHandler::push_item(&pad, &element, item).await {
Ok(()) => {
gst_log!(CAT, obj: pad.gst_pad(), "Successfully pushed item");
*queue.last_res.lock().unwrap() = Ok(gst::FlowSuccess::Ok);
glib::Continue(true)
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: pad.gst_pad(), "Flushing");
*queue.last_res.lock().unwrap() = Err(gst::FlowError::Flushing);
glib::Continue(false)
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: pad.gst_pad(), "EOS");
*queue.last_res.lock().unwrap() = Err(gst::FlowError::Eos);
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
glib::Continue(false)
}
Err(err) => {
gst_error!(CAT, obj: pad.gst_pad(), "Got error {}", err);
gst_element_error!(
element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
*queue.last_res.lock().unwrap() = Err(err);
glib::Continue(false)
}
}
}
});
}
fn flush_stop(&self, element: &gst::Element) {
// Keep the lock on the `dataqueue` until `flush_stop` is complete
// so as to prevent race conditions due to concurrent state transitions.
// Note that this won't deadlock as `Queue::dataqueue` guards a pointer to
// the `dataqueue` used within the `src_pad`'s `Task`.
let dataqueue = self.dataqueue.lock().unwrap();
let dataqueue = dataqueue.as_ref().unwrap();
if dataqueue.state() == DataQueueState::Started {
gst_debug!(CAT, obj: element, "Already started");
return;
}
gst_debug!(CAT, obj: element, "Stopping Flush");
dataqueue.start();
self.start_task(element, dataqueue);
gst_debug!(CAT, obj: element, "Stopped Flush");
} }
} }
@ -837,10 +839,10 @@ impl ElementImpl for Queue {
})?; })?;
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -848,7 +850,7 @@ impl ElementImpl for Queue {
let success = self.parent_change_state(element, transition)?; let success = self.parent_change_state(element, transition)?;
if transition == gst::StateChange::ReadyToPaused { if transition == gst::StateChange::ReadyToPaused {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
Ok(success) Ok(success)

View file

@ -488,6 +488,23 @@ impl Context {
} }
pub fn spawn<Fut>(&self, future: Fut) -> JoinHandle<Fut::Output> pub fn spawn<Fut>(&self, future: Fut) -> JoinHandle<Fut::Output>
where
Fut: Future + Send + 'static,
Fut::Output: Send + 'static,
{
self.spawn_internal(future, false)
}
pub fn awake_and_spawn<Fut>(&self, future: Fut) -> JoinHandle<Fut::Output>
where
Fut: Future + Send + 'static,
Fut::Output: Send + 'static,
{
self.spawn_internal(future, true)
}
#[inline]
fn spawn_internal<Fut>(&self, future: Fut, must_awake: bool) -> JoinHandle<Fut::Output>
where where
Fut: Future + Send + 'static, Fut: Future + Send + 'static,
Fut::Output: Send + 'static, Fut::Output: Send + 'static,
@ -510,7 +527,7 @@ impl Context {
real.name real.name
); );
let join_handle = real.handle.lock().unwrap().spawn(async move { let spawn_fut = async move {
let ctx = Context::current().unwrap(); let ctx = Context::current().unwrap();
let real = ctx.0.real.as_ref().unwrap(); let real = ctx.0.real.as_ref().unwrap();
@ -542,7 +559,15 @@ impl Context {
gst_trace!(RUNTIME_CAT, "Task {:?} on context {} done", id, real.name); gst_trace!(RUNTIME_CAT, "Task {:?} on context {} done", id, real.name);
res res
}); };
let join_handle = {
if must_awake {
real.handle.lock().unwrap().awake_and_spawn(spawn_fut)
} else {
real.handle.lock().unwrap().spawn(spawn_fut)
}
};
JoinHandle { JoinHandle {
join_handle, join_handle,

View file

@ -54,6 +54,7 @@ pub use task::{Task, TaskState};
pub mod prelude { pub mod prelude {
pub use super::pad::{PadSinkHandler, PadSrcHandler}; pub use super::pad::{PadSinkHandler, PadSrcHandler};
pub use super::task::TaskImpl;
} }
pub mod time; pub mod time;

File diff suppressed because it is too large Load diff

View file

@ -16,21 +16,22 @@
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, // Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA. // Boston, MA 02110-1335, USA.
use futures::future::{abortable, AbortHandle, Aborted, BoxFuture}; use futures::future::BoxFuture;
use futures::prelude::*;
use gst::prelude::*; use gst::prelude::*;
use gst::{gst_debug, gst_error, gst_error_msg}; use gst::{gst_debug, gst_error, gst_error_msg, gst_log};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::io; use std::io;
use std::sync::{Arc, Mutex};
use gio::prelude::*; use gio::prelude::*;
use gio_sys as gio_ffi; use gio_sys as gio_ffi;
use gobject_sys as gobject_ffi; use gobject_sys as gobject_ffi;
use std::error;
use std::fmt;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
@ -45,145 +46,55 @@ lazy_static! {
); );
} }
pub struct Socket<T: SocketRead + 'static>(Arc<Mutex<SocketInner<T>>>);
pub trait SocketRead: Send + Unpin { pub trait SocketRead: Send + Unpin {
const DO_TIMESTAMP: bool; const DO_TIMESTAMP: bool;
fn read<'buf>( fn read<'buf>(
&self, &'buf mut self,
buffer: &'buf mut [u8], buffer: &'buf mut [u8],
) -> BoxFuture<'buf, io::Result<(usize, Option<std::net::SocketAddr>)>>; ) -> BoxFuture<'buf, io::Result<(usize, Option<std::net::SocketAddr>)>>;
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Socket<T: SocketRead> {
pub enum SocketState {
Paused,
Prepared,
Started,
Unprepared,
}
struct SocketInner<T: SocketRead + 'static> {
state: SocketState,
element: gst::Element, element: gst::Element,
buffer_pool: gst::BufferPool, buffer_pool: gst::BufferPool,
reader: T,
mapped_buffer: Option<gst::MappedBuffer<gst::buffer::Writable>>,
clock: Option<gst::Clock>, clock: Option<gst::Clock>,
base_time: Option<gst::ClockTime>, base_time: Option<gst::ClockTime>,
create_read_handle: Option<AbortHandle>,
create_reader_fut: Option<BoxFuture<'static, Result<T, SocketError>>>,
read_handle: Option<AbortHandle>,
reader: Option<T>,
} }
impl<T: SocketRead + 'static> Socket<T> { impl<T: SocketRead> Socket<T> {
pub fn new<F>( pub fn try_new(
element: &gst::Element, element: gst::Element,
buffer_pool: gst::BufferPool, buffer_pool: gst::BufferPool,
create_reader_fut: F, reader: T,
) -> Result<Self, ()> ) -> Result<Self, ()> {
where // FIXME couldn't we just delegate this to caller?
F: Future<Output = Result<T, SocketError>> + Send + 'static, buffer_pool.set_active(true).map_err(|err| {
{ gst_error!(
let socket = Socket(Arc::new(Mutex::new(SocketInner::<T> { SOCKET_CAT,
state: SocketState::Unprepared, obj: &element,
element: element.clone(), "Failed to prepare socket: {}",
err
);
})?;
Ok(Socket::<T> {
buffer_pool, buffer_pool,
element,
reader,
mapped_buffer: None,
clock: None, clock: None,
base_time: None, base_time: None,
create_read_handle: None, })
create_reader_fut: Some(create_reader_fut.boxed()),
read_handle: None,
reader: None,
})));
let mut inner = socket.0.lock().unwrap();
if inner.state != SocketState::Unprepared {
gst_debug!(SOCKET_CAT, obj: &inner.element, "Socket already prepared");
return Err(());
}
gst_debug!(SOCKET_CAT, obj: &inner.element, "Preparing socket");
inner.buffer_pool.set_active(true).map_err(|err| {
gst_error!(SOCKET_CAT, obj: &inner.element, "Failed to prepare socket: {}", err);
})?;
inner.state = SocketState::Prepared;
drop(inner);
Ok(socket)
} }
pub fn state(&self) -> SocketState { pub fn set_clock(&mut self, clock: Option<gst::Clock>, base_time: Option<gst::ClockTime>) {
self.0.lock().unwrap().state self.clock = clock;
} self.base_time = base_time;
pub fn start(
&self,
clock: Option<gst::Clock>,
base_time: Option<gst::ClockTime>,
) -> Result<SocketStream<T>, ()> {
// Paused->Playing
let mut inner = self.0.lock().unwrap();
assert_ne!(SocketState::Unprepared, inner.state);
if inner.state == SocketState::Started {
gst_debug!(SOCKET_CAT, obj: &inner.element, "Socket already started");
return Err(());
}
gst_debug!(SOCKET_CAT, obj: &inner.element, "Starting socket");
inner.clock = clock;
inner.base_time = base_time;
inner.state = SocketState::Started;
Ok(SocketStream::<T>::new(self))
}
pub fn pause(&self) {
// Playing->Paused
let mut inner = self.0.lock().unwrap();
assert_ne!(SocketState::Unprepared, inner.state);
if inner.state != SocketState::Started {
gst_debug!(SOCKET_CAT, obj: &inner.element, "Socket not started");
return;
}
gst_debug!(SOCKET_CAT, obj: &inner.element, "Pausing socket");
inner.clock = None;
inner.base_time = None;
inner.state = SocketState::Paused;
if let Some(read_handle) = inner.read_handle.take() {
read_handle.abort();
} }
} }
}
impl<T: SocketRead> Drop for SocketInner<T> {
fn drop(&mut self) {
// Ready->Null
assert_ne!(SocketState::Started, self.state);
if self.state == SocketState::Unprepared {
gst_debug!(SOCKET_CAT, obj: &self.element, "Socket already unprepared");
return;
}
if let Some(create_read_handle_handle) = self.create_read_handle.take() {
create_read_handle_handle.abort();
}
if let Err(err) = self.buffer_pool.set_active(false) {
gst_error!(SOCKET_CAT, obj: &self.element, "Failed to unprepare socket: {}", err);
}
self.state = SocketState::Unprepared;
}
}
impl<T: SocketRead + Unpin + 'static> Clone for Socket<T> {
fn clone(&self) -> Self {
Socket::<T>(self.0.clone())
}
}
pub type SocketStreamItem = Result<(gst::Buffer, Option<std::net::SocketAddr>), SocketError>;
#[derive(Debug)] #[derive(Debug)]
pub enum SocketError { pub enum SocketError {
@ -191,98 +102,50 @@ pub enum SocketError {
Io(io::Error), Io(io::Error),
} }
pub struct SocketStream<T: SocketRead + 'static> { impl error::Error for SocketError {}
socket: Socket<T>,
mapped_buffer: Option<gst::MappedBuffer<gst::buffer::Writable>>,
}
impl<T: SocketRead + 'static> SocketStream<T> { impl fmt::Display for SocketError {
fn new(socket: &Socket<T>) -> Self { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
SocketStream { match self {
socket: socket.clone(), SocketError::Gst(err) => write!(f, "flow error: {}", err),
mapped_buffer: None, SocketError::Io(err) => write!(f, "IO error: {}", err),
}
} }
} }
pub type SocketStreamItem = Result<(gst::Buffer, Option<std::net::SocketAddr>), SocketError>;
impl<T: SocketRead> Socket<T> {
// Can't implement this as a Stream trait because we end up using things like
// tokio::net::UdpSocket which don't implement pollable functions.
#[allow(clippy::should_implement_trait)] #[allow(clippy::should_implement_trait)]
pub async fn next(&mut self) -> Option<SocketStreamItem> { pub async fn next(&mut self) -> Option<SocketStreamItem> {
// First create if needed gst_log!(SOCKET_CAT, obj: &self.element, "Trying to read data");
let (create_reader_fut, element) = {
let mut inner = self.socket.0.lock().unwrap();
if let Some(create_reader_fut) = inner.create_reader_fut.take() {
let (create_reader_fut, abort_handle) = abortable(create_reader_fut);
inner.create_read_handle = Some(abort_handle);
(Some(create_reader_fut), inner.element.clone())
} else {
(None, inner.element.clone())
}
};
if let Some(create_reader_fut) = create_reader_fut {
match create_reader_fut.await {
Ok(Ok(read)) => {
let mut inner = self.socket.0.lock().unwrap();
inner.create_read_handle = None;
inner.reader = Some(read);
}
Ok(Err(err)) => {
gst_debug!(SOCKET_CAT, obj: &element, "Create reader error {:?}", err);
return Some(Err(err));
}
Err(Aborted) => {
gst_debug!(SOCKET_CAT, obj: &element, "Create reader Aborted");
return None;
}
}
}
// take the mapped_buffer before locking the socket so as to please the mighty borrow checker
let (read_fut, clock, base_time) = {
let mut inner = self.socket.0.lock().unwrap();
if inner.state != SocketState::Started {
gst_debug!(SOCKET_CAT, obj: &inner.element, "Socket is not Started");
return None;
}
let reader = match inner.reader {
None => {
gst_debug!(SOCKET_CAT, obj: &inner.element, "Have no reader");
return None;
}
Some(ref reader) => reader,
};
gst_debug!(SOCKET_CAT, obj: &inner.element, "Trying to read data");
if self.mapped_buffer.is_none() { if self.mapped_buffer.is_none() {
match inner.buffer_pool.acquire_buffer(None) { match self.buffer_pool.acquire_buffer(None) {
Ok(buffer) => { Ok(buffer) => {
self.mapped_buffer = Some(buffer.into_mapped_buffer_writable().unwrap()); self.mapped_buffer = Some(buffer.into_mapped_buffer_writable().unwrap());
} }
Err(err) => { Err(err) => {
gst_debug!(SOCKET_CAT, obj: &inner.element, "Failed to acquire buffer {:?}", err); gst_debug!(SOCKET_CAT, obj: &self.element, "Failed to acquire buffer {:?}", err);
return Some(Err(SocketError::Gst(err))); return Some(Err(SocketError::Gst(err)));
} }
} }
} }
let (read_fut, abort_handle) = match self
abortable(reader.read(self.mapped_buffer.as_mut().unwrap().as_mut_slice())); .reader
inner.read_handle = Some(abort_handle); .read(self.mapped_buffer.as_mut().unwrap().as_mut_slice())
.await
(read_fut, inner.clock.clone(), inner.base_time) {
}; Ok((len, saddr)) => {
match read_fut.await {
Ok(Ok((len, saddr))) => {
let dts = if T::DO_TIMESTAMP { let dts = if T::DO_TIMESTAMP {
let time = clock.as_ref().unwrap().get_time(); let time = self.clock.as_ref().unwrap().get_time();
let running_time = time - base_time.unwrap(); let running_time = time - self.base_time.unwrap();
gst_debug!( gst_debug!(
SOCKET_CAT, SOCKET_CAT,
obj: &element, obj: &self.element,
"Read {} bytes at {} (clock {})", "Read {} bytes at {} (clock {})",
len, len,
running_time, running_time,
@ -290,7 +153,7 @@ impl<T: SocketRead + 'static> SocketStream<T> {
); );
running_time running_time
} else { } else {
gst_debug!(SOCKET_CAT, obj: &element, "Read {} bytes", len); gst_debug!(SOCKET_CAT, obj: &self.element, "Read {} bytes", len);
gst::CLOCK_TIME_NONE gst::CLOCK_TIME_NONE
}; };
@ -305,18 +168,21 @@ impl<T: SocketRead + 'static> SocketStream<T> {
Some(Ok((buffer, saddr))) Some(Ok((buffer, saddr)))
} }
Ok(Err(err)) => { Err(err) => {
gst_debug!(SOCKET_CAT, obj: &element, "Read error {:?}", err); gst_debug!(SOCKET_CAT, obj: &self.element, "Read error {:?}", err);
Some(Err(SocketError::Io(err))) Some(Err(SocketError::Io(err)))
} }
Err(Aborted) => {
gst_debug!(SOCKET_CAT, obj: &element, "Read Aborted");
None
} }
} }
} }
impl<T: SocketRead> Drop for Socket<T> {
fn drop(&mut self) {
if let Err(err) = self.buffer_pool.set_active(false) {
gst_error!(SOCKET_CAT, obj: &self.element, "Failed to unprepare socket: {}", err);
}
}
} }
// Send/Sync struct for passing around a gio::Socket // Send/Sync struct for passing around a gio::Socket

View file

@ -41,9 +41,9 @@ use std::u32;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use crate::runtime::prelude::*; use crate::runtime::prelude::*;
use crate::runtime::{Context, PadSrc, PadSrcRef, Task}; use crate::runtime::{Context, PadSrc, PadSrcRef, PadSrcWeak, Task};
use super::socket::{Socket, SocketError, SocketRead, SocketState}; use super::socket::{Socket, SocketError, SocketRead};
const DEFAULT_HOST: Option<&str> = Some("127.0.0.1"); const DEFAULT_HOST: Option<&str> = Some("127.0.0.1");
const DEFAULT_PORT: i32 = 4953; const DEFAULT_PORT: i32 = 4953;
@ -138,15 +138,11 @@ static PROPERTIES: [subclass::Property; 6] = [
}), }),
]; ];
struct TcpClientReaderInner { pub struct TcpClientReader(tokio::net::TcpStream);
socket: tokio::net::TcpStream,
}
pub struct TcpClientReader(Arc<FutMutex<TcpClientReaderInner>>);
impl TcpClientReader { impl TcpClientReader {
pub fn new(socket: tokio::net::TcpStream) -> Self { pub fn new(socket: tokio::net::TcpStream) -> Self {
TcpClientReader(Arc::new(FutMutex::new(TcpClientReaderInner { socket }))) TcpClientReader(socket)
} }
} }
@ -154,20 +150,10 @@ impl SocketRead for TcpClientReader {
const DO_TIMESTAMP: bool = false; const DO_TIMESTAMP: bool = false;
fn read<'buf>( fn read<'buf>(
&self, &'buf mut self,
buffer: &'buf mut [u8], buffer: &'buf mut [u8],
) -> BoxFuture<'buf, io::Result<(usize, Option<std::net::SocketAddr>)>> { ) -> BoxFuture<'buf, io::Result<(usize, Option<std::net::SocketAddr>)>> {
let this = Arc::clone(&self.0); async move { self.0.read(buffer).await.map(|read_size| (read_size, None)) }.boxed()
async move {
this.lock()
.await
.socket
.read(buffer)
.await
.map(|read_size| (read_size, None))
}
.boxed()
} }
} }
@ -206,16 +192,12 @@ impl TcpClientSrcPadHandler {
.caps = caps; .caps = caps;
} }
fn reset_state(&self) { async fn reset_state(&self) {
*self.0.state.try_lock().expect("State locked elsewhere") = Default::default(); *self.0.configured_caps.lock().unwrap() = None;
} }
fn set_need_segment(&self) { async fn set_need_segment(&self) {
self.0 self.0.state.lock().await.need_segment = true;
.state
.try_lock()
.expect("State locked elsewhere")
.need_segment = true;
} }
async fn push_prelude(&self, pad: &PadSrcRef<'_>, _element: &gst::Element) { async fn push_prelude(&self, pad: &PadSrcRef<'_>, _element: &gst::Element) {
@ -274,7 +256,7 @@ impl PadSrcHandler for TcpClientSrcPadHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
tcpclientsrc: &TcpClientSrc, tcpclientsrc: &TcpClientSrc,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -283,12 +265,12 @@ impl PadSrcHandler for TcpClientSrcPadHandler {
let ret = match event.view() { let ret = match event.view() {
EventView::FlushStart(..) => { EventView::FlushStart(..) => {
tcpclientsrc.flush_start(element); tcpclientsrc.task.flush_start();
true true
} }
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
tcpclientsrc.flush_stop(element); tcpclientsrc.task.flush_stop();
true true
} }
@ -354,11 +336,167 @@ impl PadSrcHandler for TcpClientSrcPadHandler {
} }
} }
struct TcpClientSrcTask {
element: gst::Element,
src_pad: PadSrcWeak,
src_pad_handler: TcpClientSrcPadHandler,
saddr: SocketAddr,
buffer_pool: Option<gst::BufferPool>,
socket: Option<Socket<TcpClientReader>>,
}
impl TcpClientSrcTask {
fn new(
element: &gst::Element,
src_pad: &PadSrc,
src_pad_handler: &TcpClientSrcPadHandler,
saddr: SocketAddr,
buffer_pool: gst::BufferPool,
) -> Self {
TcpClientSrcTask {
element: element.clone(),
src_pad: src_pad.downgrade(),
src_pad_handler: src_pad_handler.clone(),
saddr,
buffer_pool: Some(buffer_pool),
socket: None,
}
}
}
impl TaskImpl for TcpClientSrcTask {
fn prepare(&mut self) -> BoxFuture<'_, Result<(), gst::ErrorMessage>> {
async move {
gst_log!(CAT, obj: &self.element, "Preparing task connecting to {:?}", self.saddr);
let socket = tokio::net::TcpStream::connect(self.saddr)
.await
.map_err(|err| {
gst_error_msg!(
gst::ResourceError::OpenRead,
["Failed to connect to {:?}: {:?}", self.saddr, err]
)
})?;
self.socket = Some(
Socket::try_new(
self.element.clone(),
self.buffer_pool.take().unwrap(),
TcpClientReader::new(socket),
)
.map_err(|err| {
gst_error_msg!(
gst::ResourceError::OpenRead,
["Failed to prepare socket {:?}", err]
)
})?,
);
gst_log!(CAT, obj: &self.element, "Task prepared");
Ok(())
}
.boxed()
}
fn handle_prepare_error(&mut self, err: gst::ErrorMessage) -> BoxFuture<'_, ()> {
async move {
gst_error!(CAT, "Task preparation failed: {:?}", err);
self.element.post_error_message(&err);
}
.boxed()
}
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let item = self.socket.as_mut().unwrap().next().await;
let buffer = match item {
Some(Ok((buffer, _))) => buffer,
Some(Err(err)) => {
gst_error!(CAT, obj: &self.element, "Got error {:?}", err);
match err {
SocketError::Gst(err) => {
gst_element_error!(
self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
SocketError::Io(err) => {
gst_element_error!(
self.element,
gst::StreamError::Failed,
("I/O error"),
["streaming stopped, I/O error {}", err]
);
}
}
return Err(gst::FlowError::Error);
}
None => {
gst_log!(CAT, obj: &self.element, "SocketStream Stopped");
return Err(gst::FlowError::Flushing);
}
};
let pad = self.src_pad.upgrade().expect("PadSrc no longer exists");
let res = self
.src_pad_handler
.push_buffer(&pad, &self.element, buffer)
.await;
match res {
Ok(_) => {
gst_log!(CAT, obj: &self.element, "Successfully pushed buffer");
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: &self.element, "Flushing");
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: &self.element, "EOS");
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
}
Err(err) => {
gst_error!(CAT, obj: &self.element, "Got error {}", err);
gst_element_error!(
self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
}
res.map(drop)
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task");
self.src_pad_handler.reset_state().await;
gst_log!(CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
fn flush_stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task flush");
self.src_pad_handler.set_need_segment().await;
gst_log!(CAT, obj: &self.element, "Task flush stopped");
}
.boxed()
}
}
struct TcpClientSrc { struct TcpClientSrc {
src_pad: PadSrc, src_pad: PadSrc,
src_pad_handler: TcpClientSrcPadHandler, src_pad_handler: TcpClientSrcPadHandler,
task: Task, task: Task,
socket: StdMutex<Option<Socket<TcpClientReader>>>,
settings: StdMutex<Settings>, settings: StdMutex<Settings>,
} }
@ -414,194 +552,54 @@ impl TcpClientSrc {
})?; })?;
let saddr = SocketAddr::new(host, port as u16); let saddr = SocketAddr::new(host, port as u16);
let element_clone = element.clone();
let socket = Socket::new(element.upcast_ref(), buffer_pool, async move { self.src_pad_handler.prepare(settings.caps);
gst_debug!(CAT, obj: &element_clone, "Connecting to {:?}", saddr);
let socket = tokio::net::TcpStream::connect(saddr) self.task
.await .prepare(
.map_err(SocketError::Io)?; TcpClientSrcTask::new(
Ok(TcpClientReader::new(socket)) element,
}) &self.src_pad,
.map_err(|err| { &self.src_pad_handler,
gst_error_msg!( saddr,
gst::ResourceError::OpenRead, buffer_pool,
["Failed to prepare socket {:?}", err] ),
context,
) )
})?; .map_err(|err| {
*self.socket.lock().unwrap() = Some(socket);
self.task.prepare(context).map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
) )
})?; })?;
self.src_pad_handler.prepare(settings.caps);
gst_debug!(CAT, obj: element, "Prepared"); gst_debug!(CAT, obj: element, "Prepared");
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Unpreparing"); gst_debug!(CAT, obj: element, "Unpreparing");
*self.socket.lock().unwrap() = None;
self.task.unprepare().unwrap(); self.task.unprepare().unwrap();
gst_debug!(CAT, obj: element, "Unprepared"); gst_debug!(CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Stopping"); gst_debug!(CAT, obj: element, "Stopping");
self.task.stop(); self.task.stop();
self.src_pad_handler.reset_state();
gst_debug!(CAT, obj: element, "Stopped"); gst_debug!(CAT, obj: element, "Stopped");
Ok(())
}
fn start(&self, element: &gst::Element) -> Result<(), ()> {
let socket = self.socket.lock().unwrap();
let socket = socket.as_ref().unwrap();
if socket.state() == SocketState::Started {
gst_debug!(CAT, obj: element, "Already started");
return Ok(());
} }
fn start(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Starting"); gst_debug!(CAT, obj: element, "Starting");
self.start_task(element, socket); self.task.start();
gst_debug!(CAT, obj: element, "Started"); gst_debug!(CAT, obj: element, "Started");
Ok(())
} }
fn start_task(&self, element: &gst::Element, socket: &Socket<TcpClientReader>) { fn pause(&self, element: &gst::Element) {
let socket_stream = socket
.start(element.get_clock(), Some(element.get_base_time()))
.unwrap();
let socket_stream = Arc::new(FutMutex::new(socket_stream));
let src_pad_handler = self.src_pad_handler.clone();
let pad_weak = self.src_pad.downgrade();
let element = element.clone();
self.task.start(move || {
let src_pad_handler = src_pad_handler.clone();
let pad_weak = pad_weak.clone();
let element = element.clone();
let socket_stream = socket_stream.clone();
async move {
let item = socket_stream.lock().await.next().await;
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
let buffer = match item {
Some(Ok((buffer, _))) => buffer,
Some(Err(err)) => {
gst_error!(CAT, obj: &element, "Got error {:?}", err);
match err {
SocketError::Gst(err) => {
gst_element_error!(
element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
SocketError::Io(err) => {
gst_element_error!(
element,
gst::StreamError::Failed,
("I/O error"),
["streaming stopped, I/O error {}", err]
);
}
}
return glib::Continue(false);
}
None => {
gst_log!(CAT, obj: pad.gst_pad(), "SocketStream Stopped");
return glib::Continue(false);
}
};
match src_pad_handler.push_buffer(&pad, &element, buffer).await {
Ok(_) => {
gst_log!(CAT, obj: pad.gst_pad(), "Successfully pushed buffer");
glib::Continue(true)
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: pad.gst_pad(), "Flushing");
glib::Continue(false)
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: pad.gst_pad(), "EOS");
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
glib::Continue(false)
}
Err(err) => {
gst_error!(CAT, obj: pad.gst_pad(), "Got error {}", err);
gst_element_error!(
element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
glib::Continue(false)
}
}
}
});
}
fn flush_stop(&self, element: &gst::Element) {
let socket = self.socket.lock().unwrap();
if let Some(socket) = socket.as_ref() {
if socket.state() == SocketState::Started {
gst_debug!(CAT, obj: element, "Already started");
return;
}
gst_debug!(CAT, obj: element, "Stopping Flush");
self.src_pad_handler.set_need_segment();
self.start_task(element, socket);
gst_debug!(CAT, obj: element, "Stopped Flush");
} else {
gst_debug!(CAT, obj: element, "Socket not available");
}
}
fn flush_start(&self, element: &gst::Element) {
let socket = self.socket.lock().unwrap();
gst_debug!(CAT, obj: element, "Starting Flush");
if let Some(socket) = socket.as_ref() {
socket.pause();
}
self.task.cancel();
gst_debug!(CAT, obj: element, "Flush Started");
}
fn pause(&self, element: &gst::Element) -> Result<(), ()> {
gst_debug!(CAT, obj: element, "Pausing"); gst_debug!(CAT, obj: element, "Pausing");
self.socket.lock().unwrap().as_ref().unwrap().pause();
self.task.pause(); self.task.pause();
gst_debug!(CAT, obj: element, "Paused"); gst_debug!(CAT, obj: element, "Paused");
Ok(())
} }
} }
@ -644,7 +642,6 @@ impl ObjectSubclass for TcpClientSrc {
), ),
src_pad_handler, src_pad_handler,
task: Task::default(), task: Task::default(),
socket: StdMutex::new(None),
settings: StdMutex::new(Settings::default()), settings: StdMutex::new(Settings::default()),
} }
} }
@ -724,10 +721,10 @@ impl ElementImpl for TcpClientSrc {
})?; })?;
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
self.pause(element).map_err(|_| gst::StateChangeError)?; self.pause(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -739,13 +736,13 @@ impl ElementImpl for TcpClientSrc {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToPlaying => { gst::StateChange::PausedToPlaying => {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
_ => (), _ => (),
} }

View file

@ -827,7 +827,7 @@ impl PadSinkHandler for UdpSinkPadHandler {
async move { async move {
if let EventView::FlushStop(_) = event.view() { if let EventView::FlushStop(_) = event.view() {
let udpsink = UdpSink::from_instance(&element); let udpsink = UdpSink::from_instance(&element);
let _ = udpsink.start(&element); udpsink.task.flush_stop();
} else if let Some(sender) = sender.lock().await.as_mut() { } else if let Some(sender) = sender.lock().await.as_mut() {
if sender.send(TaskItem::Event(event)).await.is_err() { if sender.send(TaskItem::Event(event)).await.is_err() {
gst_debug!(CAT, obj: &element, "Flushing"); gst_debug!(CAT, obj: &element, "Flushing");
@ -843,17 +843,81 @@ impl PadSinkHandler for UdpSinkPadHandler {
&self, &self,
_pad: &PadSinkRef, _pad: &PadSinkRef,
udpsink: &UdpSink, udpsink: &UdpSink,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
if let EventView::FlushStart(..) = event.view() { if let EventView::FlushStart(..) = event.view() {
let _ = udpsink.stop(&element); udpsink.task.flush_start();
} }
true true
} }
} }
#[derive(Debug)]
struct UdpSinkTask {
element: gst::Element,
sink_pad_handler: UdpSinkPadHandler,
receiver: Option<mpsc::Receiver<TaskItem>>,
}
impl UdpSinkTask {
fn new(element: &gst::Element, sink_pad_handler: &UdpSinkPadHandler) -> Self {
UdpSinkTask {
element: element.clone(),
sink_pad_handler: sink_pad_handler.clone(),
receiver: None,
}
}
}
impl TaskImpl for UdpSinkTask {
fn start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Starting task");
let (sender, receiver) = mpsc::channel(0);
let mut sink_pad_handler = self.sink_pad_handler.0.write().unwrap();
sink_pad_handler.sender = Arc::new(Mutex::new(Some(sender)));
self.receiver = Some(receiver);
gst_log!(CAT, obj: &self.element, "Task started");
}
.boxed()
}
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
match self.receiver.as_mut().unwrap().next().await {
Some(TaskItem::Buffer(buffer)) => {
match self.sink_pad_handler.render(&self.element, buffer).await {
Err(err) => {
gst_element_error!(
&self.element,
gst::StreamError::Failed,
["Failed to render item, stopping task: {}", err]
);
Err(gst::FlowError::Error)
}
_ => Ok(()),
}
}
Some(TaskItem::Event(event)) => {
self.sink_pad_handler
.handle_event(&self.element, event)
.await;
Ok(())
}
None => Err(gst::FlowError::Flushing),
}
}
.boxed()
}
}
#[derive(Debug)] #[derive(Debug)]
enum SocketFamily { enum SocketFamily {
Ipv4, Ipv4,
@ -1022,7 +1086,9 @@ impl UdpSink {
self.prepare_socket(SocketFamily::Ipv4, &context, element)?; self.prepare_socket(SocketFamily::Ipv4, &context, element)?;
self.prepare_socket(SocketFamily::Ipv6, &context, element)?; self.prepare_socket(SocketFamily::Ipv6, &context, element)?;
self.task.prepare(context).map_err(|err| { self.task
.prepare(UdpSinkTask::new(&element, &self.sink_pad_handler), context)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
@ -1034,67 +1100,25 @@ impl UdpSink {
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Unpreparing"); gst_debug!(CAT, obj: element, "Unpreparing");
self.task.unprepare().unwrap(); self.task.unprepare().unwrap();
self.sink_pad_handler.unprepare(); self.sink_pad_handler.unprepare();
gst_debug!(CAT, obj: element, "Unprepared"); gst_debug!(CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Stopping"); gst_debug!(CAT, obj: element, "Stopping");
self.task.stop(); self.task.stop();
gst_debug!(CAT, obj: element, "Stopped"); gst_debug!(CAT, obj: element, "Stopped");
Ok(())
} }
fn start(&self, element: &gst::Element) -> Result<(), ()> { fn start(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Starting"); gst_debug!(CAT, obj: element, "Starting");
self.task.start();
let sink_pad_handler = self.sink_pad_handler.clone(); gst_debug!(CAT, obj: element, "Started");
let element_clone = element.clone();
let (sender, receiver) = mpsc::channel(0);
let receiver = Arc::new(Mutex::new(receiver));
sink_pad_handler.0.write().unwrap().sender = Arc::new(Mutex::new(Some(sender)));
self.task.start(move || {
let receiver = Arc::clone(&receiver);
let element = element_clone.clone();
let sink_pad_handler = sink_pad_handler.clone();
async move {
match receiver.lock().await.next().await {
Some(TaskItem::Buffer(buffer)) => {
match sink_pad_handler.render(&element, buffer).await {
Err(err) => {
gst_element_error!(
element,
gst::StreamError::Failed,
["Failed to render item, stopping task: {}", err]
);
glib::Continue(false)
}
_ => glib::Continue(true),
}
}
Some(TaskItem::Event(event)) => {
sink_pad_handler.handle_event(&element, event).await;
glib::Continue(true)
}
None => glib::Continue(false),
}
}
});
Ok(())
} }
} }
@ -1491,13 +1515,13 @@ impl ElementImpl for UdpSink {
})?; })?;
} }
gst::StateChange::ReadyToPaused => { gst::StateChange::ReadyToPaused => {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }

View file

@ -39,9 +39,9 @@ use std::sync::Mutex as StdMutex;
use std::u16; use std::u16;
use crate::runtime::prelude::*; use crate::runtime::prelude::*;
use crate::runtime::{Context, PadSrc, PadSrcRef, Task}; use crate::runtime::{Context, PadSrc, PadSrcRef, PadSrcWeak, Task};
use super::socket::{wrap_socket, GioSocketWrapper, Socket, SocketError, SocketRead, SocketState}; use super::socket::{wrap_socket, GioSocketWrapper, Socket, SocketError, SocketRead};
const DEFAULT_ADDRESS: Option<&str> = Some("0.0.0.0"); const DEFAULT_ADDRESS: Option<&str> = Some("0.0.0.0");
const DEFAULT_PORT: i32 = 5000; const DEFAULT_PORT: i32 = 5000;
@ -185,16 +185,11 @@ static PROPERTIES: [subclass::Property; 10] = [
]; ];
#[derive(Debug)] #[derive(Debug)]
struct UdpReaderInner { pub struct UdpReader(tokio::net::UdpSocket);
socket: tokio::net::UdpSocket,
}
#[derive(Debug)]
pub struct UdpReader(Arc<FutMutex<UdpReaderInner>>);
impl UdpReader { impl UdpReader {
fn new(socket: tokio::net::UdpSocket) -> Self { fn new(socket: tokio::net::UdpSocket) -> Self {
UdpReader(Arc::new(FutMutex::new(UdpReaderInner { socket }))) UdpReader(socket)
} }
} }
@ -202,15 +197,11 @@ impl SocketRead for UdpReader {
const DO_TIMESTAMP: bool = true; const DO_TIMESTAMP: bool = true;
fn read<'buf>( fn read<'buf>(
&self, &'buf mut self,
buffer: &'buf mut [u8], buffer: &'buf mut [u8],
) -> BoxFuture<'buf, io::Result<(usize, Option<std::net::SocketAddr>)>> { ) -> BoxFuture<'buf, io::Result<(usize, Option<std::net::SocketAddr>)>> {
let this = Arc::clone(&self.0);
async move { async move {
this.lock() self.0
.await
.socket
.recv_from(buffer) .recv_from(buffer)
.await .await
.map(|(read_size, saddr)| (read_size, Some(saddr))) .map(|(read_size, saddr)| (read_size, Some(saddr)))
@ -255,16 +246,12 @@ impl UdpSrcPadHandler {
state.retrieve_sender_address = retrieve_sender_address; state.retrieve_sender_address = retrieve_sender_address;
} }
fn reset_state(&self) { async fn reset_state(&self) {
*self.0.state.try_lock().expect("State locked elsewhere") = Default::default(); *self.0.state.lock().await = Default::default();
} }
fn set_need_segment(&self) { async fn set_need_segment(&self) {
self.0 self.0.state.lock().await.need_segment = true;
.state
.try_lock()
.expect("State locked elsewhere")
.need_segment = true;
} }
async fn push_prelude(&self, pad: &PadSrcRef<'_>, _element: &gst::Element) { async fn push_prelude(&self, pad: &PadSrcRef<'_>, _element: &gst::Element) {
@ -317,7 +304,7 @@ impl PadSrcHandler for UdpSrcPadHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
udpsrc: &UdpSrc, udpsrc: &UdpSrc,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
use gst::EventView; use gst::EventView;
@ -326,12 +313,12 @@ impl PadSrcHandler for UdpSrcPadHandler {
let ret = match event.view() { let ret = match event.view() {
EventView::FlushStart(..) => { EventView::FlushStart(..) => {
udpsrc.flush_start(element); udpsrc.task.flush_start();
true true
} }
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
udpsrc.flush_stop(element); udpsrc.task.flush_stop();
true true
} }
@ -398,11 +385,148 @@ impl PadSrcHandler for UdpSrcPadHandler {
} }
} }
struct UdpSrcTask {
element: gst::Element,
src_pad: PadSrcWeak,
src_pad_handler: UdpSrcPadHandler,
socket: Socket<UdpReader>,
}
impl UdpSrcTask {
fn new(
element: &gst::Element,
src_pad: &PadSrc,
src_pad_handler: &UdpSrcPadHandler,
socket: Socket<UdpReader>,
) -> Self {
UdpSrcTask {
element: element.clone(),
src_pad: src_pad.downgrade(),
src_pad_handler: src_pad_handler.clone(),
socket,
}
}
}
impl TaskImpl for UdpSrcTask {
fn start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Starting task");
self.socket
.set_clock(self.element.get_clock(), Some(self.element.get_base_time()));
gst_log!(CAT, obj: &self.element, "Task started");
}
.boxed()
}
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let item = self.socket.next().await;
let (mut buffer, saddr) = match item {
Some(Ok((buffer, saddr))) => (buffer, saddr),
Some(Err(err)) => {
gst_error!(CAT, obj: &self.element, "Got error {:?}", err);
match err {
SocketError::Gst(err) => {
gst_element_error!(
self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
SocketError::Io(err) => {
gst_element_error!(
self.element,
gst::StreamError::Failed,
("I/O error"),
["streaming stopped, I/O error {}", err]
);
}
}
return Err(gst::FlowError::Error);
}
None => {
gst_log!(CAT, obj: &self.element, "SocketStream Stopped");
return Err(gst::FlowError::Flushing);
}
};
if let Some(saddr) = saddr {
if self
.src_pad_handler
.0
.state
.lock()
.await
.retrieve_sender_address
{
let inet_addr = match saddr.ip() {
IpAddr::V4(ip) => gio::InetAddress::new_from_bytes(
gio::InetAddressBytes::V4(&ip.octets()),
),
IpAddr::V6(ip) => gio::InetAddress::new_from_bytes(
gio::InetAddressBytes::V6(&ip.octets()),
),
};
let inet_socket_addr = &gio::InetSocketAddress::new(&inet_addr, saddr.port());
NetAddressMeta::add(buffer.get_mut().unwrap(), inet_socket_addr);
}
}
let pad = self.src_pad.upgrade().expect("PadSrc no longer exists");
let res = self
.src_pad_handler
.push_buffer(&pad, &self.element, buffer)
.await;
match res {
Ok(_) => gst_log!(CAT, obj: &self.element, "Successfully pushed buffer"),
Err(gst::FlowError::Flushing) => gst_debug!(CAT, obj: &self.element, "Flushing"),
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: &self.element, "EOS");
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
}
Err(err) => {
gst_error!(CAT, obj: &self.element, "Got error {}", err);
gst_element_error!(
self.element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
}
res.map(drop)
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task");
self.src_pad_handler.reset_state().await;
gst_log!(CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
fn flush_stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(CAT, obj: &self.element, "Stopping task flush");
self.src_pad_handler.set_need_segment().await;
gst_log!(CAT, obj: &self.element, "Stopped task flush");
}
.boxed()
}
}
struct UdpSrc { struct UdpSrc {
src_pad: PadSrc, src_pad: PadSrc,
src_pad_handler: UdpSrcPadHandler, src_pad_handler: UdpSrcPadHandler,
task: Task, task: Task,
socket: StdMutex<Option<Socket<UdpReader>>>,
settings: StdMutex<Settings>, settings: StdMutex<Settings>,
} }
@ -585,9 +709,7 @@ impl UdpSrc {
) )
})?; })?;
let socket = Socket::new(element.upcast_ref(), buffer_pool, async move { let socket = Socket::try_new(element.clone(), buffer_pool, UdpReader::new(socket))
Ok(UdpReader::new(socket))
})
.map_err(|err| { .map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
@ -595,200 +717,55 @@ impl UdpSrc {
) )
})?; })?;
*self.socket.lock().unwrap() = Some(socket);
element.notify("used-socket"); element.notify("used-socket");
self.task.prepare(context).map_err(|err| { self.src_pad_handler
.prepare(settings.caps, settings.retrieve_sender_address);
self.task
.prepare(
UdpSrcTask::new(element, &self.src_pad, &self.src_pad_handler, socket),
context,
)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
) )
})?; })?;
self.src_pad_handler
.prepare(settings.caps, settings.retrieve_sender_address);
gst_debug!(CAT, obj: element, "Prepared"); gst_debug!(CAT, obj: element, "Prepared");
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Unpreparing"); gst_debug!(CAT, obj: element, "Unpreparing");
*self.socket.lock().unwrap() = None;
self.settings.lock().unwrap().used_socket = None; self.settings.lock().unwrap().used_socket = None;
element.notify("used-socket"); element.notify("used-socket");
self.task.unprepare().unwrap(); self.task.unprepare().unwrap();
gst_debug!(CAT, obj: element, "Unprepared"); gst_debug!(CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Stopping"); gst_debug!(CAT, obj: element, "Stopping");
self.task.stop(); self.task.stop();
self.src_pad_handler.reset_state();
gst_debug!(CAT, obj: element, "Stopped"); gst_debug!(CAT, obj: element, "Stopped");
Ok(())
}
fn start(&self, element: &gst::Element) -> Result<(), ()> {
let socket = self.socket.lock().unwrap();
let socket = socket.as_ref().unwrap();
if socket.state() == SocketState::Started {
gst_debug!(CAT, obj: element, "Already started");
return Ok(());
} }
fn start(&self, element: &gst::Element) {
gst_debug!(CAT, obj: element, "Starting"); gst_debug!(CAT, obj: element, "Starting");
self.start_task(element, socket); self.task.start();
gst_debug!(CAT, obj: element, "Started"); gst_debug!(CAT, obj: element, "Started");
Ok(())
} }
fn start_task(&self, element: &gst::Element, socket: &Socket<UdpReader>) { fn pause(&self, element: &gst::Element) {
let socket_stream = socket
.start(element.get_clock(), Some(element.get_base_time()))
.unwrap();
let socket_stream = Arc::new(FutMutex::new(socket_stream));
let src_pad_handler = self.src_pad_handler.clone();
let pad_weak = self.src_pad.downgrade();
let element = element.clone();
self.task.start(move || {
let src_pad_handler = src_pad_handler.clone();
let pad_weak = pad_weak.clone();
let element = element.clone();
let socket_stream = socket_stream.clone();
async move {
let item = socket_stream.lock().await.next().await;
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
let (mut buffer, saddr) = match item {
Some(Ok((buffer, saddr))) => (buffer, saddr),
Some(Err(err)) => {
gst_error!(CAT, obj: &element, "Got error {:?}", err);
match err {
SocketError::Gst(err) => {
gst_element_error!(
element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
}
SocketError::Io(err) => {
gst_element_error!(
element,
gst::StreamError::Failed,
("I/O error"),
["streaming stopped, I/O error {}", err]
);
}
}
return glib::Continue(false);
}
None => {
gst_log!(CAT, obj: pad.gst_pad(), "SocketStream Stopped");
return glib::Continue(false);
}
};
if let Some(saddr) = saddr {
if src_pad_handler.0.state.lock().await.retrieve_sender_address {
let inet_addr = match saddr.ip() {
IpAddr::V4(ip) => gio::InetAddress::new_from_bytes(
gio::InetAddressBytes::V4(&ip.octets()),
),
IpAddr::V6(ip) => gio::InetAddress::new_from_bytes(
gio::InetAddressBytes::V6(&ip.octets()),
),
};
let inet_socket_addr =
&gio::InetSocketAddress::new(&inet_addr, saddr.port());
NetAddressMeta::add(buffer.get_mut().unwrap(), inet_socket_addr);
}
}
match src_pad_handler.push_buffer(&pad, &element, buffer).await {
Ok(_) => {
gst_log!(CAT, obj: pad.gst_pad(), "Successfully pushed buffer");
glib::Continue(true)
}
Err(gst::FlowError::Flushing) => {
gst_debug!(CAT, obj: pad.gst_pad(), "Flushing");
glib::Continue(false)
}
Err(gst::FlowError::Eos) => {
gst_debug!(CAT, obj: pad.gst_pad(), "EOS");
let eos = gst::Event::new_eos().build();
pad.push_event(eos).await;
glib::Continue(false)
}
Err(err) => {
gst_error!(CAT, obj: pad.gst_pad(), "Got error {}", err);
gst_element_error!(
element,
gst::StreamError::Failed,
("Internal data stream error"),
["streaming stopped, reason {}", err]
);
glib::Continue(false)
}
}
}
});
}
fn flush_stop(&self, element: &gst::Element) {
let socket = self.socket.lock().unwrap();
if let Some(socket) = socket.as_ref() {
if socket.state() == SocketState::Started {
gst_debug!(CAT, obj: element, "Already started");
return;
}
gst_debug!(CAT, obj: element, "Stopping Flush");
self.src_pad_handler.set_need_segment();
self.start_task(element, socket);
gst_debug!(CAT, obj: element, "Stopped Flush");
} else {
gst_debug!(CAT, obj: element, "Socket not available");
}
}
fn flush_start(&self, element: &gst::Element) {
let socket = self.socket.lock().unwrap();
gst_debug!(CAT, obj: element, "Starting Flush");
if let Some(socket) = socket.as_ref() {
socket.pause();
}
self.task.cancel();
gst_debug!(CAT, obj: element, "Flush Started");
}
fn pause(&self, element: &gst::Element) -> Result<(), ()> {
gst_debug!(CAT, obj: element, "Pausing"); gst_debug!(CAT, obj: element, "Pausing");
self.socket.lock().unwrap().as_ref().unwrap().pause();
self.task.pause(); self.task.pause();
gst_debug!(CAT, obj: element, "Paused"); gst_debug!(CAT, obj: element, "Paused");
Ok(())
} }
} }
@ -847,7 +824,6 @@ impl ObjectSubclass for UdpSrc {
), ),
src_pad_handler, src_pad_handler,
task: Task::default(), task: Task::default(),
socket: StdMutex::new(None),
settings: StdMutex::new(Settings::default()), settings: StdMutex::new(Settings::default()),
} }
} }
@ -956,10 +932,10 @@ impl ElementImpl for UdpSrc {
})?; })?;
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
self.pause(element).map_err(|_| gst::StateChangeError)?; self.pause(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -971,13 +947,13 @@ impl ElementImpl for UdpSrc {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToPlaying => { gst::StateChange::PausedToPlaying => {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
} }
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
_ => (), _ => (),
} }

View file

@ -95,7 +95,7 @@ fn push() {
} }
#[test] #[test]
fn pause() { fn pause_regular() {
init(); init();
let mut h = gst_check::Harness::new("ts-appsrc"); let mut h = gst_check::Harness::new("ts-appsrc");
@ -122,10 +122,6 @@ fn pause() {
let _ = h.pull().unwrap(); let _ = h.pull().unwrap();
appsrc
.change_state(gst::StateChange::PlayingToPaused)
.unwrap();
// Pre-pause buffer // Pre-pause buffer
assert!(appsrc assert!(appsrc
.emit("push-buffer", &[&gst::Buffer::from_slice(vec![5, 6, 7])]) .emit("push-buffer", &[&gst::Buffer::from_slice(vec![5, 6, 7])])
@ -169,7 +165,7 @@ fn pause() {
} }
#[test] #[test]
fn flush() { fn flush_regular() {
init(); init();
let mut h = gst_check::Harness::new("ts-appsrc"); let mut h = gst_check::Harness::new("ts-appsrc");
@ -264,7 +260,7 @@ fn pause_flush() {
// FlushStart // FlushStart
assert!(h.push_upstream_event(gst::Event::new_flush_start().build())); assert!(h.push_upstream_event(gst::Event::new_flush_start().build()));
// Can't push buffer while flushing // Can't push buffers while flushing
assert!(!appsrc assert!(!appsrc
.emit("push-buffer", &[&gst::Buffer::new()]) .emit("push-buffer", &[&gst::Buffer::new()])
.unwrap() .unwrap()

View file

@ -33,11 +33,12 @@ use lazy_static::lazy_static;
use std::boxed::Box; use std::boxed::Box;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::Mutex as StdMutex; use std::sync::Mutex as StdMutex;
use gstthreadshare::runtime::prelude::*; use gstthreadshare::runtime::prelude::*;
use gstthreadshare::runtime::{Context, PadSink, PadSinkRef, PadSrc, PadSrcRef, Task}; use gstthreadshare::runtime::{
Context, PadSink, PadSinkRef, PadSrc, PadSrcRef, PadSrcWeak, Task, TaskState,
};
const DEFAULT_CONTEXT: &str = ""; const DEFAULT_CONTEXT: &str = "";
const THROTTLING_DURATION: u32 = 2; const THROTTLING_DURATION: u32 = 2;
@ -82,7 +83,10 @@ lazy_static! {
struct PadSrcTestHandler; struct PadSrcTestHandler;
impl PadSrcTestHandler { impl PadSrcTestHandler {
async fn push_item(pad: PadSrcRef<'_>, item: Item) -> Result<gst::FlowSuccess, gst::FlowError> { async fn push_item(
pad: &PadSrcRef<'_>,
item: Item,
) -> Result<gst::FlowSuccess, gst::FlowError> {
gst_debug!(SRC_CAT, obj: pad.gst_pad(), "Handling {:?}", item); gst_debug!(SRC_CAT, obj: pad.gst_pad(), "Handling {:?}", item);
match item { match item {
@ -104,19 +108,19 @@ impl PadSrcHandler for PadSrcTestHandler {
&self, &self,
pad: &PadSrcRef, pad: &PadSrcRef,
elem_src_test: &ElementSrcTest, elem_src_test: &ElementSrcTest,
element: &gst::Element, _element: &gst::Element,
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
gst_log!(SRC_CAT, obj: pad.gst_pad(), "Handling {:?}", event); gst_log!(SRC_CAT, obj: pad.gst_pad(), "Handling {:?}", event);
let ret = match event.view() { let ret = match event.view() {
EventView::FlushStart(..) => { EventView::FlushStart(..) => {
elem_src_test.flush_start(element); elem_src_test.task.flush_start();
true true
} }
EventView::Qos(..) | EventView::Reconfigure(..) | EventView::Latency(..) => true, EventView::Qos(..) | EventView::Reconfigure(..) | EventView::Latency(..) => true,
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
elem_src_test.flush_stop(&element); elem_src_test.task.flush_stop();
true true
} }
_ => false, _ => false,
@ -132,27 +136,89 @@ impl PadSrcHandler for PadSrcTestHandler {
} }
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug)]
enum ElementSrcTestState { struct ElementSrcTestTask {
Paused, element: gst::Element,
RejectItems, src_pad: PadSrcWeak,
Started, receiver: mpsc::Receiver<Item>,
}
impl ElementSrcTestTask {
fn new(element: &gst::Element, src_pad: &PadSrc, receiver: mpsc::Receiver<Item>) -> Self {
ElementSrcTestTask {
element: element.clone(),
src_pad: src_pad.downgrade(),
receiver,
}
}
}
impl ElementSrcTestTask {
fn flush(&mut self) {
// Purge the channel
while let Ok(Some(_item)) = self.receiver.try_next() {}
}
}
impl TaskImpl for ElementSrcTestTask {
fn iterate(&mut self) -> BoxFuture<'_, Result<(), gst::FlowError>> {
async move {
let item = self.receiver.next().await;
let item = match item {
Some(item) => item,
None => {
gst_log!(SRC_CAT, obj: &self.element, "SrcPad channel aborted");
return Err(gst::FlowError::Eos);
}
};
let pad = self.src_pad.upgrade().expect("PadSrc no longer exists");
let res = PadSrcTestHandler::push_item(&pad, item).await;
match res {
Ok(_) => gst_log!(SRC_CAT, obj: &self.element, "Successfully pushed item"),
Err(gst::FlowError::Flushing) => {
gst_debug!(SRC_CAT, obj: &self.element, "Flushing")
}
Err(err) => panic!("Got error {}", err),
}
res.map(drop)
}
.boxed()
}
fn stop(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(SRC_CAT, obj: &self.element, "Stopping task");
self.flush();
gst_log!(SRC_CAT, obj: &self.element, "Task stopped");
}
.boxed()
}
fn flush_start(&mut self) -> BoxFuture<'_, ()> {
async move {
gst_log!(SRC_CAT, obj: &self.element, "Starting task flush");
self.flush();
gst_log!(SRC_CAT, obj: &self.element, "Task flush started");
}
.boxed()
}
} }
#[derive(Debug)] #[derive(Debug)]
struct ElementSrcTest { struct ElementSrcTest {
src_pad: PadSrc, src_pad: PadSrc,
task: Task, task: Task,
state: StdMutex<ElementSrcTestState>,
sender: StdMutex<Option<mpsc::Sender<Item>>>, sender: StdMutex<Option<mpsc::Sender<Item>>>,
receiver: StdMutex<Option<Arc<FutMutex<mpsc::Receiver<Item>>>>>,
settings: StdMutex<Settings>, settings: StdMutex<Settings>,
} }
impl ElementSrcTest { impl ElementSrcTest {
fn try_push(&self, item: Item) -> Result<(), Item> { fn try_push(&self, item: Item) -> Result<(), Item> {
let state = self.state.lock().unwrap(); let state = self.task.lock_state();
if *state == ElementSrcTestState::RejectItems { if *state != TaskState::Started && *state != TaskState::Paused {
gst_debug!(SRC_CAT, "ElementSrcTest rejecting item due to pad state"); gst_debug!(SRC_CAT, "ElementSrcTest rejecting item due to pad state");
return Err(item); return Err(item);
@ -177,162 +243,51 @@ impl ElementSrcTest {
) )
})?; })?;
self.task.prepare(context).map_err(|err| { let (sender, receiver) = mpsc::channel(1);
*self.sender.lock().unwrap() = Some(sender);
self.task
.prepare(
ElementSrcTestTask::new(element, &self.src_pad, receiver),
context,
)
.map_err(|err| {
gst_error_msg!( gst_error_msg!(
gst::ResourceError::OpenRead, gst::ResourceError::OpenRead,
["Error preparing Task: {:?}", err] ["Error preparing Task: {:?}", err]
) )
})?; })?;
let (sender, receiver) = mpsc::channel(1);
*self.sender.lock().unwrap() = Some(sender);
*self.receiver.lock().unwrap() = Some(Arc::new(FutMutex::new(receiver)));
gst_debug!(SRC_CAT, obj: element, "Prepared"); gst_debug!(SRC_CAT, obj: element, "Prepared");
Ok(()) Ok(())
} }
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> { fn unprepare(&self, element: &gst::Element) {
gst_debug!(SRC_CAT, obj: element, "Unpreparing"); gst_debug!(SRC_CAT, obj: element, "Unpreparing");
*self.sender.lock().unwrap() = None;
self.task.unprepare().unwrap(); self.task.unprepare().unwrap();
*self.sender.lock().unwrap() = None;
*self.receiver.lock().unwrap() = None;
gst_debug!(SRC_CAT, obj: element, "Unprepared"); gst_debug!(SRC_CAT, obj: element, "Unprepared");
Ok(())
} }
fn stop(&self, element: &gst::Element) -> Result<(), ()> { fn stop(&self, element: &gst::Element) {
let mut state = self.state.lock().unwrap();
gst_debug!(SRC_CAT, obj: element, "Stopping"); gst_debug!(SRC_CAT, obj: element, "Stopping");
self.flush(element);
*state = ElementSrcTestState::RejectItems;
gst_debug!(SRC_CAT, obj: element, "Stopped");
Ok(())
}
fn flush(&self, element: &gst::Element) {
gst_debug!(SRC_CAT, obj: element, "Flushing");
self.task.stop(); self.task.stop();
gst_debug!(SRC_CAT, obj: element, "Stopped");
let receiver = self.receiver.lock().unwrap();
let mut receiver = receiver
.as_ref()
.unwrap()
.try_lock()
.expect("receiver locked elsewhere");
// Purge the channel
loop {
match receiver.try_next() {
Ok(Some(_item)) => {
gst_debug!(SRC_CAT, obj: element, "Dropping pending item");
}
Err(_) => {
gst_debug!(SRC_CAT, obj: element, "No more pending item");
break;
}
Ok(None) => {
panic!("Channel sender dropped");
}
}
}
gst_debug!(SRC_CAT, obj: element, "Flushed");
}
fn start(&self, element: &gst::Element) -> Result<(), ()> {
let mut state = self.state.lock().unwrap();
if *state == ElementSrcTestState::Started {
gst_debug!(SRC_CAT, obj: element, "Already started");
return Err(());
} }
fn start(&self, element: &gst::Element) {
gst_debug!(SRC_CAT, obj: element, "Starting"); gst_debug!(SRC_CAT, obj: element, "Starting");
self.task.start();
self.start_task();
*state = ElementSrcTestState::Started;
gst_debug!(SRC_CAT, obj: element, "Started"); gst_debug!(SRC_CAT, obj: element, "Started");
Ok(())
} }
fn start_task(&self) { fn pause(&self, element: &gst::Element) {
let pad_weak = self.src_pad.downgrade();
let receiver = Arc::clone(self.receiver.lock().unwrap().as_ref().expect("No receiver"));
self.task.start(move || {
let pad_weak = pad_weak.clone();
let receiver = Arc::clone(&receiver);
async move {
let item = receiver.lock().await.next().await;
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
let item = match item {
Some(item) => item,
None => {
gst_log!(SRC_CAT, obj: pad.gst_pad(), "SrcPad channel aborted");
return glib::Continue(false);
}
};
let pad = pad_weak.upgrade().expect("PadSrc no longer exists");
match PadSrcTestHandler::push_item(pad, item).await {
Ok(_) => glib::Continue(true),
Err(gst::FlowError::Flushing) => glib::Continue(false),
Err(err) => panic!("Got error {:?}", err),
}
}
});
}
fn flush_stop(&self, element: &gst::Element) {
let mut state = self.state.lock().unwrap();
if *state == ElementSrcTestState::Started {
gst_debug!(SRC_CAT, obj: element, "Already started");
return;
}
gst_debug!(SRC_CAT, obj: element, "Stopping Flush");
self.flush(element);
self.start_task();
*state = ElementSrcTestState::Started;
gst_debug!(SRC_CAT, obj: element, "Stopped Flush");
}
fn flush_start(&self, element: &gst::Element) {
let mut state = self.state.lock().unwrap();
gst_debug!(SRC_CAT, obj: element, "Starting Flush");
self.task.cancel();
*state = ElementSrcTestState::RejectItems;
gst_debug!(SRC_CAT, obj: element, "Flush Started");
}
fn pause(&self, element: &gst::Element) -> Result<(), ()> {
let mut state = self.state.lock().unwrap();
gst_debug!(SRC_CAT, obj: element, "Pausing"); gst_debug!(SRC_CAT, obj: element, "Pausing");
self.task.pause(); self.task.pause();
*state = ElementSrcTestState::Paused;
gst_debug!(SRC_CAT, obj: element, "Paused"); gst_debug!(SRC_CAT, obj: element, "Paused");
Ok(())
} }
} }
@ -372,9 +327,7 @@ impl ObjectSubclass for ElementSrcTest {
PadSrcTestHandler, PadSrcTestHandler,
), ),
task: Task::default(), task: Task::default(),
state: StdMutex::new(ElementSrcTestState::RejectItems),
sender: StdMutex::new(None), sender: StdMutex::new(None),
receiver: StdMutex::new(None),
settings: StdMutex::new(Settings::default()), settings: StdMutex::new(Settings::default()),
} }
} }
@ -423,10 +376,10 @@ impl ElementImpl for ElementSrcTest {
})?; })?;
} }
gst::StateChange::PlayingToPaused => { gst::StateChange::PlayingToPaused => {
self.pause(element).map_err(|_| gst::StateChangeError)?; self.pause(element);
} }
gst::StateChange::ReadyToNull => { gst::StateChange::ReadyToNull => {
self.unprepare(element).map_err(|_| gst::StateChangeError)?; self.unprepare(element);
} }
_ => (), _ => (),
} }
@ -435,10 +388,10 @@ impl ElementImpl for ElementSrcTest {
match transition { match transition {
gst::StateChange::PausedToReady => { gst::StateChange::PausedToReady => {
self.stop(element).map_err(|_| gst::StateChangeError)?; self.stop(element);
} }
gst::StateChange::PausedToPlaying => { gst::StateChange::PausedToPlaying => {
self.start(element).map_err(|_| gst::StateChangeError)?; self.start(element);
} }
gst::StateChange::ReadyToPaused | gst::StateChange::PlayingToPaused => { gst::StateChange::ReadyToPaused | gst::StateChange::PlayingToPaused => {
success = gst::StateChangeSuccess::NoPreroll; success = gst::StateChangeSuccess::NoPreroll;
@ -449,13 +402,13 @@ impl ElementImpl for ElementSrcTest {
Ok(success) Ok(success)
} }
fn send_event(&self, element: &gst::Element, event: gst::Event) -> bool { fn send_event(&self, _element: &gst::Element, event: gst::Event) -> bool {
match event.view() { match event.view() {
EventView::FlushStart(..) => { EventView::FlushStart(..) => {
self.flush_start(element); self.task.flush_start();
} }
EventView::FlushStop(..) => { EventView::FlushStop(..) => {
self.flush_stop(element); self.task.flush_stop();
} }
_ => (), _ => (),
} }

View file

@ -406,12 +406,15 @@ fn eos() {
eos_notif_rcv.recv().unwrap(); eos_notif_rcv.recv().unwrap();
assert!(push_buffer(&src)); // FIXME not ideal, but better than previous approach.
std::thread::sleep(std::time::Duration::from_millis(50)); // I think the "end-of-stream" signal should block
assert_eq!( // until the **src** element has actually reached EOS
sample_notif_rcv.try_recv().unwrap_err(), loop {
mpsc::TryRecvError::Empty std::thread::sleep(std::time::Duration::from_millis(10));
); if !push_buffer(&src) {
break;
}
}
pipeline_clone.set_state(gst::State::Null).unwrap(); pipeline_clone.set_state(gst::State::Null).unwrap();
l_clone.quit(); l_clone.quit();