media_pp/elements/source/
app_source.rs1use std::{sync::Arc, time::Duration};
2
3use crate::pp_log::{PpLog, pp_info};
4use crossbeam_channel::{Receiver, Sender, TrySendError, bounded, select};
5use thiserror::Error as ThisError;
6
7use crate::{
8 buffer::MediaBuffer,
9 bus::{Bus, BusEvent},
10 control::{
11 ControlMsg, ControlReceiver, RequestKind, apply_finish, apply_one, drain_control,
12 wait_out_pause,
13 },
14 element::{Element, ElementType, Source, SourceElement, element_pp_log},
15 error::Result,
16 pad::SrcPad,
17};
18
19#[derive(Debug, ThisError)]
22pub enum AppSourceError {
23 #[error("AppSource has already ended (its Pipeline finished, or Eos was already pushed)")]
25 Closed,
26}
27
28pub struct AppSource {
51 pp_log: PpLog,
52 name: Arc<str>,
53 pad: SrcPad,
54 data_rx: Receiver<MediaBuffer>,
55}
56
57#[derive(Clone)]
61pub struct AppSourceHandle {
62 name: Arc<str>,
63 data_tx: Sender<MediaBuffer>,
64}
65
66impl AppSource {
67 pub fn new(name: impl Into<String>, capacity: usize) -> (Self, AppSourceHandle) {
71 let name: Arc<str> = name.into().into();
72 let pp_log = element_pp_log(ElementType::AppSource, &name, None);
73 pp_info!(pp_log: &pp_log, "created: capacity={capacity}");
74 let pad = SrcPad::new(format!("{name}_src"));
75 let (data_tx, data_rx) = bounded(capacity);
76 (
77 Self {
78 name: name.clone(),
79 pp_log,
80 pad,
81 data_rx,
82 },
83 AppSourceHandle { name, data_tx },
84 )
85 }
86}
87
88impl AppSourceHandle {
89 pub fn name(&self) -> Arc<str> {
91 self.name.clone()
92 }
93
94 pub fn push(&self, buf: MediaBuffer) -> Result<()> {
97 self.data_tx
98 .send(buf)
99 .map_err(|_| AppSourceError::Closed.into())
100 }
101
102 pub fn try_push(&self, buf: MediaBuffer) -> Result<bool> {
108 match self.data_tx.try_send(buf) {
109 Ok(()) => Ok(true),
110 Err(TrySendError::Full(_)) => Ok(false),
111 Err(TrySendError::Disconnected(_)) => Err(AppSourceError::Closed.into()),
112 }
113 }
114}
115
116impl Element for AppSource {
117 fn name(&self) -> Arc<str> {
118 self.name.clone()
119 }
120
121 fn element_type(&self) -> ElementType {
122 ElementType::AppSource
123 }
124
125 fn pp_log(&self) -> &PpLog {
126 &self.pp_log
127 }
128
129 fn pp_log_mut(&mut self) -> &mut PpLog {
130 &mut self.pp_log
131 }
132}
133
134impl Source for AppSource {
135 fn src_pads(&mut self) -> &mut [SrcPad] {
136 std::slice::from_mut(&mut self.pad)
137 }
138}
139
140impl SourceElement for AppSource {
141 fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()> {
142 pp_info!(self, "started");
143 loop {
144 if drain_control(control, self, bus)?.stopped {
150 pp_info!(self, "stopped");
151 return Ok(());
152 }
153
154 select! {
155 recv(control.rx) -> req => {
156 match req {
157 Ok(req) => {
158 match req.kind {
159 RequestKind::Finish => {
160 apply_finish(self, bus, &req.ack);
161 pp_info!(self, "finished");
162 return Ok(());
163 }
164 RequestKind::Control(msg) => {
165 if apply_one(self, bus, msg, &req.ack)? {
166 pp_info!(self, "stopped");
167 return Ok(());
168 }
169 if msg == ControlMsg::Pause
170 && wait_out_pause(control, self, bus)?
171 {
172 pp_info!(self, "stopped");
173 return Ok(());
174 }
175 }
176 }
177 }
178 Err(_) => {
180 pp_info!(self, "run: control channel gone, ending");
181 return Ok(());
182 }
183 }
184 }
185 recv(self.data_rx) -> buf => {
186 match buf {
187 Ok(buf) if buf.is_eos() => {
188 pp_info!(self, "event=eos phase=source_received");
189 break;
190 }
191 Ok(buf) => {
192 if let Err(error) = self.pad.push(buf) {
193 bus.post(
194 &self.pp_log,
195 BusEvent::Error {
196 element_type: ElementType::AppSource,
197 name: self.name.clone(),
198 error,
199 },
200 );
201 }
202 }
203 Err(_) => {
205 pp_info!(self, "run: every AppSourceHandle dropped, ending");
206 break;
207 }
208 }
209 }
210 }
211 }
212 self.pad.push_eos(&self.pp_log)
213 }
214
215 fn seek(&mut self, target: Duration) -> Result<Duration> {
221 Ok(target)
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use std::{
228 sync::atomic::{AtomicUsize, Ordering},
229 thread,
230 };
231
232 use super::*;
233 use crate::pipeline::Pipeline;
234
235 struct CountingSink {
236 pp_log: PpLog,
237 count: Arc<AtomicUsize>,
238 }
239
240 impl Element for CountingSink {
241 fn name(&self) -> Arc<str> {
242 "counter".into()
243 }
244
245 fn element_type(&self) -> ElementType {
246 ElementType::Other
247 }
248
249 fn pp_log(&self) -> &PpLog {
250 &self.pp_log
251 }
252
253 fn pp_log_mut(&mut self) -> &mut PpLog {
254 &mut self.pp_log
255 }
256 }
257
258 impl crate::element::Sink for CountingSink {
259 fn consume(&mut self, buf: MediaBuffer) -> Result<()> {
260 if !buf.is_eos() {
261 self.count.fetch_add(1, Ordering::SeqCst);
262 }
263 Ok(())
264 }
265
266 fn control(&mut self, _msg: ControlMsg) -> Result<()> {
267 Ok(())
268 }
269 }
270
271 fn packet() -> MediaBuffer {
272 MediaBuffer::Packet(Arc::new(ffmpeg_next::Packet::empty()))
273 }
274
275 fn wire(source: AppSource, count: Arc<AtomicUsize>) -> Arc<Pipeline> {
276 let sink = CountingSink {
277 count,
278 pp_log: element_pp_log(ElementType::Other, "counter", None),
279 };
280 Pipeline::new("test", source, |source, ctx| {
281 let branch = ctx.branch().to(Box::new(sink))?;
282 ctx.attach(source, 0, branch)?;
283 Ok(())
284 })
285 .expect("test pipeline wiring must succeed")
286 }
287
288 #[test]
289 fn pushed_buffers_reach_downstream_then_eos_ends_it() {
290 let (source, handle) = AppSource::new("app-source", 4);
291 let count = Arc::new(AtomicUsize::new(0));
292 let pipeline = wire(source, count.clone());
293 pipeline.run().unwrap();
294
295 for _ in 0..5 {
296 handle.push(packet()).unwrap();
297 }
298 handle.push(MediaBuffer::Eos).unwrap();
299
300 let events: Vec<_> = pipeline.bus().iter().collect();
301 assert!(
302 !events.iter().any(|e| matches!(e, BusEvent::Error { .. })),
303 "unexpected error event(s): {events:?}"
304 );
305 assert!(events.iter().any(|e| matches!(e, BusEvent::Eos { .. })));
306 assert_eq!(count.load(Ordering::SeqCst), 5);
307 }
308
309 #[test]
310 fn dropping_every_handle_without_eos_still_ends_cleanly() {
311 let (source, handle) = AppSource::new("app-source", 4);
312 let count = Arc::new(AtomicUsize::new(0));
313 let pipeline = wire(source, count.clone());
314 pipeline.run().unwrap();
315
316 handle.push(packet()).unwrap();
317 handle.push(packet()).unwrap();
318 drop(handle); let events: Vec<_> = pipeline.bus().iter().collect();
321 assert!(
322 !events.iter().any(|e| matches!(e, BusEvent::Error { .. })),
323 "unexpected error event(s): {events:?}"
324 );
325 assert!(events.iter().any(|e| matches!(e, BusEvent::Eos { .. })));
326 assert_eq!(count.load(Ordering::SeqCst), 2);
327 }
328
329 #[test]
335 fn stop_ends_promptly_even_with_no_producer() {
336 let (source, _handle) = AppSource::new("app-source", 4);
337 let count = Arc::new(AtomicUsize::new(0));
338 let pipeline = wire(source, count.clone());
339 pipeline.run().unwrap();
340
341 thread::sleep(Duration::from_millis(50));
345 pipeline.stop();
346
347 let events: Vec<_> = pipeline.bus().iter().collect();
348 assert!(
349 !events.iter().any(|e| matches!(e, BusEvent::Error { .. })),
350 "unexpected error event(s): {events:?}"
351 );
352 assert_eq!(count.load(Ordering::SeqCst), 0);
353 }
354}