g2g_core/element.rs
1use core::future::Future;
2use core::pin::Pin;
3
4use alloc::boxed::Box;
5
6use crate::caps::Caps;
7use crate::clock::{ClockCandidate, ClockSync};
8use crate::error::G2gError;
9use crate::format_element::{
10 legacy_sink_constraint, legacy_transform_constraint, CapsConstraint, CapsPreferences,
11};
12use crate::frame::PipelinePacket;
13use crate::memory::{DomainSet, MemoryDomainKind};
14use crate::property::{ElementMetadata, PropError, PropValue, PropertySpec};
15use crate::query::{AllocationParams, LatencyReport};
16
17#[cfg(feature = "multi-thread")]
18pub trait ElementBound: Send {}
19#[cfg(feature = "multi-thread")]
20impl<T: Send> ElementBound for T {}
21
22#[cfg(not(feature = "multi-thread"))]
23pub trait ElementBound {}
24#[cfg(not(feature = "multi-thread"))]
25impl<T> ElementBound for T {}
26
27/// Boxed future alias for dyn-safe async methods in element / sink traits.
28pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
29
30/// Downstream-originated request to renegotiate caps. Travels upstream
31/// along a link's reverse channel and is surfaced to the producing element
32/// as a [`PushOutcome::Reconfigure`].
33#[derive(Debug, Clone, PartialEq)]
34pub enum Reconfigure {
35 /// Downstream proposes specific replacement caps (Phase 3 counter).
36 Propose(Caps),
37 /// Downstream wants renegotiation but has no specific proposal โ
38 /// the upstream element picks freely. Equivalent to GStreamer's
39 /// bare RECONFIGURE event.
40 Renegotiate,
41 /// Downstream needs a keyframe now (no caps change): an encoder should emit
42 /// an IDR / key frame on its next output. Originated by a WebRTC egress sink
43 /// on a remote PLI (Picture Loss Indication) and carried up the reverse
44 /// channel to the encoder. The GStreamer `GstForceKeyUnit` upstream-event
45 /// analog.
46 ForceKeyframe,
47 /// The sink downstream applies an
48 /// [`OrientationMeta`](crate::meta::OrientationMeta) itself, so a rotation
49 /// upstream should attach the descriptor rather than remap the pixels. Sent
50 /// once by a display sink that can turn a buffer for free (a Wayland
51 /// `set_buffer_transform`, a KMS plane rotation) before the first frame is
52 /// pulled, and relayed past any transform that does not answer it (see
53 /// [`AsyncElement::handles_orientation`]).
54 AbsorbOrientation,
55}
56
57/// Downstream-originated quality-of-service signal: a synchronising sink is
58/// running behind the pipeline clock and dropped a late frame. Travels upstream
59/// along a link's reverse channel and is surfaced to the producing element as a
60/// [`PushOutcome::Qos`], so a source / decoder can shed load (skip frames) to let
61/// the pipeline catch up. The GStreamer QoS event analog (the
62/// [`BusMessage::Qos`](crate::BusMessage::Qos) report is the out-of-band sibling
63/// the application observes).
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub struct QosMessage {
66 /// How far past its deadline the dropped frame was, ns. Positive is late
67 /// (behind the clock); the producer skips roughly this much stream time to
68 /// catch up.
69 pub jitter_ns: i64,
70 /// Running time (PTS) of the late frame, for reference.
71 pub running_time_ns: u64,
72}
73
74/// Cumulative presentation counters a paced sink kept over a run, read via
75/// [`AsyncElement::presentation_stats`] once the sink's arm ends. `consumed`
76/// alone can't say whether frames actually reached the display on time; these
77/// counters split it into shown vs shed.
78#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
79pub struct PresentationStats {
80 /// Frames the sink actually presented (e.g. committed and acknowledged by
81 /// the display server).
82 pub presented: u64,
83 /// Frames overwritten before they ever painted (a `DropOldest` pacing
84 /// policy under a slow consumer).
85 pub dropped: u64,
86 /// Frames discarded by QoS late-drop (past their deadline beyond the
87 /// configured bound).
88 pub late_dropped: u64,
89}
90
91/// Outcome of pushing a packet downstream. Sources and transforms must
92/// react to `Reconfigure` before pushing any further data; terminal sinks
93/// and intermediate adapters that can't renegotiate may ignore it. `Qos` is
94/// advisory: the packet still flowed, but the producer may shed load.
95#[derive(Debug, Clone, PartialEq)]
96pub enum PushOutcome {
97 /// Downstream accepted the packet; continue normally.
98 Accepted,
99 /// Downstream signaled a reconfigure request between this push and
100 /// the previous one. The producer should handle the request before
101 /// pushing further `DataFrame`s.
102 Reconfigure(Reconfigure),
103 /// Downstream is behind the clock (a sink dropped a late frame). Advisory:
104 /// the producer may skip ahead to shed load. Reconfigure takes priority when
105 /// both are pending (negotiation correctness over QoS).
106 Qos(QosMessage),
107 /// Downstream reports a target send bitrate in bits/second (a WebRTC sink
108 /// relaying its congestion-control / BWE estimate). Advisory: an encoder
109 /// upstream should retarget its bitrate. Lowest priority of the reverse
110 /// signals (Reconfigure > Qos > Bitrate); a held estimate surfaces on a
111 /// later push, and BWE updates far slower than the frame rate. A target of
112 /// `0` is the shed-layer idle hint (M722): the consumer downstream is
113 /// discarding this stream (a starved simulcast layer), so the encoder
114 /// should mostly stop encoding until a non-zero target resumes it.
115 Bitrate(u32),
116}
117
118/// Downstream output for elements. Push is async so backpressure-aware
119/// implementations can await downstream capacity instead of erroring on a
120/// full link. The required method is the poll form, so a push through a
121/// `dyn OutputSink` costs no heap: `push` wraps it in the concrete
122/// [`PushFuture`] (provided here for concrete sinks and on the trait object
123/// for `&mut dyn OutputSink` callers, so `out.push(pkt).await` reads the same
124/// either way).
125pub trait OutputSink {
126 /// Drive one packet toward downstream. `packet` is `Some` until this
127 /// implementation commits it (or resolves it early: a probe drop, a
128 /// pre-send reconfigure); the caller re-polls with the same slot until
129 /// `Ready`. Taking the packet on an early outcome matches the old
130 /// by-value push, where an unsent packet was dropped with the future.
131 fn poll_push(
132 &mut self,
133 cx: &mut core::task::Context<'_>,
134 packet: &mut Option<PipelinePacket>,
135 ) -> core::task::Poll<Result<PushOutcome, G2gError>>;
136
137 /// Discard any phase a cancelled earlier push left behind. Runs once per
138 /// [`PushFuture`] construction; stateless sinks keep the no-op.
139 fn begin_push(&mut self) {}
140}
141
142/// `push` for concrete (sized) sinks. Separate from [`OutputSink`] because a
143/// provided method there is ambiguous against the inherent `push` on the
144/// trait object (an inherent impl on `dyn` does not shadow trait methods).
145pub trait OutputSinkExt: OutputSink + Sized {
146 fn push(&mut self, packet: PipelinePacket) -> PushFuture<'_, Self> {
147 self.begin_push();
148 PushFuture {
149 sink: self,
150 packet: Some(packet),
151 }
152 }
153}
154
155impl<S: OutputSink> OutputSinkExt for S {}
156
157impl<'e> dyn OutputSink + 'e {
158 /// [`OutputSink::push`] for trait objects (the provided method needs
159 /// `Self: Sized`).
160 pub fn push(&mut self, packet: PipelinePacket) -> PushFuture<'_, dyn OutputSink + 'e> {
161 self.begin_push();
162 PushFuture {
163 sink: self,
164 packet: Some(packet),
165 }
166 }
167}
168
169/// Concrete future behind [`OutputSink::push`]: the packet slot
170/// [`OutputSink::poll_push`] drains. No heap.
171#[allow(missing_debug_implementations)]
172pub struct PushFuture<'a, S: OutputSink + ?Sized> {
173 sink: &'a mut S,
174 packet: Option<PipelinePacket>,
175}
176
177impl<S: OutputSink + ?Sized> Future for PushFuture<'_, S> {
178 type Output = Result<PushOutcome, G2gError>;
179
180 fn poll(
181 self: Pin<&mut Self>,
182 cx: &mut core::task::Context<'_>,
183 ) -> core::task::Poll<Self::Output> {
184 let this = self.get_mut();
185 this.sink.poll_push(cx, &mut this.packet)
186 }
187}
188
189// Closed set: intentionally exhaustive (not #[non_exhaustive]); see STABILITY.md.
190#[derive(Debug)]
191pub enum ConfigureOutcome {
192 Accepted,
193 ReFixate(Caps),
194}
195
196impl ConfigureOutcome {
197 /// Reject a mid-negotiation renegotiation request: at startup the caps handed
198 /// to `configure_pipeline` are already fixated, so an element that answers
199 /// `ReFixate` cannot be honored and is a hard error. Collapses the
200 /// `if let ConfigureOutcome::ReFixate(_) = elem.configure_pipeline(..)? { return
201 /// Err(FixationFailed) }` guard repeated across the runner startup paths.
202 pub fn reject_refixate(self) -> Result<(), G2gError> {
203 match self {
204 ConfigureOutcome::Accepted => Ok(()),
205 ConfigureOutcome::ReFixate(_) => Err(G2gError::FixationFailed),
206 }
207 }
208}
209
210pub trait AsyncElement: ElementBound {
211 type ProcessFuture<'a>: Future<Output = Result<(), G2gError>> + 'a
212 where
213 Self: 'a;
214
215 fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError>;
216
217 fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError>;
218
219 /// Receive this element's negotiated OUTPUT (source-pad) caps after the
220 /// solve, alongside the input caps from [`configure_pipeline`] (M185). A
221 /// geometry / format / rate-changing transform (videoscale, videoconvert,
222 /// audioresample) uses this to take its target from a downstream capsfilter
223 /// instead of its own properties, the gst caps-driven idiom. Default: no-op,
224 /// so elements that don't need it (and runners that don't yet deliver it)
225 /// are unaffected. Called only on transforms, with their single output
226 /// link's caps; sources and sinks never receive it.
227 fn configure_output(&mut self, _output_caps: &Caps) -> Result<(), G2gError> {
228 Ok(())
229 }
230
231 fn process<'a>(
232 &'a mut self,
233 packet: PipelinePacket,
234 out: &'a mut dyn OutputSink,
235 ) -> Self::ProcessFuture<'a>;
236
237 /// This element's contribution to the pipeline latency query (M12).
238 /// Default: zero, non-live. Transforms that buffer (jitter buffers,
239 /// reorder queues) and live sources override this; the linear runners
240 /// fold the chain into `RunStats::latency`.
241 fn latency(&self) -> LatencyReport {
242 LatencyReport::ZERO
243 }
244
245 /// The memory domain of the frames this element emits on its output pad.
246 /// Default [`System`](MemoryDomainKind::System); a GPU producer (a hardware
247 /// decoder emitting into VRAM, a wgpu/CUDA bridge) overrides it. Surfaced
248 /// per edge by the negotiate-only path so the DOT dump can mark the GPU /
249 /// zero-copy links (it is not part of `Caps`; see DESIGN.md 4.13.9).
250 fn output_memory(&self) -> MemoryDomainKind {
251 MemoryDomainKind::System
252 }
253
254 /// The full set of memory domains this element *can* emit on its output pad,
255 /// not just its preferred one. The producer-capability half of the M351
256 /// two-sided allocation-domain negotiation: the runner intersects it with the
257 /// downstream consumers' acceptance set and settles on a single domain, so a
258 /// decoder that can deliver to System *or* stay resident on the GPU lets the
259 /// runner keep the frame copy-free when a downstream wants it. Default: just
260 /// [`output_memory`](Self::output_memory), so a single-domain element
261 /// negotiates exactly as before. A multi-domain producer overrides this.
262 fn output_domains(&self) -> DomainSet {
263 DomainSet::only(self.output_memory())
264 }
265
266 /// The memory domains this element can accept on its *input* pad (M354), for
267 /// the domain-converter auto-plug. Default [`DomainSet::ALL`] (no requirement,
268 /// so no converter is forced); a domain-strict element (a CUDA encoder/sink
269 /// that needs device-resident input) narrows it, and the auto-plug splices a
270 /// converter when the upstream cannot produce a domain in this set. A pure
271 /// pass-through element (a memory-domain converter, an aggregator) leaves it
272 /// `ALL`. Caps-free so the splice runs before the caps solve.
273 fn input_domains(&self) -> DomainSet {
274 DomainSet::ALL
275 }
276
277 /// Answer the upstream peer's allocation query (M12): the buffer size,
278 /// count, alignment, and memory domain this element needs allocated so a
279 /// pool can be handed over without a copy. Default: no preference
280 /// (`None`). A transform that has already received its own downstream
281 /// proposal via [`configure_allocation`](Self::configure_allocation) can
282 /// fold it in with [`AllocationParams::merge`].
283 fn propose_allocation(&self, _caps: &Caps) -> Option<AllocationParams> {
284 None
285 }
286
287 /// Receive the downstream peer's allocation proposal (M12) so this element
288 /// can allocate its output buffers from a compatible pool. Default:
289 /// ignore and allocate however the element sees fit.
290 fn configure_allocation(&mut self, _params: &AllocationParams) {}
291
292 /// Offer a clock to the pipeline's clock election (M12). Default: none.
293 /// Elements that pace to real hardware (an audio sink to its DAC) override
294 /// this; the runner elects the highest-priority offered clock.
295 fn provide_clock(&self) -> Option<ClockCandidate> {
296 None
297 }
298
299 /// Receive the pipeline's elected clock + base time after election, so a
300 /// sink can present each frame at its running-time deadline (PTS mapped
301 /// through the active `Segment`) โ the "use PTS to decide when to display"
302 /// path. The runner calls this once before streaming, only when a clock was
303 /// elected. Default: ignore (present as fast as backpressure allows, the
304 /// pre-sync behaviour). See [`ClockSync`].
305 fn set_clock_sync(&mut self, _sync: ClockSync) {}
306
307 /// Take any QoS signal this element wants to send upstream, consuming it. A
308 /// synchronising sink that dropped a late frame returns a [`QosMessage`]
309 /// here; the runner forwards it onto the element's incoming link, where the
310 /// producer observes it as [`PushOutcome::Qos`]. Called by the runner after
311 /// each `process`. Default: nothing to send.
312 fn take_qos(&mut self) -> Option<QosMessage> {
313 None
314 }
315
316 /// Cumulative presentation counters a paced sink kept over the run, read by
317 /// the runner once its arm ends and surfaced in `RunStats::per_element`. A
318 /// display / audio sink that counts what it actually presented overrides
319 /// this. Default: not a presenting sink.
320 fn presentation_stats(&self) -> Option<PresentationStats> {
321 None
322 }
323
324 /// Take any [`Reconfigure`] this element wants to send upstream, consuming
325 /// it. The sink/transform analog of [`Self::take_qos`]: the runner forwards
326 /// it onto the element's incoming link, where the producer observes it as
327 /// [`PushOutcome::Reconfigure`]. The keyframe-request path uses this: a
328 /// WebRTC egress sink that received a remote PLI returns
329 /// [`Reconfigure::ForceKeyframe`] so the upstream encoder emits an IDR.
330 /// Called by the runner after each `process`. Default: nothing to send.
331 fn take_reconfigure(&mut self) -> Option<Reconfigure> {
332 None
333 }
334
335 /// Take a target send bitrate (bits/second) this element wants to push
336 /// upstream, consuming it. A WebRTC egress sink returns its latest
337 /// congestion-control / BWE estimate here; the runner forwards it onto the
338 /// incoming link, where the encoder observes it as [`PushOutcome::Bitrate`]
339 /// and retargets. Called by the runner after each `process`. Default: none.
340 fn take_bitrate(&mut self) -> Option<u32> {
341 None
342 }
343
344 /// Whether this element consumes a downstream keyframe request
345 /// (`PushOutcome::Reconfigure(ForceKeyframe)`) itself, i.e. it is an
346 /// encoder that forces an IDR. Default `false`: the runner then relays the
347 /// request onto the element's input link (M720), so a PLI crosses any
348 /// number of pass-through transforms (a parser between the encoder and a
349 /// WebRTC sink) to reach the encoder.
350 fn handles_keyframe_requests(&self) -> bool {
351 false
352 }
353
354 /// As [`Self::handles_keyframe_requests`], for a downstream bitrate target
355 /// (`PushOutcome::Bitrate`): an encoder that retargets returns `true`.
356 fn handles_bitrate_requests(&self) -> bool {
357 false
358 }
359
360 /// Whether this sink applies an
361 /// [`OrientationMeta`](crate::meta::OrientationMeta) itself, i.e. it can
362 /// turn the picture for free at present time. The runner sends
363 /// [`Reconfigure::AbsorbOrientation`] up this sink's input link before the
364 /// first frame is pulled, so a `videoflip` upstream attaches the descriptor
365 /// instead of remapping pixels. Default `false`: the flip realizes the
366 /// rotation as it always did.
367 fn absorbs_orientation(&self) -> bool {
368 false
369 }
370
371 /// Whether [`Reconfigure::AbsorbOrientation`] stops at this element instead
372 /// of being relayed toward the source. `true` for `videoflip`, which answers
373 /// it by switching to the descriptor, and for any transform whose output
374 /// geometry is chosen in the buffer's stored coordinates (a crop), which
375 /// would mean something different once the picture is turned. Default
376 /// `false`: the advertisement crosses.
377 ///
378 /// An element that returns `true` sees the signal as
379 /// [`PushOutcome::Reconfigure`] from its own `push`, and the pre-send check
380 /// holds that packet back rather than enqueuing it, so it has to push the
381 /// packet again.
382 fn handles_orientation(&self) -> bool {
383 false
384 }
385
386 /// Whether this element acts on a downstream QoS report itself, ie it sheds
387 /// work when the sink is behind (a decoder skipping non-reference frames).
388 /// Default `false`: the runner relays the report onto the element's input
389 /// link (M175) so it reaches the source, and `process` never sees it.
390 /// `true` surfaces it as [`PushOutcome::Qos`] from the element's own `push`
391 /// instead, and the relay stops here.
392 fn handles_qos(&self) -> bool {
393 false
394 }
395
396 /// Declares that this element changes the caps "domain" between its
397 /// input and output: a decoder turns compressed bitstream into raw
398 /// pixels, an encoder turns raw pixels into compressed bitstream, a
399 /// format converter shifts color space, etc. Default: false.
400 ///
401 /// Currently informational. The runner uses a single linear caps
402 /// cascade and the three workarounds documented in
403 /// `architecture_caps_nego_debt` apply on its behalf. The planned
404 /// caps redesign (Plan 2) will use this hint to split the pipeline
405 /// into per-domain negotiation segments, eliminating the
406 /// pass-through `intercept_caps` and deferred-configure dance that
407 /// sinks downstream of a boundary currently rely on.
408 ///
409 /// Declaring this true today changes no behavior โ it's a forward
410 /// declaration so the redesign can roll out without simultaneously
411 /// migrating every decoder.
412 fn is_format_boundary(&self) -> bool {
413 false
414 }
415
416 /// Derive the element's *output* caps from its negotiated input
417 /// caps. Only consulted by the runner when `is_format_boundary()`
418 /// is true. Default: pass input through (correct for non-boundary
419 /// elements that don't change format).
420 ///
421 /// Boundary elements (decoders, encoders, format converters)
422 /// override this to advertise their post-transform caps so the
423 /// downstream segment can negotiate honestly. A decoder typically
424 /// reads dims from the input caps (already populated from the
425 /// stream's SPS / container header) and returns raw video caps at
426 /// matching geometry.
427 ///
428 /// If the output caps genuinely can't be known until first decoded
429 /// frame (rare for modern stream containers), return ranged caps
430 /// here and emit a fixing `CapsChanged` mid-stream.
431 fn propose_output_caps(&self, input: &Caps) -> Caps {
432 input.clone()
433 }
434
435 /// The metadata [`Transform`](crate::meta::Transform) this element applies to
436 /// per-frame metadata, or `None` to opt out (the default). When `Some(t)` the
437 /// runner clones each input frame's metadata,
438 /// [`propagate(t)`](crate::meta::FrameMetaSet::propagate)s it, and attaches
439 /// the survivors to output frames whose own metadata is empty
440 /// (element-authored meta is never overwritten). `None` means the element
441 /// carries meta through itself (a pass-through forwarding the same frame) or
442 /// produces none, so the runner does nothing. Association is exact for a
443 /// 1-in-1-out transform; a pipelined element gets most-recent-input
444 /// association. See DESIGN.md 5.4.
445 #[cfg(feature = "metadata")]
446 fn meta_transform(&self) -> Option<crate::meta::Transform> {
447 None
448 }
449
450 /// The per-frame metadata this element wants attached to the frames it
451 /// receives (M976), the pull half of `meta_transform`'s push half. The
452 /// runner unions the declaration into the allocation cascade travelling
453 /// upstream, so a producer any number of hops away can ask
454 /// [`MetaRequests::wants`](crate::meta::MetaRequests::wants) in
455 /// [`configure_allocation`](Self::configure_allocation) and skip work nobody
456 /// downstream reads. Default: nothing requested, and a graph where every
457 /// element defaults cascades exactly as it did before the hook existed.
458 ///
459 /// Requesting a meta is a hint, never a guarantee: a consumer must still
460 /// handle a frame arriving without it (no producer upstream may be able to
461 /// attach one). Without the `metadata` feature
462 /// [`MetaRequests`](crate::meta::MetaRequests) is a zero-sized empty set, so
463 /// overriding this can only return the default.
464 fn meta_requests(&self) -> crate::meta::MetaRequests {
465 crate::meta::MetaRequests::new()
466 }
467
468 /// M16 step 5b: declare this element's negotiation-time constraint
469 /// when used as the **sink** of a chain. The default returns the
470 /// legacy bridge (`LegacySink` wrapping today's `intercept_caps`).
471 /// Migrated sinks override with `Accepts(CapsSet)` (or a more
472 /// elaborate native variant) to participate in arc consistency
473 /// and skip the dynamic intercept callback.
474 fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
475 legacy_sink_constraint(self)
476 }
477
478 /// M16 step 5b: same as `caps_constraint_as_sink` but for the
479 /// **transform** role. Default returns `LegacyTransform` wrapping
480 /// today's `intercept_caps` + `propose_output_caps`. Migrated
481 /// transforms override with `Identity` / `Mapping` /
482 /// `DerivedOutput`.
483 fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
484 legacy_transform_constraint(self)
485 }
486
487 /// What this element is willing to pay for each alternative of the set its
488 /// `caps_constraint_as_*` advertises. Default `None`: the alternatives are
489 /// already in preference order and cost their index. An element overrides
490 /// this to declare *equal* cost between alternatives it does not care
491 /// about (so a neighbour's preference decides) or a gap wide enough that a
492 /// neighbour's preference cannot pull the chain onto its fallback.
493 fn caps_preferences(&self) -> Option<CapsPreferences> {
494 None
495 }
496
497 /// The runtime properties this element type exposes (M104), the GObject
498 /// property-spec analog. Default: none. An element overrides this (and
499 /// [`set_property`](Self::set_property) / [`get_property`](Self::get_property))
500 /// to be settable by name from a `gst-launch` pipeline or inspectable by a
501 /// `gst-inspect` dump. The `with_*` builders remain the zero-cost
502 /// construction path; this is the string-keyed runtime face.
503 fn properties(&self) -> &'static [PropertySpec] {
504 &[]
505 }
506
507 /// Static introspection metadata for this element type (M178): the
508 /// `gst-inspect` "Factory Details" (long-name / classification / description
509 /// / author). Default: empty, like [`properties`](Self::properties). An
510 /// element overrides it with a `const ElementMetadata` to document itself.
511 fn metadata(&self) -> ElementMetadata {
512 ElementMetadata::default()
513 }
514
515 /// Receive this instance's log name (M179), assigned by the runner as
516 /// `<category>N`. Default: ignore. An element that logs about itself stores
517 /// it and returns it from its [`LogSource`](crate::log::LogSource) so its log
518 /// lines carry the instance name.
519 fn set_instance_name(&mut self, _name: alloc::string::String) {}
520
521 /// Override this instance's log category (M845), which is otherwise the
522 /// element type name. Default: ignore. An element that logs about itself
523 /// stores it (in a [`LogName`](crate::log::LogName)) and returns it from
524 /// `LogSource::log_category_override`, so `G2G_DEBUG` filtering keys off the
525 /// override for this instance while its siblings keep the type category.
526 fn set_log_category(&mut self, _category: alloc::string::String) {}
527
528 /// Set a property by name (M104). Default: every name is
529 /// [`PropError::Unknown`] (no properties). An overriding element validates
530 /// the value kind against its [`properties`](Self::properties) spec and
531 /// applies it.
532 fn set_property(&mut self, _name: &str, _value: PropValue) -> Result<(), PropError> {
533 Err(PropError::Unknown)
534 }
535
536 /// Read a property back by name (M104). Default: `None`. Overriding elements
537 /// return the current value for a known property.
538 fn get_property(&self, _name: &str) -> Option<PropValue> {
539 None
540 }
541
542 /// The log category for this element (M179): its short type name by
543 /// default, the `G2G_DEBUG` filtering key. A wrapper that erases another
544 /// element forwards the inner one's category instead.
545 fn log_category(&self) -> &'static str {
546 crate::log::short_type_name::<Self>()
547 }
548}
549
550/// Dyn-safe variant of [`AsyncElement`] for plugin registries on `std` targets.
551/// `no_std` graphs use the monomorphised `AsyncElement` directly.
552#[cfg(feature = "std")]
553pub trait DynAsyncElement: ElementBound {
554 fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError>;
555
556 fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError>;
557
558 /// Dyn-safe mirror of [`AsyncElement::configure_output`] (M185). Defaults to
559 /// no-op so unaffected erased elements need not implement it.
560 fn configure_output(&mut self, _output_caps: &Caps) -> Result<(), G2gError> {
561 Ok(())
562 }
563
564 fn process<'a>(
565 &'a mut self,
566 packet: PipelinePacket,
567 out: &'a mut dyn OutputSink,
568 ) -> core::pin::Pin<alloc::boxed::Box<dyn Future<Output = Result<(), G2gError>> + 'a>>;
569
570 /// Dyn-safe mirror of [`AsyncElement::caps_constraint_as_sink`], so a
571 /// `Box`-erased branch sink (fan-out Phase C FO-2) can be re-solved
572 /// against its declared constraint on a mid-stream `CapsChanged`.
573 fn caps_constraint_as_sink(&self) -> CapsConstraint<'_>;
574
575 /// Dyn-safe mirror of [`AsyncElement::caps_constraint_as_transform`], so
576 /// an interior element of an N-element linear chain (`run_linear_chain`)
577 /// declares its transform constraint to the solver while erased.
578 fn caps_constraint_as_transform(&self) -> CapsConstraint<'_>;
579
580 /// Dyn-safe mirror of [`AsyncElement::caps_preferences`], so an erased
581 /// element's declared per-alternative costs reach the solver. Defaults to
582 /// `None` (cost = alternative index), matching `AsyncElement`.
583 fn caps_preferences(&self) -> Option<CapsPreferences> {
584 None
585 }
586
587 /// Dyn-safe mirror of [`AsyncElement::propose_allocation`], so a
588 /// `Box`-erased branch sink can re-derive its own pool on a mid-stream
589 /// caps change (fan-out element-local ฮฑ).
590 fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams>;
591
592 /// Dyn-safe mirror of [`AsyncElement::configure_allocation`].
593 fn configure_allocation(&mut self, params: &AllocationParams);
594
595 /// Dyn-safe mirror of [`AsyncElement::latency`], so a buffering interior
596 /// element of an N-element chain (`run_linear_chain`) contributes to the
597 /// runner's latency fold. Defaults to zero, matching `AsyncElement`.
598 fn latency(&self) -> LatencyReport {
599 LatencyReport::ZERO
600 }
601
602 /// Dyn-safe mirror of [`AsyncElement::output_memory`]. Default
603 /// [`System`](MemoryDomainKind::System).
604 fn output_memory(&self) -> MemoryDomainKind {
605 MemoryDomainKind::System
606 }
607
608 /// Dyn-safe mirror of [`AsyncElement::output_domains`]. Default
609 /// `only(output_memory())`.
610 fn output_domains(&self) -> DomainSet {
611 DomainSet::only(self.output_memory())
612 }
613
614 /// Dyn-safe mirror of [`AsyncElement::input_domains`]. Default
615 /// [`DomainSet::ALL`].
616 fn input_domains(&self) -> DomainSet {
617 DomainSet::ALL
618 }
619
620 /// Dyn-safe mirror of [`AsyncElement::meta_transform`]. Default `None`.
621 #[cfg(feature = "metadata")]
622 fn meta_transform(&self) -> Option<crate::meta::Transform> {
623 None
624 }
625
626 /// Dyn-safe mirror of [`AsyncElement::meta_requests`]. Default: nothing
627 /// requested.
628 fn meta_requests(&self) -> crate::meta::MetaRequests {
629 crate::meta::MetaRequests::new()
630 }
631
632 /// Dyn-safe mirror of [`AsyncElement::provide_clock`], so an interior
633 /// element that paces to hardware joins the runner's clock election.
634 /// Defaults to none.
635 fn provide_clock(&self) -> Option<ClockCandidate> {
636 None
637 }
638
639 /// Dyn-safe mirror of [`AsyncElement::set_clock_sync`], so an erased sink
640 /// receives the elected clock + base time. Defaults to ignore.
641 fn set_clock_sync(&mut self, _sync: ClockSync) {}
642
643 /// Dyn-safe mirror of [`AsyncElement::take_qos`], so an erased sink can send
644 /// a QoS signal upstream. Defaults to nothing.
645 fn take_qos(&mut self) -> Option<QosMessage> {
646 None
647 }
648
649 /// Dyn-safe mirror of [`AsyncElement::presentation_stats`], so the runner
650 /// can read an erased sink's presentation counters at end of run.
651 fn presentation_stats(&self) -> Option<PresentationStats> {
652 None
653 }
654
655 /// Dyn-safe mirror of [`AsyncElement::take_reconfigure`], so an erased sink
656 /// can request a keyframe / renegotiation upstream. Defaults to nothing.
657 fn take_reconfigure(&mut self) -> Option<Reconfigure> {
658 None
659 }
660
661 /// Dyn-safe mirror of [`AsyncElement::take_bitrate`], so an erased sink can
662 /// push a target bitrate upstream. Defaults to nothing.
663 fn take_bitrate(&mut self) -> Option<u32> {
664 None
665 }
666
667 /// Dyn-safe mirror of [`AsyncElement::handles_keyframe_requests`] (M720).
668 fn handles_keyframe_requests(&self) -> bool {
669 false
670 }
671
672 /// Dyn-safe mirror of [`AsyncElement::handles_bitrate_requests`] (M720).
673 fn handles_bitrate_requests(&self) -> bool {
674 false
675 }
676
677 /// Dyn-safe mirror of [`AsyncElement::absorbs_orientation`] (M1058).
678 fn absorbs_orientation(&self) -> bool {
679 false
680 }
681
682 /// Dyn-safe mirror of [`AsyncElement::handles_orientation`] (M1058).
683 fn handles_orientation(&self) -> bool {
684 false
685 }
686
687 /// Dyn-safe mirror of [`AsyncElement::handles_qos`] (M997).
688 fn handles_qos(&self) -> bool {
689 false
690 }
691
692 /// Dyn-safe mirror of [`AsyncElement::properties`], so a `gst-inspect` dump
693 /// and the `gst-launch` parser can introspect / set an erased element.
694 fn properties(&self) -> &'static [PropertySpec] {
695 &[]
696 }
697
698 /// Dyn-safe mirror of [`AsyncElement::metadata`], so a `gst-inspect` dump can
699 /// read an erased element's "Factory Details". Defaults to empty.
700 fn metadata(&self) -> ElementMetadata {
701 ElementMetadata::default()
702 }
703
704 /// The log category for this erased element (M179): its short type name by
705 /// default (the blanket impl fills it from `core::any::type_name`), so the
706 /// runner can name (`<category>N`) and log about any element. Filtering key.
707 fn log_category(&self) -> &'static str {
708 "element"
709 }
710
711 /// Dyn-safe mirror of [`AsyncElement::set_instance_name`], so the runner can
712 /// name an erased element instance for logging.
713 fn set_instance_name(&mut self, _name: alloc::string::String) {}
714
715 /// Dyn-safe mirror of [`AsyncElement::set_log_category`].
716 fn set_log_category(&mut self, _category: alloc::string::String) {}
717
718 /// Dyn-safe mirror of [`AsyncElement::set_property`]. Defaults to "no
719 /// properties" so a hand-written `DynAsyncElement` need not implement it; the
720 /// blanket `impl<T: AsyncElement>` overrides it to forward to the element.
721 fn set_property(&mut self, _name: &str, _value: PropValue) -> Result<(), PropError> {
722 Err(PropError::Unknown)
723 }
724
725 /// Dyn-safe mirror of [`AsyncElement::get_property`]. Defaults to `None`; the
726 /// blanket impl forwards to the element.
727 fn get_property(&self, _name: &str) -> Option<PropValue> {
728 None
729 }
730
731 /// Consume this element into its graph-runner transform arm (M1000). The
732 /// blanket impl monomorphizes the arm loop over the concrete element type,
733 /// so the per-frame `process` future is unboxed: the one box is this
734 /// method's returned arm future, once per run. Implementations outside the
735 /// blanket cannot build the runner's `TransformArmIo`; implement
736 /// [`AsyncElement`] instead.
737 #[cfg(feature = "runtime")]
738 #[doc(hidden)]
739 fn drive_transform_arm<'s>(
740 self: alloc::boxed::Box<Self>,
741 io: crate::runtime::TransformArmIo,
742 ) -> BoxFuture<'s, Result<u64, G2gError>>
743 where
744 Self: 's;
745
746 /// As [`Self::drive_transform_arm`], for the sink arm.
747 #[cfg(feature = "runtime")]
748 #[doc(hidden)]
749 fn drive_sink_arm<'s>(
750 self: alloc::boxed::Box<Self>,
751 io: crate::runtime::SinkArmIo,
752 ) -> BoxFuture<'s, Result<u64, G2gError>>
753 where
754 Self: 's;
755}
756
757/// Blanket adapter: every [`AsyncElement`] is usable as a
758/// [`DynAsyncElement`] by boxing its `process` future (DESIGN.md ยง4.3).
759/// This is what lets real plugin elements drop into a `Box<dyn
760/// DynAsyncElement>` slot without a hand-written impl. Method calls are
761/// disambiguated to `AsyncElement::` because the two traits share names.
762#[cfg(feature = "std")]
763impl<T: AsyncElement> DynAsyncElement for T {
764 fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError> {
765 AsyncElement::intercept_caps(self, upstream_caps)
766 }
767
768 fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError> {
769 AsyncElement::configure_pipeline(self, absolute_caps)
770 }
771
772 fn configure_output(&mut self, output_caps: &Caps) -> Result<(), G2gError> {
773 AsyncElement::configure_output(self, output_caps)
774 }
775
776 fn process<'a>(
777 &'a mut self,
778 packet: PipelinePacket,
779 out: &'a mut dyn OutputSink,
780 ) -> BoxFuture<'a, Result<(), G2gError>> {
781 Box::pin(AsyncElement::process(self, packet, out))
782 }
783
784 fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
785 AsyncElement::caps_constraint_as_sink(self)
786 }
787
788 fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
789 AsyncElement::caps_constraint_as_transform(self)
790 }
791
792 fn caps_preferences(&self) -> Option<CapsPreferences> {
793 AsyncElement::caps_preferences(self)
794 }
795
796 fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams> {
797 AsyncElement::propose_allocation(self, caps)
798 }
799
800 fn configure_allocation(&mut self, params: &AllocationParams) {
801 AsyncElement::configure_allocation(self, params)
802 }
803
804 fn latency(&self) -> LatencyReport {
805 AsyncElement::latency(self)
806 }
807
808 fn output_memory(&self) -> MemoryDomainKind {
809 AsyncElement::output_memory(self)
810 }
811
812 fn output_domains(&self) -> DomainSet {
813 AsyncElement::output_domains(self)
814 }
815
816 fn input_domains(&self) -> DomainSet {
817 AsyncElement::input_domains(self)
818 }
819
820 #[cfg(feature = "metadata")]
821 fn meta_transform(&self) -> Option<crate::meta::Transform> {
822 AsyncElement::meta_transform(self)
823 }
824
825 fn meta_requests(&self) -> crate::meta::MetaRequests {
826 AsyncElement::meta_requests(self)
827 }
828
829 fn provide_clock(&self) -> Option<ClockCandidate> {
830 AsyncElement::provide_clock(self)
831 }
832
833 fn set_clock_sync(&mut self, sync: ClockSync) {
834 AsyncElement::set_clock_sync(self, sync)
835 }
836
837 fn take_qos(&mut self) -> Option<QosMessage> {
838 AsyncElement::take_qos(self)
839 }
840
841 fn presentation_stats(&self) -> Option<PresentationStats> {
842 AsyncElement::presentation_stats(self)
843 }
844
845 fn take_reconfigure(&mut self) -> Option<Reconfigure> {
846 AsyncElement::take_reconfigure(self)
847 }
848
849 fn take_bitrate(&mut self) -> Option<u32> {
850 AsyncElement::take_bitrate(self)
851 }
852
853 fn handles_keyframe_requests(&self) -> bool {
854 AsyncElement::handles_keyframe_requests(self)
855 }
856
857 fn handles_bitrate_requests(&self) -> bool {
858 AsyncElement::handles_bitrate_requests(self)
859 }
860
861 fn absorbs_orientation(&self) -> bool {
862 AsyncElement::absorbs_orientation(self)
863 }
864
865 fn handles_orientation(&self) -> bool {
866 AsyncElement::handles_orientation(self)
867 }
868
869 fn handles_qos(&self) -> bool {
870 AsyncElement::handles_qos(self)
871 }
872
873 fn properties(&self) -> &'static [PropertySpec] {
874 AsyncElement::properties(self)
875 }
876
877 fn metadata(&self) -> ElementMetadata {
878 AsyncElement::metadata(self)
879 }
880
881 fn log_category(&self) -> &'static str {
882 AsyncElement::log_category(self)
883 }
884
885 fn set_instance_name(&mut self, name: alloc::string::String) {
886 AsyncElement::set_instance_name(self, name)
887 }
888
889 fn set_log_category(&mut self, category: alloc::string::String) {
890 AsyncElement::set_log_category(self, category)
891 }
892
893 fn set_property(&mut self, name: &str, value: PropValue) -> Result<(), PropError> {
894 AsyncElement::set_property(self, name, value)
895 }
896
897 fn get_property(&self, name: &str) -> Option<PropValue> {
898 AsyncElement::get_property(self, name)
899 }
900
901 #[cfg(feature = "runtime")]
902 fn drive_transform_arm<'s>(
903 self: Box<Self>,
904 io: crate::runtime::TransformArmIo,
905 ) -> BoxFuture<'s, Result<u64, G2gError>>
906 where
907 Self: 's,
908 {
909 Box::pin(crate::runtime::transform_arm(*self, io))
910 }
911
912 #[cfg(feature = "runtime")]
913 fn drive_sink_arm<'s>(
914 self: Box<Self>,
915 io: crate::runtime::SinkArmIo,
916 ) -> BoxFuture<'s, Result<u64, G2gError>>
917 where
918 Self: 's,
919 {
920 Box::pin(crate::runtime::sink_arm(*self, io))
921 }
922}
923
924/// Private [`AsyncElement`] face over an erased element, so the generic
925/// (monomorphized) arms can drive a `&mut dyn DynAsyncElement` graph node too.
926/// Its per-frame process future stays boxed (the element underneath is
927/// erased); a newtype rather than an impl on `&mut dyn` itself, which would
928/// make method calls ambiguous wherever both traits are imported.
929#[cfg(all(feature = "std", feature = "runtime"))]
930struct DynRef<'b>(&'b mut (dyn DynAsyncElement + 'b));
931
932#[cfg(all(feature = "std", feature = "runtime"))]
933impl<'b> AsyncElement for DynRef<'b> {
934 type ProcessFuture<'a>
935 = BoxFuture<'a, Result<(), G2gError>>
936 where
937 Self: 'a;
938
939 fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError> {
940 self.0.intercept_caps(upstream_caps)
941 }
942
943 fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError> {
944 self.0.configure_pipeline(absolute_caps)
945 }
946
947 fn configure_output(&mut self, output_caps: &Caps) -> Result<(), G2gError> {
948 self.0.configure_output(output_caps)
949 }
950
951 fn process<'a>(
952 &'a mut self,
953 packet: PipelinePacket,
954 out: &'a mut dyn OutputSink,
955 ) -> Self::ProcessFuture<'a> {
956 self.0.process(packet, out)
957 }
958
959 fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
960 self.0.caps_constraint_as_sink()
961 }
962
963 fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
964 self.0.caps_constraint_as_transform()
965 }
966
967 fn caps_preferences(&self) -> Option<CapsPreferences> {
968 self.0.caps_preferences()
969 }
970
971 fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams> {
972 self.0.propose_allocation(caps)
973 }
974
975 fn configure_allocation(&mut self, params: &AllocationParams) {
976 self.0.configure_allocation(params)
977 }
978
979 fn latency(&self) -> LatencyReport {
980 self.0.latency()
981 }
982
983 fn output_memory(&self) -> MemoryDomainKind {
984 self.0.output_memory()
985 }
986
987 fn output_domains(&self) -> DomainSet {
988 self.0.output_domains()
989 }
990
991 fn input_domains(&self) -> DomainSet {
992 self.0.input_domains()
993 }
994
995 #[cfg(feature = "metadata")]
996 fn meta_transform(&self) -> Option<crate::meta::Transform> {
997 self.0.meta_transform()
998 }
999
1000 fn meta_requests(&self) -> crate::meta::MetaRequests {
1001 self.0.meta_requests()
1002 }
1003
1004 fn provide_clock(&self) -> Option<ClockCandidate> {
1005 self.0.provide_clock()
1006 }
1007
1008 fn set_clock_sync(&mut self, sync: ClockSync) {
1009 self.0.set_clock_sync(sync)
1010 }
1011
1012 fn take_qos(&mut self) -> Option<QosMessage> {
1013 self.0.take_qos()
1014 }
1015
1016 fn presentation_stats(&self) -> Option<PresentationStats> {
1017 self.0.presentation_stats()
1018 }
1019
1020 fn take_reconfigure(&mut self) -> Option<Reconfigure> {
1021 self.0.take_reconfigure()
1022 }
1023
1024 fn take_bitrate(&mut self) -> Option<u32> {
1025 self.0.take_bitrate()
1026 }
1027
1028 fn handles_keyframe_requests(&self) -> bool {
1029 self.0.handles_keyframe_requests()
1030 }
1031
1032 fn handles_bitrate_requests(&self) -> bool {
1033 self.0.handles_bitrate_requests()
1034 }
1035
1036 fn absorbs_orientation(&self) -> bool {
1037 self.0.absorbs_orientation()
1038 }
1039
1040 fn handles_orientation(&self) -> bool {
1041 self.0.handles_orientation()
1042 }
1043
1044 fn handles_qos(&self) -> bool {
1045 self.0.handles_qos()
1046 }
1047
1048 fn properties(&self) -> &'static [PropertySpec] {
1049 self.0.properties()
1050 }
1051
1052 fn metadata(&self) -> ElementMetadata {
1053 self.0.metadata()
1054 }
1055
1056 fn log_category(&self) -> &'static str {
1057 self.0.log_category()
1058 }
1059
1060 fn set_instance_name(&mut self, name: alloc::string::String) {
1061 self.0.set_instance_name(name)
1062 }
1063
1064 fn set_log_category(&mut self, category: alloc::string::String) {
1065 self.0.set_log_category(category)
1066 }
1067
1068 fn set_property(&mut self, name: &str, value: PropValue) -> Result<(), PropError> {
1069 self.0.set_property(name, value)
1070 }
1071
1072 fn get_property(&self, name: &str) -> Option<PropValue> {
1073 self.0.get_property(name)
1074 }
1075}
1076
1077/// Forwarding impl so a borrowed `&mut dyn DynAsyncElement` can be boxed into a
1078/// `Box<dyn DynAsyncElement + 'a>` graph node (the convenience wrappers build a
1079/// borrowing `Graph` over their `&mut` element references). Disjoint from the
1080/// `AsyncElement` blanket above: a `&mut dyn DynAsyncElement` does not implement
1081/// `AsyncElement`.
1082#[cfg(feature = "std")]
1083impl<'b> DynAsyncElement for &'b mut (dyn DynAsyncElement + 'b) {
1084 fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError> {
1085 (**self).intercept_caps(upstream_caps)
1086 }
1087
1088 fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError> {
1089 (**self).configure_pipeline(absolute_caps)
1090 }
1091
1092 fn configure_output(&mut self, output_caps: &Caps) -> Result<(), G2gError> {
1093 (**self).configure_output(output_caps)
1094 }
1095
1096 fn process<'a>(
1097 &'a mut self,
1098 packet: PipelinePacket,
1099 out: &'a mut dyn OutputSink,
1100 ) -> BoxFuture<'a, Result<(), G2gError>> {
1101 (**self).process(packet, out)
1102 }
1103
1104 fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
1105 (**self).caps_constraint_as_sink()
1106 }
1107
1108 fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
1109 (**self).caps_constraint_as_transform()
1110 }
1111
1112 fn caps_preferences(&self) -> Option<CapsPreferences> {
1113 (**self).caps_preferences()
1114 }
1115
1116 fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams> {
1117 (**self).propose_allocation(caps)
1118 }
1119
1120 fn configure_allocation(&mut self, params: &AllocationParams) {
1121 (**self).configure_allocation(params)
1122 }
1123
1124 fn latency(&self) -> LatencyReport {
1125 (**self).latency()
1126 }
1127
1128 fn output_memory(&self) -> MemoryDomainKind {
1129 (**self).output_memory()
1130 }
1131
1132 fn output_domains(&self) -> DomainSet {
1133 (**self).output_domains()
1134 }
1135
1136 fn input_domains(&self) -> DomainSet {
1137 (**self).input_domains()
1138 }
1139
1140 #[cfg(feature = "metadata")]
1141 fn meta_transform(&self) -> Option<crate::meta::Transform> {
1142 (**self).meta_transform()
1143 }
1144
1145 fn meta_requests(&self) -> crate::meta::MetaRequests {
1146 (**self).meta_requests()
1147 }
1148
1149 fn provide_clock(&self) -> Option<ClockCandidate> {
1150 (**self).provide_clock()
1151 }
1152
1153 fn set_clock_sync(&mut self, sync: ClockSync) {
1154 (**self).set_clock_sync(sync)
1155 }
1156
1157 fn take_qos(&mut self) -> Option<QosMessage> {
1158 (**self).take_qos()
1159 }
1160
1161 fn presentation_stats(&self) -> Option<PresentationStats> {
1162 (**self).presentation_stats()
1163 }
1164
1165 fn take_reconfigure(&mut self) -> Option<Reconfigure> {
1166 (**self).take_reconfigure()
1167 }
1168
1169 fn take_bitrate(&mut self) -> Option<u32> {
1170 (**self).take_bitrate()
1171 }
1172
1173 fn handles_keyframe_requests(&self) -> bool {
1174 (**self).handles_keyframe_requests()
1175 }
1176
1177 fn handles_bitrate_requests(&self) -> bool {
1178 (**self).handles_bitrate_requests()
1179 }
1180
1181 fn absorbs_orientation(&self) -> bool {
1182 (**self).absorbs_orientation()
1183 }
1184
1185 fn handles_orientation(&self) -> bool {
1186 (**self).handles_orientation()
1187 }
1188
1189 fn handles_qos(&self) -> bool {
1190 (**self).handles_qos()
1191 }
1192
1193 fn properties(&self) -> &'static [PropertySpec] {
1194 (**self).properties()
1195 }
1196
1197 fn metadata(&self) -> ElementMetadata {
1198 (**self).metadata()
1199 }
1200
1201 fn log_category(&self) -> &'static str {
1202 (**self).log_category()
1203 }
1204
1205 fn set_instance_name(&mut self, name: alloc::string::String) {
1206 (**self).set_instance_name(name)
1207 }
1208
1209 fn set_log_category(&mut self, category: alloc::string::String) {
1210 (**self).set_log_category(category)
1211 }
1212
1213 fn set_property(&mut self, name: &str, value: PropValue) -> Result<(), PropError> {
1214 (**self).set_property(name, value)
1215 }
1216
1217 fn get_property(&self, name: &str) -> Option<PropValue> {
1218 (**self).get_property(name)
1219 }
1220
1221 #[cfg(feature = "runtime")]
1222 fn drive_transform_arm<'s>(
1223 self: Box<Self>,
1224 io: crate::runtime::TransformArmIo,
1225 ) -> BoxFuture<'s, Result<u64, G2gError>>
1226 where
1227 Self: 's,
1228 {
1229 Box::pin(crate::runtime::transform_arm(DynRef(*self), io))
1230 }
1231
1232 #[cfg(feature = "runtime")]
1233 fn drive_sink_arm<'s>(
1234 self: Box<Self>,
1235 io: crate::runtime::SinkArmIo,
1236 ) -> BoxFuture<'s, Result<u64, G2gError>>
1237 where
1238 Self: 's,
1239 {
1240 Box::pin(crate::runtime::sink_arm(DynRef(*self), io))
1241 }
1242}