fuchsia_audio/
sigproc.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use {fidl_fuchsia_hardware_audio_signalprocessing as fhaudio_sigproc, zx_types};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Topology {
9    pub id: fhaudio_sigproc::TopologyId,
10    pub edge_pairs: Vec<fhaudio_sigproc::EdgePair>,
11}
12
13impl TryFrom<fhaudio_sigproc::Topology> for Topology {
14    type Error = String;
15
16    fn try_from(value: fhaudio_sigproc::Topology) -> Result<Self, Self::Error> {
17        let id = value.id.ok_or_else(|| "missing 'id'".to_string())?;
18        let edge_pairs = value
19            .processing_elements_edge_pairs
20            .ok_or_else(|| "missing 'processing_elements_edge_pairs'".to_string())?;
21        Ok(Self { id, edge_pairs })
22    }
23}
24
25impl From<Topology> for fhaudio_sigproc::Topology {
26    fn from(value: Topology) -> Self {
27        Self {
28            id: Some(value.id),
29            processing_elements_edge_pairs: Some(value.edge_pairs),
30            ..Default::default()
31        }
32    }
33}
34
35#[derive(Debug, Clone, PartialEq)]
36pub struct Element {
37    pub id: fhaudio_sigproc::ElementId,
38    pub type_: fhaudio_sigproc::ElementType,
39    pub type_specific: Option<TypeSpecificElement>,
40    pub description: Option<String>,
41    pub can_stop: Option<bool>,
42    pub can_bypass: Option<bool>,
43}
44
45impl TryFrom<fhaudio_sigproc::Element> for Element {
46    type Error = String;
47
48    fn try_from(value: fhaudio_sigproc::Element) -> Result<Self, Self::Error> {
49        let id = value.id.ok_or_else(|| "missing 'id'".to_string())?;
50        let type_ = value.type_.ok_or_else(|| "missing 'type'".to_string())?;
51        let type_specific: Option<TypeSpecificElement> =
52            value.type_specific.map(TryInto::try_into).transpose()?;
53        Ok(Self {
54            id,
55            type_,
56            type_specific,
57            description: value.description,
58            can_stop: value.can_stop,
59            can_bypass: value.can_bypass,
60        })
61    }
62}
63
64impl From<Element> for fhaudio_sigproc::Element {
65    fn from(value: Element) -> Self {
66        Self {
67            id: Some(value.id),
68            type_: Some(value.type_),
69            type_specific: value.type_specific.map(Into::into),
70            description: value.description,
71            can_stop: value.can_stop,
72            can_bypass: value.can_bypass,
73            ..Default::default()
74        }
75    }
76}
77
78#[derive(Debug, Clone, PartialEq)]
79pub enum TypeSpecificElement {
80    VendorSpecific(VendorSpecific),
81    Gain(Gain),
82    Equalizer(Equalizer),
83    Dynamics(Dynamics),
84    DaiInterconnect(DaiInterconnect),
85}
86
87impl TryFrom<fhaudio_sigproc::TypeSpecificElement> for TypeSpecificElement {
88    type Error = String;
89
90    fn try_from(value: fhaudio_sigproc::TypeSpecificElement) -> Result<Self, Self::Error> {
91        match value {
92            fhaudio_sigproc::TypeSpecificElement::VendorSpecific(vendor_specific) => {
93                Ok(Self::VendorSpecific(vendor_specific.try_into()?))
94            }
95            fhaudio_sigproc::TypeSpecificElement::Gain(gain) => Ok(Self::Gain(gain.try_into()?)),
96            fhaudio_sigproc::TypeSpecificElement::Equalizer(equalizer) => {
97                Ok(Self::Equalizer(equalizer.try_into()?))
98            }
99            fhaudio_sigproc::TypeSpecificElement::Dynamics(dynamics) => {
100                Ok(Self::Dynamics(dynamics.try_into()?))
101            }
102            fhaudio_sigproc::TypeSpecificElement::DaiInterconnect(dai_interconnect) => {
103                Ok(Self::DaiInterconnect(dai_interconnect.try_into()?))
104            }
105            _ => Err("unknown TypeSpecificElement variant".to_string()),
106        }
107    }
108}
109
110impl From<TypeSpecificElement> for fhaudio_sigproc::TypeSpecificElement {
111    fn from(value: TypeSpecificElement) -> Self {
112        match value {
113            TypeSpecificElement::VendorSpecific(vendor_specific) => {
114                Self::VendorSpecific(vendor_specific.into())
115            }
116            TypeSpecificElement::Gain(gain) => Self::Gain(gain.into()),
117            TypeSpecificElement::Equalizer(equalizer) => Self::Equalizer(equalizer.into()),
118            TypeSpecificElement::Dynamics(dynamics) => Self::Dynamics(dynamics.into()),
119            TypeSpecificElement::DaiInterconnect(dai_interconnect) => {
120                Self::DaiInterconnect(dai_interconnect.into())
121            }
122        }
123    }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub struct VendorSpecific {}
128
129impl TryFrom<fhaudio_sigproc::VendorSpecific> for VendorSpecific {
130    type Error = String;
131
132    fn try_from(_value: fhaudio_sigproc::VendorSpecific) -> Result<Self, Self::Error> {
133        Ok(Self {})
134    }
135}
136
137impl From<VendorSpecific> for fhaudio_sigproc::VendorSpecific {
138    fn from(_value: VendorSpecific) -> Self {
139        Default::default()
140    }
141}
142
143#[derive(Debug, Clone, Copy, PartialEq)]
144pub struct Gain {
145    pub type_: fhaudio_sigproc::GainType,
146    pub domain: Option<fhaudio_sigproc::GainDomain>,
147    pub range: GainRange,
148}
149
150impl TryFrom<fhaudio_sigproc::Gain> for Gain {
151    type Error = String;
152
153    fn try_from(value: fhaudio_sigproc::Gain) -> Result<Self, Self::Error> {
154        let type_ = value.type_.ok_or_else(|| "missing 'type'".to_string())?;
155        let min_gain = value.min_gain.ok_or_else(|| "missing 'min_gain'".to_string())?;
156        let max_gain = value.max_gain.ok_or_else(|| "missing 'max_gain'".to_string())?;
157        let min_gain_step =
158            value.min_gain_step.ok_or_else(|| "missing 'min_gain_step'".to_string())?;
159        let range = GainRange { min: min_gain, max: max_gain, min_step: min_gain_step };
160        Ok(Self { type_, domain: value.domain, range })
161    }
162}
163
164impl From<Gain> for fhaudio_sigproc::Gain {
165    fn from(value: Gain) -> Self {
166        Self {
167            type_: Some(value.type_),
168            domain: value.domain,
169            min_gain: Some(value.range.min),
170            max_gain: Some(value.range.max),
171            min_gain_step: Some(value.range.min_step),
172            ..Default::default()
173        }
174    }
175}
176
177#[derive(Debug, Clone, Copy, PartialEq)]
178pub struct GainRange {
179    pub min: f32,
180    pub max: f32,
181    pub min_step: f32,
182}
183
184#[derive(Debug, Clone, PartialEq)]
185pub struct Equalizer {
186    pub bands: Vec<EqualizerBand>,
187    pub supported_controls: Option<fhaudio_sigproc::EqualizerSupportedControls>,
188    pub can_disable_bands: Option<bool>,
189    pub min_frequency: u32,
190    pub max_frequency: u32,
191    pub max_q: Option<f32>,
192    pub min_gain_db: Option<f32>,
193    pub max_gain_db: Option<f32>,
194}
195
196impl TryFrom<fhaudio_sigproc::Equalizer> for Equalizer {
197    type Error = String;
198
199    fn try_from(value: fhaudio_sigproc::Equalizer) -> Result<Self, Self::Error> {
200        let bands: Vec<EqualizerBand> = value
201            .bands
202            .ok_or_else(|| "missing 'bands'".to_string())?
203            .into_iter()
204            .map(TryInto::try_into)
205            .collect::<Result<Vec<_>, _>>()?;
206        let min_frequency =
207            value.min_frequency.ok_or_else(|| "missing 'min_frequency'".to_string())?;
208        let max_frequency =
209            value.max_frequency.ok_or_else(|| "missing 'max_frequency'".to_string())?;
210        Ok(Self {
211            bands,
212            supported_controls: value.supported_controls,
213            can_disable_bands: value.can_disable_bands,
214            min_frequency,
215            max_frequency,
216            max_q: value.max_q,
217            min_gain_db: value.min_gain_db,
218            max_gain_db: value.max_gain_db,
219        })
220    }
221}
222
223impl From<Equalizer> for fhaudio_sigproc::Equalizer {
224    fn from(value: Equalizer) -> Self {
225        let bands: Vec<fhaudio_sigproc::EqualizerBand> =
226            value.bands.into_iter().map(Into::into).collect();
227        Self {
228            bands: Some(bands),
229            supported_controls: value.supported_controls,
230            can_disable_bands: value.can_disable_bands,
231            min_frequency: Some(value.min_frequency),
232            max_frequency: Some(value.max_frequency),
233            max_q: value.max_q,
234            min_gain_db: value.min_gain_db,
235            max_gain_db: value.max_gain_db,
236            ..Default::default()
237        }
238    }
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242pub struct EqualizerBand {
243    pub id: u64,
244}
245
246impl TryFrom<fhaudio_sigproc::EqualizerBand> for EqualizerBand {
247    type Error = String;
248
249    fn try_from(value: fhaudio_sigproc::EqualizerBand) -> Result<Self, Self::Error> {
250        let id = value.id.ok_or_else(|| "missing 'id'".to_string())?;
251        Ok(Self { id })
252    }
253}
254
255impl From<EqualizerBand> for fhaudio_sigproc::EqualizerBand {
256    fn from(value: EqualizerBand) -> Self {
257        Self { id: Some(value.id), ..Default::default() }
258    }
259}
260
261#[derive(Debug, Clone, PartialEq)]
262pub struct Dynamics {
263    pub bands: Vec<DynamicsBand>,
264    pub supported_controls: Option<fhaudio_sigproc::DynamicsSupportedControls>,
265}
266
267impl TryFrom<fhaudio_sigproc::Dynamics> for Dynamics {
268    type Error = String;
269
270    fn try_from(value: fhaudio_sigproc::Dynamics) -> Result<Self, Self::Error> {
271        let bands: Vec<DynamicsBand> = value
272            .bands
273            .ok_or_else(|| "missing 'bands'".to_string())?
274            .into_iter()
275            .map(TryInto::try_into)
276            .collect::<Result<Vec<_>, _>>()?;
277        Ok(Self { bands, supported_controls: value.supported_controls })
278    }
279}
280
281impl From<Dynamics> for fhaudio_sigproc::Dynamics {
282    fn from(value: Dynamics) -> Self {
283        let bands: Vec<fhaudio_sigproc::DynamicsBand> =
284            value.bands.into_iter().map(Into::into).collect();
285        Self {
286            bands: Some(bands),
287            supported_controls: value.supported_controls,
288            ..Default::default()
289        }
290    }
291}
292
293#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294pub struct DynamicsBand {
295    pub id: u64,
296}
297
298impl TryFrom<fhaudio_sigproc::DynamicsBand> for DynamicsBand {
299    type Error = String;
300
301    fn try_from(value: fhaudio_sigproc::DynamicsBand) -> Result<Self, Self::Error> {
302        let id = value.id.ok_or_else(|| "missing 'id'".to_string())?;
303        Ok(Self { id })
304    }
305}
306
307impl From<DynamicsBand> for fhaudio_sigproc::DynamicsBand {
308    fn from(value: DynamicsBand) -> Self {
309        Self { id: Some(value.id), ..Default::default() }
310    }
311}
312
313#[derive(Debug, Clone, Copy, PartialEq)]
314pub struct DaiInterconnect {
315    pub plug_detect_capabilities: fhaudio_sigproc::PlugDetectCapabilities,
316}
317
318impl TryFrom<fhaudio_sigproc::DaiInterconnect> for DaiInterconnect {
319    type Error = String;
320
321    fn try_from(value: fhaudio_sigproc::DaiInterconnect) -> Result<Self, Self::Error> {
322        let plug_detect_capabilities = value
323            .plug_detect_capabilities
324            .ok_or_else(|| "missing 'plug_detect_capabilities'".to_string())?;
325        Ok(Self { plug_detect_capabilities })
326    }
327}
328
329impl From<DaiInterconnect> for fhaudio_sigproc::DaiInterconnect {
330    fn from(value: DaiInterconnect) -> Self {
331        Self {
332            plug_detect_capabilities: Some(value.plug_detect_capabilities),
333            ..Default::default()
334        }
335    }
336}
337
338#[derive(Debug, Clone, PartialEq)]
339pub struct ElementState {
340    pub type_specific: Option<TypeSpecificElementState>,
341    pub vendor_specific_data: Option<Vec<u8>>,
342    pub started: bool,
343    pub bypassed: Option<bool>,
344    pub turn_on_delay_ns: Option<zx_types::zx_duration_t>,
345    pub turn_off_delay_ns: Option<zx_types::zx_duration_t>,
346    pub processing_delay_ns: Option<zx_types::zx_duration_t>,
347}
348
349impl TryFrom<fhaudio_sigproc::ElementState> for ElementState {
350    type Error = String;
351
352    fn try_from(value: fhaudio_sigproc::ElementState) -> Result<Self, Self::Error> {
353        let type_specific = value.type_specific.map(TryInto::try_into).transpose()?;
354        let started = value.started.ok_or_else(|| "missing 'started'".to_string())?;
355        Ok(Self {
356            type_specific,
357            vendor_specific_data: value.vendor_specific_data,
358            started,
359            bypassed: value.bypassed,
360            turn_on_delay_ns: value.turn_on_delay,
361            turn_off_delay_ns: value.turn_off_delay,
362            processing_delay_ns: value.processing_delay,
363        })
364    }
365}
366
367impl From<ElementState> for fhaudio_sigproc::ElementState {
368    fn from(value: ElementState) -> Self {
369        Self {
370            type_specific: value.type_specific.map(Into::into),
371            vendor_specific_data: value.vendor_specific_data,
372            started: Some(value.started),
373            bypassed: value.bypassed,
374            turn_on_delay: value.turn_on_delay_ns,
375            turn_off_delay: value.turn_off_delay_ns,
376            processing_delay: value.processing_delay_ns,
377            ..Default::default()
378        }
379    }
380}
381
382#[derive(Debug, Clone, PartialEq)]
383pub enum TypeSpecificElementState {
384    VendorSpecific(VendorSpecificElementState),
385    Gain(GainElementState),
386    Equalizer(EqualizerElementState),
387    Dynamics(DynamicsElementState),
388    DaiInterconnect(DaiInterconnectElementState),
389}
390
391impl TryFrom<fhaudio_sigproc::TypeSpecificElementState> for TypeSpecificElementState {
392    type Error = String;
393
394    fn try_from(value: fhaudio_sigproc::TypeSpecificElementState) -> Result<Self, Self::Error> {
395        match value {
396            fhaudio_sigproc::TypeSpecificElementState::VendorSpecific(vendor_specific_state) => {
397                Ok(Self::VendorSpecific(vendor_specific_state.try_into()?))
398            }
399            fhaudio_sigproc::TypeSpecificElementState::Gain(gain_state) => {
400                Ok(Self::Gain(gain_state.try_into()?))
401            }
402            fhaudio_sigproc::TypeSpecificElementState::Equalizer(equalizer_state) => {
403                Ok(Self::Equalizer(equalizer_state.try_into()?))
404            }
405            fhaudio_sigproc::TypeSpecificElementState::Dynamics(dynamics_state) => {
406                Ok(Self::Dynamics(dynamics_state.try_into()?))
407            }
408            fhaudio_sigproc::TypeSpecificElementState::DaiInterconnect(dai_interconnect_state) => {
409                Ok(Self::DaiInterconnect(dai_interconnect_state.try_into()?))
410            }
411            _ => Err("unknown TypeSpecificElementStateState variant".to_string()),
412        }
413    }
414}
415
416impl From<TypeSpecificElementState> for fhaudio_sigproc::TypeSpecificElementState {
417    fn from(value: TypeSpecificElementState) -> Self {
418        match value {
419            TypeSpecificElementState::VendorSpecific(vendor_specific_state) => {
420                Self::VendorSpecific(vendor_specific_state.into())
421            }
422            TypeSpecificElementState::Gain(gain_state) => Self::Gain(gain_state.into()),
423            TypeSpecificElementState::Equalizer(equalizer_state) => {
424                Self::Equalizer(equalizer_state.into())
425            }
426            TypeSpecificElementState::Dynamics(dynamics_state) => {
427                Self::Dynamics(dynamics_state.into())
428            }
429            TypeSpecificElementState::DaiInterconnect(dai_interconnect_state) => {
430                Self::DaiInterconnect(dai_interconnect_state.into())
431            }
432        }
433    }
434}
435
436#[derive(Debug, Clone, Copy, PartialEq, Eq)]
437pub struct VendorSpecificElementState {}
438
439impl TryFrom<fhaudio_sigproc::VendorSpecificState> for VendorSpecificElementState {
440    type Error = String;
441
442    fn try_from(_value: fhaudio_sigproc::VendorSpecificState) -> Result<Self, Self::Error> {
443        Ok(Self {})
444    }
445}
446
447impl From<VendorSpecificElementState> for fhaudio_sigproc::VendorSpecificState {
448    fn from(_value: VendorSpecificElementState) -> Self {
449        Default::default()
450    }
451}
452
453#[derive(Debug, Clone, Copy, PartialEq)]
454pub struct GainElementState {
455    pub gain: f32,
456}
457
458impl TryFrom<fhaudio_sigproc::GainElementState> for GainElementState {
459    type Error = String;
460
461    fn try_from(value: fhaudio_sigproc::GainElementState) -> Result<Self, Self::Error> {
462        let gain = value.gain.ok_or_else(|| "missing 'gain'".to_string())?;
463        Ok(Self { gain })
464    }
465}
466
467impl From<GainElementState> for fhaudio_sigproc::GainElementState {
468    fn from(value: GainElementState) -> Self {
469        Self { gain: Some(value.gain), ..Default::default() }
470    }
471}
472
473#[derive(Debug, Clone, PartialEq)]
474pub struct EqualizerElementState {
475    pub band_states: Vec<EqualizerBandState>,
476}
477
478impl TryFrom<fhaudio_sigproc::EqualizerElementState> for EqualizerElementState {
479    type Error = String;
480
481    fn try_from(value: fhaudio_sigproc::EqualizerElementState) -> Result<Self, Self::Error> {
482        let band_states = value
483            .band_states
484            .ok_or_else(|| "missing 'band_states'".to_string())?
485            .into_iter()
486            .map(TryInto::try_into)
487            .collect::<Result<Vec<_>, _>>()?;
488        Ok(Self { band_states })
489    }
490}
491
492impl From<EqualizerElementState> for fhaudio_sigproc::EqualizerElementState {
493    fn from(value: EqualizerElementState) -> Self {
494        let band_states: Vec<fhaudio_sigproc::EqualizerBandState> =
495            value.band_states.into_iter().map(Into::into).collect();
496        Self { band_states: Some(band_states), ..Default::default() }
497    }
498}
499
500#[derive(Debug, Clone, PartialEq)]
501pub struct EqualizerBandState {
502    pub id: u64,
503    pub type_: Option<fhaudio_sigproc::EqualizerBandType>,
504    pub frequency: Option<u32>,
505    pub q: Option<f32>,
506    pub gain_db: Option<f32>,
507    pub enabled: Option<bool>,
508}
509
510impl TryFrom<fhaudio_sigproc::EqualizerBandState> for EqualizerBandState {
511    type Error = String;
512
513    fn try_from(value: fhaudio_sigproc::EqualizerBandState) -> Result<Self, Self::Error> {
514        let id = value.id.ok_or_else(|| "missing 'id'".to_string())?;
515        Ok(Self {
516            id,
517            type_: value.type_,
518            frequency: value.frequency,
519            q: value.q,
520            gain_db: value.gain_db,
521            enabled: value.enabled,
522        })
523    }
524}
525
526impl From<EqualizerBandState> for fhaudio_sigproc::EqualizerBandState {
527    fn from(value: EqualizerBandState) -> Self {
528        Self {
529            id: Some(value.id),
530            type_: value.type_,
531            frequency: value.frequency,
532            q: value.q,
533            gain_db: value.gain_db,
534            enabled: value.enabled,
535            ..Default::default()
536        }
537    }
538}
539
540#[derive(Debug, Clone, PartialEq)]
541pub struct DynamicsElementState {
542    pub band_states: Vec<DynamicsBandState>,
543}
544
545impl TryFrom<fhaudio_sigproc::DynamicsElementState> for DynamicsElementState {
546    type Error = String;
547
548    fn try_from(value: fhaudio_sigproc::DynamicsElementState) -> Result<Self, Self::Error> {
549        let band_states = value
550            .band_states
551            .ok_or_else(|| "missing 'band_states'".to_string())?
552            .into_iter()
553            .map(TryInto::try_into)
554            .collect::<Result<Vec<_>, _>>()?;
555        Ok(Self { band_states })
556    }
557}
558
559impl From<DynamicsElementState> for fhaudio_sigproc::DynamicsElementState {
560    fn from(value: DynamicsElementState) -> Self {
561        let band_states: Vec<fhaudio_sigproc::DynamicsBandState> =
562            value.band_states.into_iter().map(Into::into).collect();
563        Self { band_states: Some(band_states), ..Default::default() }
564    }
565}
566
567#[derive(Debug, Clone, PartialEq)]
568pub struct DynamicsBandState {
569    pub id: u64,
570    pub min_frequency: u32,
571    pub max_frequency: u32,
572    pub threshold_db: f32,
573    pub threshold_type: fhaudio_sigproc::ThresholdType,
574    pub ratio: f32,
575    pub knee_width_db: Option<f32>,
576    pub attack: Option<zx_types::zx_duration_t>,
577    pub release: Option<zx_types::zx_duration_t>,
578    pub output_gain_db: Option<f32>,
579    pub input_gain_db: Option<f32>,
580    pub level_type: Option<fhaudio_sigproc::LevelType>,
581    pub lookahead: Option<zx_types::zx_duration_t>,
582    pub linked_channels: Option<bool>,
583}
584
585impl TryFrom<fhaudio_sigproc::DynamicsBandState> for DynamicsBandState {
586    type Error = String;
587
588    fn try_from(value: fhaudio_sigproc::DynamicsBandState) -> Result<Self, Self::Error> {
589        let id = value.id.ok_or_else(|| "missing 'id'".to_string())?;
590        let min_frequency =
591            value.min_frequency.ok_or_else(|| "missing 'min_frequency'".to_string())?;
592        let max_frequency =
593            value.max_frequency.ok_or_else(|| "missing 'max_frequency'".to_string())?;
594        let threshold_db =
595            value.threshold_db.ok_or_else(|| "missing 'threshold_db'".to_string())?;
596        let threshold_type =
597            value.threshold_type.ok_or_else(|| "missing 'threshold_type'".to_string())?;
598        let ratio = value.ratio.ok_or_else(|| "missing 'ratio'".to_string())?;
599        Ok(Self {
600            id,
601            min_frequency,
602            max_frequency,
603            threshold_db,
604            threshold_type,
605            ratio,
606            knee_width_db: value.knee_width_db,
607            attack: value.attack,
608            release: value.release,
609            output_gain_db: value.output_gain_db,
610            input_gain_db: value.input_gain_db,
611            level_type: value.level_type,
612            lookahead: value.lookahead,
613            linked_channels: value.linked_channels,
614        })
615    }
616}
617
618impl From<DynamicsBandState> for fhaudio_sigproc::DynamicsBandState {
619    fn from(value: DynamicsBandState) -> Self {
620        Self {
621            id: Some(value.id),
622            min_frequency: Some(value.min_frequency),
623            max_frequency: Some(value.max_frequency),
624            threshold_db: Some(value.threshold_db),
625            threshold_type: Some(value.threshold_type),
626            ratio: Some(value.ratio),
627            knee_width_db: value.knee_width_db,
628            attack: value.attack,
629            release: value.release,
630            output_gain_db: value.output_gain_db,
631            input_gain_db: value.input_gain_db,
632            level_type: value.level_type,
633            lookahead: value.lookahead,
634            linked_channels: value.linked_channels,
635            ..Default::default()
636        }
637    }
638}
639
640#[derive(Debug, Clone, Copy, PartialEq, Eq)]
641pub struct PlugState {
642    pub plugged: bool,
643    pub plug_state_time: zx_types::zx_time_t,
644}
645
646impl TryFrom<fhaudio_sigproc::PlugState> for PlugState {
647    type Error = String;
648
649    fn try_from(value: fhaudio_sigproc::PlugState) -> Result<Self, Self::Error> {
650        let plugged = value.plugged.ok_or_else(|| "missing 'plugged'".to_string())?;
651        let plug_state_time =
652            value.plug_state_time.ok_or_else(|| "missing 'plug_state_time'".to_string())?;
653        Ok(Self { plugged, plug_state_time })
654    }
655}
656
657impl From<PlugState> for fhaudio_sigproc::PlugState {
658    fn from(value: PlugState) -> Self {
659        Self {
660            plugged: Some(value.plugged),
661            plug_state_time: Some(value.plug_state_time),
662            ..Default::default()
663        }
664    }
665}
666
667#[derive(Debug, Clone, PartialEq)]
668pub struct DaiInterconnectElementState {
669    pub plug_state: PlugState,
670    pub external_delay_ns: Option<zx_types::zx_duration_t>,
671}
672
673impl TryFrom<fhaudio_sigproc::DaiInterconnectElementState> for DaiInterconnectElementState {
674    type Error = String;
675
676    fn try_from(value: fhaudio_sigproc::DaiInterconnectElementState) -> Result<Self, Self::Error> {
677        let plug_state: PlugState =
678            value.plug_state.ok_or_else(|| "missing 'plug_state'".to_string())?.try_into()?;
679        Ok(Self { plug_state, external_delay_ns: value.external_delay })
680    }
681}
682
683impl From<DaiInterconnectElementState> for fhaudio_sigproc::DaiInterconnectElementState {
684    fn from(value: DaiInterconnectElementState) -> Self {
685        Self {
686            plug_state: Some(value.plug_state.into()),
687            external_delay: value.external_delay_ns,
688            ..Default::default()
689        }
690    }
691}