1use std::sync::Arc;
2
3use crate::pp_log::{PpLog, pp_trace};
4
5use crate::{
6 buffer::MediaBuffer,
7 bus::{Bus, BusEvent},
8 control::ControlMsg,
9 element::{Context, Element, ElementType, Filter, Sink, Source, element_pp_log},
10 error::Result,
11 graph::{BranchId, BranchPlan, ElementId, GraphError, NodeInfo, PlannedEdge, PortRef},
12 pad::SrcPad,
13 queue::{OverflowPolicy, Queue},
14};
15
16pub struct ChainBuilder {
25 context: Arc<Context>,
26 elements: Vec<Box<dyn StageBuilder>>,
27 planned: Vec<PlannedNode>,
30 error: Option<GraphError>,
31}
32
33struct PlannedNode {
34 info: NodeInfo,
35 output_port: Arc<str>,
36}
37
38pub struct DetachedBranch {
41 pub(crate) root: Box<dyn Sink>,
42 pub(crate) plan: BranchPlan,
43}
44
45impl DetachedBranch {
46 pub fn root_id(&self) -> ElementId {
51 self.plan.root
52 }
53}
54
55trait StageBuilder: Send {
56 fn wrap(
57 self: Box<Self>,
58 downstream: Box<dyn Sink>,
59 bus: &Bus,
60 pipeline_id: &str,
61 ) -> Result<Box<dyn Sink>>;
62}
63
64struct DirectStage<T>(T);
65
66struct FlowTracer<T> {
69 inner: T,
70}
71
72impl<T: Element> Element for FlowTracer<T> {
73 fn name(&self) -> Arc<str> {
74 self.inner.name()
75 }
76
77 fn element_type(&self) -> ElementType {
78 self.inner.element_type()
79 }
80
81 fn graph_id(&self) -> Option<ElementId> {
82 self.inner.graph_id()
83 }
84
85 fn pp_log(&self) -> &PpLog {
86 self.inner.pp_log()
87 }
88
89 fn pp_log_mut(&mut self) -> &mut PpLog {
90 self.inner.pp_log_mut()
91 }
92}
93
94impl<T: Source> Source for FlowTracer<T> {
95 fn src_pads(&mut self) -> &mut [SrcPad] {
96 self.inner.src_pads()
97 }
98}
99
100impl<T: Sink> Sink for FlowTracer<T> {
101 fn consume(&mut self, buf: MediaBuffer) -> Result<()> {
102 let is_eos = buf.is_eos();
103 if is_eos {
104 pp_trace!(pp_log: self.inner.pp_log(), "event=eos phase=received");
105 }
106 let result = self.inner.consume(buf);
107 if is_eos {
108 match &result {
109 Ok(()) => pp_trace!(
110 pp_log: self.inner.pp_log(),
111 "event=eos phase=completed outcome=ok"
112 ),
113 Err(error) => pp_trace!(
114 pp_log: self.inner.pp_log(),
115 "event=eos phase=completed outcome=error error={error}"
116 ),
117 }
118 }
119 result
120 }
121
122 fn control(&mut self, msg: ControlMsg) -> Result<()> {
123 pp_trace!(
124 pp_log: self.inner.pp_log(),
125 "event=control control={msg:?} phase=received"
126 );
127 let result = self.inner.control(msg);
128 match &result {
129 Ok(()) => pp_trace!(
130 pp_log: self.inner.pp_log(),
131 "event=control control={msg:?} phase=completed outcome=ok"
132 ),
133 Err(error) => pp_trace!(
134 pp_log: self.inner.pp_log(),
135 "event=control control={msg:?} phase=completed outcome=error error={error}"
136 ),
137 }
138 result
139 }
140}
141
142impl<T> StageBuilder for DirectStage<T>
143where
144 T: Filter + 'static,
145{
146 fn wrap(
147 self: Box<Self>,
148 downstream: Box<dyn Sink>,
149 _bus: &Bus,
150 pipeline_id: &str,
151 ) -> Result<Box<dyn Sink>> {
152 let mut element = self.0;
153 *element.pp_log_mut() =
154 element_pp_log(element.element_type(), &element.name(), Some(pipeline_id));
155 element.src_pads()[0].link(downstream);
156 Ok(Box::new(FlowTracer { inner: element }))
157 }
158}
159
160struct QueueStage {
161 id: ElementId,
162 name: String,
163 capacity: usize,
164 policy: OverflowPolicy,
165}
166
167struct TerminalTracer {
173 bus: Bus,
174 inner: Box<dyn Sink>,
175}
176
177impl Element for TerminalTracer {
178 fn name(&self) -> Arc<str> {
179 self.inner.name()
180 }
181
182 fn element_type(&self) -> ElementType {
183 self.inner.element_type()
184 }
185
186 fn graph_id(&self) -> Option<ElementId> {
187 self.inner.graph_id()
188 }
189
190 fn pp_log(&self) -> &PpLog {
191 self.inner.pp_log()
192 }
193
194 fn pp_log_mut(&mut self) -> &mut PpLog {
195 self.inner.pp_log_mut()
196 }
197}
198
199impl Sink for TerminalTracer {
200 fn consume(&mut self, buf: MediaBuffer) -> Result<()> {
201 let is_eos = buf.is_eos();
202 if is_eos {
203 pp_trace!(pp_log: self.inner.pp_log(), "event=eos phase=received");
204 }
205 let result = self.inner.consume(buf);
206 if is_eos {
207 match &result {
208 Ok(()) => {
209 pp_trace!(
210 pp_log: self.inner.pp_log(),
211 "event=eos phase=completed outcome=ok"
212 );
213 self.bus.post(
214 self.inner.pp_log(),
215 BusEvent::Eos {
216 element_type: self.inner.element_type(),
217 name: self.inner.name(),
218 },
219 );
220 }
221 Err(error) => pp_trace!(
222 pp_log: self.inner.pp_log(),
223 "event=eos phase=completed outcome=error error={error}"
224 ),
225 }
226 }
227 result
228 }
229
230 fn control(&mut self, msg: ControlMsg) -> Result<()> {
231 pp_trace!(
232 pp_log: self.inner.pp_log(),
233 "event=control control={msg:?} phase=received"
234 );
235 let result = self.inner.control(msg);
236 match &result {
237 Ok(()) => pp_trace!(
238 pp_log: self.inner.pp_log(),
239 "event=control control={msg:?} phase=completed outcome=ok"
240 ),
241 Err(error) => pp_trace!(
242 pp_log: self.inner.pp_log(),
243 "event=control control={msg:?} phase=completed outcome=error error={error}"
244 ),
245 }
246 result
247 }
248}
249
250impl StageBuilder for QueueStage {
251 fn wrap(
252 self: Box<Self>,
253 downstream: Box<dyn Sink>,
254 bus: &Bus,
255 pipeline_id: &str,
256 ) -> Result<Box<dyn Sink>> {
257 Ok(Box::new(Queue::spawn_with_policy(
258 self.name,
259 self.capacity,
260 downstream,
261 bus.for_element(self.id),
262 self.policy,
263 Some(pipeline_id),
264 )?))
265 }
266}
267
268impl ChainBuilder {
269 pub fn new(context: Arc<Context>) -> Self {
273 Self {
274 context,
275 elements: Vec::new(),
276 planned: Vec::new(),
277 error: None,
278 }
279 }
280
281 pub fn pipe<T: Filter + 'static>(mut self, mut element: T) -> Self {
286 let name = element.name();
287 let pad_count = element.src_pads().len();
288 if pad_count != 1 && self.error.is_none() {
289 self.error = Some(GraphError::NotSingleOutput {
290 name: name.clone(),
291 count: pad_count,
292 });
293 }
294 let output_port = element
295 .src_pads()
296 .first()
297 .map(|pad| Arc::<str>::from(pad.name()))
298 .unwrap_or_else(|| "src".into());
299 self.planned.push(PlannedNode {
300 info: NodeInfo {
301 id: self.context.graph.reserve_element_id(),
302 element_type: element.element_type(),
303 name,
304 },
305 output_port,
306 });
307 self.elements.push(Box::new(DirectStage(element)));
308 self
309 }
310
311 pub fn queue(self, name: impl Into<String>, capacity: usize) -> Self {
315 self.queue_with_policy(name, capacity, OverflowPolicy::default())
316 }
317
318 pub fn queue_with_policy(
322 mut self,
323 name: impl Into<String>,
324 capacity: usize,
325 policy: OverflowPolicy,
326 ) -> Self {
327 let name: Arc<str> = name.into().into();
328 let id = self.context.graph.reserve_element_id();
329 self.planned.push(PlannedNode {
330 info: NodeInfo {
331 id,
332 element_type: ElementType::Queue,
333 name: name.clone(),
334 },
335 output_port: format!("{name}_src").into(),
336 });
337 self.elements.push(Box::new(QueueStage {
338 id,
339 name: name.to_string(),
340 capacity,
341 policy,
342 }));
343 self
344 }
345
346 pub fn to(self, mut terminal: Box<dyn Sink>) -> Result<DetachedBranch> {
351 if let Some(error) = self.error {
352 return Err(error.into());
353 }
354 *terminal.pp_log_mut() = element_pp_log(
355 terminal.element_type(),
356 &terminal.name(),
357 Some(&self.context.pipeline_id),
358 );
359 let terminal_info = NodeInfo {
360 id: terminal
361 .graph_id()
362 .unwrap_or_else(|| self.context.graph.reserve_element_id()),
363 element_type: terminal.element_type(),
364 name: terminal.name(),
365 };
366 let terminal_id = terminal_info.id;
367 let mut nodes: Vec<_> = self.planned.iter().map(|node| node.info.clone()).collect();
368 nodes.push(terminal_info);
369 let edges = nodes
370 .windows(2)
371 .enumerate()
372 .map(|(index, pair)| PlannedEdge {
373 from: PortRef {
374 element: pair[0].id,
375 port: self.planned[index].output_port.clone(),
376 },
377 to: PortRef {
378 element: pair[1].id,
379 port: "sink".into(),
380 },
381 })
382 .collect();
383 let root_id = nodes.first().expect("terminal always supplies one node").id;
384 let terminal: Box<dyn Sink> = Box::new(TerminalTracer {
385 bus: self.context.bus.for_element(terminal_id),
386 inner: terminal,
387 });
388 let root = self
389 .elements
390 .into_iter()
391 .rev()
392 .try_fold(terminal, |downstream, stage| {
393 stage.wrap(downstream, &self.context.bus, &self.context.pipeline_id)
394 })?;
395 Ok(DetachedBranch {
396 root,
397 plan: BranchPlan {
398 nodes,
399 edges,
400 root: root_id,
401 },
402 })
403 }
404
405 pub fn build(self, terminal: Box<dyn Sink>) -> Result<DetachedBranch> {
408 self.to(terminal)
409 }
410}
411
412impl Context {
413 pub fn branch(self: &Arc<Self>) -> ChainBuilder {
418 ChainBuilder::new(self.clone())
419 }
420
421 pub fn attach<S: Source>(
427 &self,
428 source: &mut S,
429 pad_index: usize,
430 branch: DetachedBranch,
431 ) -> Result<BranchId> {
432 let pads = source.src_pads();
433 let pad_count = pads.len();
434 let pad = pads.get_mut(pad_index).ok_or(GraphError::PadOutOfRange {
435 index: pad_index,
436 pad_count,
437 })?;
438 self.attach_pad(pad, branch)
439 }
440
441 pub(crate) fn attach_pad(&self, pad: &mut SrcPad, branch: DetachedBranch) -> Result<BranchId> {
442 if pad.is_linked() {
443 return Err(GraphError::PadAlreadyLinked(pad.name().to_owned()).into());
444 }
445 let from_port: Arc<str> = pad.name().into();
446 let DetachedBranch { root, plan } = branch;
447 Ok(self
448 .graph
449 .attach_with(self.source_id, from_port, plan, |_| {
450 pad.link(root);
451 Ok(())
452 })?)
453 }
454}