1#![allow(dead_code)]
24
25use alloc::{string::String, vec::Vec};
26
27use crate::error::KernelError;
28
29pub const USB_CLASS_AUDIO: u8 = 0x01;
35
36pub const USB_SUBCLASS_AUDIO_CONTROL: u8 = 0x01;
38pub const USB_SUBCLASS_AUDIO_STREAMING: u8 = 0x02;
39pub const USB_SUBCLASS_MIDI_STREAMING: u8 = 0x03;
40
41pub const UAC_PROTOCOL_NONE: u8 = 0x00;
43pub const UAC_PROTOCOL_IP_VERSION_02_00: u8 = 0x20;
44
45pub const CS_INTERFACE: u8 = 0x24;
47pub const CS_ENDPOINT: u8 = 0x25;
48
49pub const UAC_AC_HEADER: u8 = 0x01;
53pub const UAC_INPUT_TERMINAL: u8 = 0x02;
55pub const UAC_OUTPUT_TERMINAL: u8 = 0x03;
57pub const UAC_MIXER_UNIT: u8 = 0x04;
59pub const UAC_SELECTOR_UNIT: u8 = 0x05;
61pub const UAC_FEATURE_UNIT: u8 = 0x06;
63pub const UAC_PROCESSING_UNIT: u8 = 0x07;
65pub const UAC_EXTENSION_UNIT: u8 = 0x08;
67pub const UAC2_CLOCK_SOURCE: u8 = 0x0A;
69pub const UAC2_CLOCK_SELECTOR: u8 = 0x0B;
71pub const UAC2_CLOCK_MULTIPLIER: u8 = 0x0C;
73
74pub const UAC_AS_GENERAL: u8 = 0x01;
78pub const UAC_AS_FORMAT_TYPE: u8 = 0x02;
80
81pub const UAC_TERMINAL_USB_STREAMING: u16 = 0x0101;
85pub const UAC_TERMINAL_SPEAKER: u16 = 0x0301;
87pub const UAC_TERMINAL_HEADPHONES: u16 = 0x0302;
89pub const UAC_TERMINAL_DESKTOP_SPEAKER: u16 = 0x0304;
91pub const UAC_TERMINAL_MICROPHONE: u16 = 0x0201;
93pub const UAC_TERMINAL_DESKTOP_MIC: u16 = 0x0202;
95pub const UAC_TERMINAL_HEADSET_MIC: u16 = 0x0204;
97pub const UAC_TERMINAL_HDMI: u16 = 0x0605;
99pub const UAC_TERMINAL_SPDIF: u16 = 0x0605;
101
102pub const UAC_FORMAT_PCM: u16 = 0x0001;
106pub const UAC_FORMAT_PCM8: u16 = 0x0002;
108pub const UAC_FORMAT_IEEE_FLOAT: u16 = 0x0003;
110pub const UAC_FORMAT_ALAW: u16 = 0x0004;
112pub const UAC_FORMAT_MULAW: u16 = 0x0005;
114
115pub const UAC_SET_CUR: u8 = 0x01;
118pub const UAC_GET_CUR: u8 = 0x81;
119pub const UAC_SET_MIN: u8 = 0x02;
120pub const UAC_GET_MIN: u8 = 0x82;
121pub const UAC_SET_MAX: u8 = 0x03;
122pub const UAC_GET_MAX: u8 = 0x83;
123pub const UAC_SET_RES: u8 = 0x04;
124pub const UAC_GET_RES: u8 = 0x84;
125
126pub const UAC_FU_MUTE_CONTROL: u8 = 0x01;
129pub const UAC_FU_VOLUME_CONTROL: u8 = 0x02;
130pub const UAC_FU_BASS_CONTROL: u8 = 0x03;
131pub const UAC_FU_TREBLE_CONTROL: u8 = 0x04;
132pub const UAC_FU_AUTOMATIC_GAIN: u8 = 0x07;
133
134pub const UAC_EP_SYNC_NONE: u8 = 0x00;
138pub const UAC_EP_SYNC_ASYNC: u8 = 0x04;
140pub const UAC_EP_SYNC_ADAPTIVE: u8 = 0x08;
142pub const UAC_EP_SYNC_SYNC: u8 = 0x0C;
144
145const MAX_CHANNELS: usize = 8;
147
148const MAX_SAMPLE_RATES: usize = 16;
150
151const MAX_UNITS: usize = 32;
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub enum UacVersion {
161 Uac10,
163 Uac20,
165}
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub enum IsoSyncType {
170 None,
172 Asynchronous,
174 Adaptive,
176 Synchronous,
178}
179
180impl IsoSyncType {
181 pub(crate) fn from_attributes(attr: u8) -> Self {
183 match attr & 0x0C {
184 UAC_EP_SYNC_ASYNC => IsoSyncType::Asynchronous,
185 UAC_EP_SYNC_ADAPTIVE => IsoSyncType::Adaptive,
186 UAC_EP_SYNC_SYNC => IsoSyncType::Synchronous,
187 _ => IsoSyncType::None,
188 }
189 }
190
191 pub(crate) fn to_attributes(self) -> u8 {
193 match self {
194 IsoSyncType::None => UAC_EP_SYNC_NONE,
195 IsoSyncType::Asynchronous => UAC_EP_SYNC_ASYNC,
196 IsoSyncType::Adaptive => UAC_EP_SYNC_ADAPTIVE,
197 IsoSyncType::Synchronous => UAC_EP_SYNC_SYNC,
198 }
199 }
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub enum TerminalDirection {
205 Input,
207 Output,
209}
210
211#[derive(Debug, Clone)]
213pub struct InputTerminal {
214 pub terminal_id: u8,
216 pub terminal_type: u16,
218 pub assoc_terminal: u8,
220 pub nr_channels: u8,
222 pub channel_config: u16,
224}
225
226#[derive(Debug, Clone)]
228pub struct OutputTerminal {
229 pub terminal_id: u8,
231 pub terminal_type: u16,
233 pub assoc_terminal: u8,
235 pub source_id: u8,
237}
238
239#[derive(Debug, Clone)]
241pub struct FeatureUnit {
242 pub unit_id: u8,
244 pub source_id: u8,
246 pub controls: Vec<u32>,
249}
250
251impl FeatureUnit {
252 pub(crate) fn has_mute(&self, channel: usize) -> bool {
254 self.controls
255 .get(channel)
256 .is_some_and(|c| c & (1 << 0) != 0)
257 }
258
259 pub(crate) fn has_volume(&self, channel: usize) -> bool {
261 self.controls
262 .get(channel)
263 .is_some_and(|c| c & (1 << 1) != 0)
264 }
265}
266
267#[derive(Debug, Clone)]
269pub struct MixerUnit {
270 pub unit_id: u8,
272 pub source_ids: Vec<u8>,
274 pub nr_channels: u8,
276 pub channel_config: u16,
278}
279
280#[derive(Debug, Clone, Copy)]
282pub struct ClockSource {
283 pub clock_id: u8,
285 pub attributes: u8,
287 pub assoc_terminal: u8,
289}
290
291impl ClockSource {
292 pub(crate) fn is_external(&self) -> bool {
294 self.attributes & 0x01 != 0
295 }
296
297 pub(crate) fn is_sof_synced(&self) -> bool {
299 self.attributes & 0x02 != 0
300 }
301}
302
303#[derive(Debug, Clone)]
305pub enum AudioUnit {
306 InputTerminal(InputTerminal),
308 OutputTerminal(OutputTerminal),
310 FeatureUnit(FeatureUnit),
312 MixerUnit(MixerUnit),
314 ClockSource(ClockSource),
316}
317
318impl AudioUnit {
319 pub(crate) fn id(&self) -> u8 {
321 match self {
322 AudioUnit::InputTerminal(t) => t.terminal_id,
323 AudioUnit::OutputTerminal(t) => t.terminal_id,
324 AudioUnit::FeatureUnit(u) => u.unit_id,
325 AudioUnit::MixerUnit(u) => u.unit_id,
326 AudioUnit::ClockSource(c) => c.clock_id,
327 }
328 }
329}
330
331#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337pub struct SampleRateRange {
338 pub min: u32,
340 pub max: u32,
342}
343
344impl SampleRateRange {
345 pub(crate) fn discrete(rate: u32) -> Self {
347 Self {
348 min: rate,
349 max: rate,
350 }
351 }
352
353 pub(crate) fn range(min: u32, max: u32) -> Self {
355 Self { min, max }
356 }
357
358 pub(crate) fn contains(&self, rate: u32) -> bool {
360 rate >= self.min && rate <= self.max
361 }
362
363 pub(crate) fn is_discrete(&self) -> bool {
365 self.min == self.max
366 }
367}
368
369#[derive(Debug, Clone)]
371pub struct AudioFormatDescriptor {
372 pub format_tag: u16,
374 pub nr_channels: u8,
376 pub subframe_size: u8,
378 pub bit_resolution: u8,
380 pub sample_rates: Vec<SampleRateRange>,
382}
383
384impl AudioFormatDescriptor {
385 pub(crate) fn supports_rate(&self, rate: u32) -> bool {
387 if self.sample_rates.is_empty() {
389 return true;
390 }
391 self.sample_rates.iter().any(|r| r.contains(rate))
392 }
393
394 pub(crate) fn is_pcm(&self) -> bool {
396 self.format_tag == UAC_FORMAT_PCM || self.format_tag == UAC_FORMAT_PCM8
397 }
398
399 pub(crate) fn frame_size(&self) -> u16 {
401 self.nr_channels as u16 * self.subframe_size as u16
402 }
403}
404
405#[derive(Debug, Clone)]
411pub struct AudioStreamingInterface {
412 pub interface_num: u8,
414 pub alternate_setting: u8,
416 pub terminal_link: u8,
418 pub format: AudioFormatDescriptor,
420 pub endpoint_address: u8,
422 pub max_packet_size: u16,
424 pub sync_type: IsoSyncType,
426 pub sync_endpoint: u8,
428}
429
430impl AudioStreamingInterface {
431 pub(crate) fn is_input(&self) -> bool {
433 self.endpoint_address & 0x80 != 0
434 }
435
436 pub(crate) fn is_output(&self) -> bool {
438 self.endpoint_address & 0x80 == 0
439 }
440
441 pub(crate) fn is_zero_bandwidth(&self) -> bool {
443 self.alternate_setting == 0
444 }
445
446 pub(crate) fn bytes_per_usb_frame(&self, sample_rate: u32) -> u32 {
449 let frame_size = self.format.frame_size() as u32;
451 sample_rate.saturating_mul(frame_size) / 1000
453 }
454}
455
456#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
473pub struct VolumeDb(pub i16);
474
475pub const VOLUME_SILENCE: VolumeDb = VolumeDb(i16::MIN);
477
478pub const VOLUME_UNITY: VolumeDb = VolumeDb(0);
480
481pub const VOLUME_MAX: VolumeDb = VolumeDb(i16::MAX);
483
484impl VolumeDb {
485 pub(crate) fn from_db(db: i8) -> Self {
487 VolumeDb((db as i16) << 8)
488 }
489
490 pub(crate) fn integer_db(&self) -> i8 {
492 (self.0 >> 8) as i8
493 }
494
495 pub(crate) fn fraction(&self) -> u8 {
497 self.0 as u8
498 }
499
500 pub(crate) fn raw(&self) -> i16 {
502 self.0
503 }
504
505 #[allow(clippy::wrong_self_convention)]
514 pub(crate) fn to_linear_u16(&self) -> u16 {
515 let db_int = self.integer_db();
516
517 if db_int >= 0 {
518 return 65535;
520 }
521
522 if db_int <= -96 {
523 return 0;
525 }
526
527 let abs_db = (-db_int) as u32;
533 let steps_6db = abs_db / 6;
534 let remainder = abs_db % 6;
535
536 let mut gain: u32 = 65535;
538 let mut i = 0u32;
539 while i < steps_6db && i < 16 {
540 gain /= 2;
541 i += 1;
542 }
543
544 if remainder > 0 {
547 gain = gain.saturating_mul(6u32.saturating_sub(remainder)) / 6;
548 }
549
550 if gain > 65535 {
551 65535
552 } else {
553 gain as u16
554 }
555 }
556
557 pub(crate) fn from_linear_u16(linear: u16) -> Self {
561 if linear == 0 {
562 return VOLUME_SILENCE;
563 }
564 if linear == u16::MAX {
565 return VOLUME_UNITY;
566 }
567
568 let mut val = linear as u32;
571 let mut db: i32 = 0;
572 while val < 65535 && db > -96 {
573 val = val.saturating_mul(2);
574 db -= 6;
575 }
576
577 VolumeDb::from_db(db as i8)
578 }
579}
580
581#[derive(Debug, Clone)]
587pub struct UsbAudioDevice {
588 pub device_address: u8,
590 pub version: UacVersion,
592 pub control_interface: u8,
594 pub units: Vec<AudioUnit>,
596 pub streaming_interfaces: Vec<AudioStreamingInterface>,
598 pub active_stream: Option<(u8, u8)>,
600 pub current_sample_rate: u32,
602 pub name: String,
604}
605
606impl UsbAudioDevice {
607 pub fn new(device_address: u8, version: UacVersion) -> Self {
609 Self {
610 device_address,
611 version,
612 control_interface: 0,
613 units: Vec::new(),
614 streaming_interfaces: Vec::new(),
615 active_stream: None,
616 current_sample_rate: 0,
617 name: String::new(),
618 }
619 }
620
621 pub(crate) fn find_input_terminal(&self, id: u8) -> Option<&InputTerminal> {
623 self.units.iter().find_map(|u| match u {
624 AudioUnit::InputTerminal(t) if t.terminal_id == id => Some(t),
625 _ => None,
626 })
627 }
628
629 pub(crate) fn find_output_terminal(&self, id: u8) -> Option<&OutputTerminal> {
631 self.units.iter().find_map(|u| match u {
632 AudioUnit::OutputTerminal(t) if t.terminal_id == id => Some(t),
633 _ => None,
634 })
635 }
636
637 pub(crate) fn find_feature_unit(&self, id: u8) -> Option<&FeatureUnit> {
639 self.units.iter().find_map(|u| match u {
640 AudioUnit::FeatureUnit(f) if f.unit_id == id => Some(f),
641 _ => None,
642 })
643 }
644
645 pub(crate) fn feature_units(&self) -> Vec<&FeatureUnit> {
647 self.units
648 .iter()
649 .filter_map(|u| match u {
650 AudioUnit::FeatureUnit(f) => Some(f),
651 _ => None,
652 })
653 .collect()
654 }
655
656 pub(crate) fn playback_interfaces(&self) -> Vec<&AudioStreamingInterface> {
658 self.streaming_interfaces
659 .iter()
660 .filter(|s| s.is_output() && !s.is_zero_bandwidth())
661 .collect()
662 }
663
664 pub(crate) fn capture_interfaces(&self) -> Vec<&AudioStreamingInterface> {
666 self.streaming_interfaces
667 .iter()
668 .filter(|s| s.is_input() && !s.is_zero_bandwidth())
669 .collect()
670 }
671
672 pub(crate) fn find_compatible_interface(
675 &self,
676 sample_rate: u32,
677 channels: u8,
678 output: bool,
679 ) -> Option<&AudioStreamingInterface> {
680 self.streaming_interfaces.iter().find(|s| {
681 let direction_ok = if output { s.is_output() } else { s.is_input() };
682 direction_ok
683 && !s.is_zero_bandwidth()
684 && s.format.nr_channels == channels
685 && s.format.supports_rate(sample_rate)
686 })
687 }
688
689 pub(crate) fn unit_count(&self) -> usize {
691 self.units.len()
692 }
693}
694
695pub(crate) fn parse_ac_header(data: &[u8]) -> Result<(UacVersion, u16), KernelError> {
703 if data.len() < 8 {
707 return Err(KernelError::InvalidArgument {
708 name: "ac_header",
709 value: "too short",
710 });
711 }
712
713 if data[1] != CS_INTERFACE || data[2] != UAC_AC_HEADER {
714 return Err(KernelError::InvalidArgument {
715 name: "ac_header",
716 value: "wrong descriptor type",
717 });
718 }
719
720 let bcd_adc = u16::from_le_bytes([data[3], data[4]]);
721 let version = if bcd_adc >= 0x0200 {
722 UacVersion::Uac20
723 } else {
724 UacVersion::Uac10
725 };
726
727 let total_length = u16::from_le_bytes([data[5], data[6]]);
728
729 Ok((version, total_length))
730}
731
732pub(crate) fn parse_input_terminal(data: &[u8]) -> Result<InputTerminal, KernelError> {
734 if data.len() < 12 {
736 return Err(KernelError::InvalidArgument {
737 name: "input_terminal",
738 value: "too short",
739 });
740 }
741
742 if data[1] != CS_INTERFACE || data[2] != UAC_INPUT_TERMINAL {
743 return Err(KernelError::InvalidArgument {
744 name: "input_terminal",
745 value: "wrong subtype",
746 });
747 }
748
749 Ok(InputTerminal {
750 terminal_id: data[3],
751 terminal_type: u16::from_le_bytes([data[4], data[5]]),
752 assoc_terminal: data[6],
753 nr_channels: data[7],
754 channel_config: u16::from_le_bytes([data[8], data[9]]),
755 })
756}
757
758pub(crate) fn parse_output_terminal(data: &[u8]) -> Result<OutputTerminal, KernelError> {
760 if data.len() < 9 {
762 return Err(KernelError::InvalidArgument {
763 name: "output_terminal",
764 value: "too short",
765 });
766 }
767
768 if data[1] != CS_INTERFACE || data[2] != UAC_OUTPUT_TERMINAL {
769 return Err(KernelError::InvalidArgument {
770 name: "output_terminal",
771 value: "wrong subtype",
772 });
773 }
774
775 Ok(OutputTerminal {
776 terminal_id: data[3],
777 terminal_type: u16::from_le_bytes([data[4], data[5]]),
778 assoc_terminal: data[6],
779 source_id: data[7],
780 })
781}
782
783pub(crate) fn parse_feature_unit(data: &[u8]) -> Result<FeatureUnit, KernelError> {
785 if data.len() < 7 {
788 return Err(KernelError::InvalidArgument {
789 name: "feature_unit",
790 value: "too short",
791 });
792 }
793
794 if data[1] != CS_INTERFACE || data[2] != UAC_FEATURE_UNIT {
795 return Err(KernelError::InvalidArgument {
796 name: "feature_unit",
797 value: "wrong subtype",
798 });
799 }
800
801 let unit_id = data[3];
802 let source_id = data[4];
803 let control_size = data[5] as usize;
804
805 if control_size == 0 {
806 return Ok(FeatureUnit {
807 unit_id,
808 source_id,
809 controls: Vec::new(),
810 });
811 }
812
813 let controls_start = 6;
815 let bma_len = data[0] as usize - controls_start - 1; let num_controls = if control_size > 0 {
817 bma_len / control_size
818 } else {
819 0
820 };
821
822 let mut controls = Vec::new();
823 for i in 0..num_controls {
824 let offset = controls_start + i * control_size;
825 let mut ctrl: u32 = 0;
826 for b in 0..control_size.min(4) {
827 if offset + b < data.len() {
828 ctrl |= (data[offset + b] as u32) << (b * 8);
829 }
830 }
831 controls.push(ctrl);
832 }
833
834 Ok(FeatureUnit {
835 unit_id,
836 source_id,
837 controls,
838 })
839}
840
841pub(crate) fn parse_mixer_unit(data: &[u8]) -> Result<MixerUnit, KernelError> {
843 if data.len() < 5 {
846 return Err(KernelError::InvalidArgument {
847 name: "mixer_unit",
848 value: "too short",
849 });
850 }
851
852 if data[1] != CS_INTERFACE || data[2] != UAC_MIXER_UNIT {
853 return Err(KernelError::InvalidArgument {
854 name: "mixer_unit",
855 value: "wrong subtype",
856 });
857 }
858
859 let unit_id = data[3];
860 let nr_in_pins = data[4] as usize;
861
862 let mut source_ids = Vec::new();
863 for i in 0..nr_in_pins {
864 let idx = 5 + i;
865 if idx < data.len() {
866 source_ids.push(data[idx]);
867 }
868 }
869
870 let chan_offset = 5 + nr_in_pins;
872 let nr_channels = if chan_offset < data.len() {
873 data[chan_offset]
874 } else {
875 0
876 };
877 let channel_config = if chan_offset + 2 < data.len() {
878 u16::from_le_bytes([data[chan_offset + 1], data[chan_offset + 2]])
879 } else {
880 0
881 };
882
883 Ok(MixerUnit {
884 unit_id,
885 source_ids,
886 nr_channels,
887 channel_config,
888 })
889}
890
891pub(crate) fn parse_format_type_i(data: &[u8]) -> Result<AudioFormatDescriptor, KernelError> {
893 if data.len() < 8 {
897 return Err(KernelError::InvalidArgument {
898 name: "format_type",
899 value: "too short",
900 });
901 }
902
903 if data[1] != CS_INTERFACE || data[2] != UAC_AS_FORMAT_TYPE {
904 return Err(KernelError::InvalidArgument {
905 name: "format_type",
906 value: "wrong subtype",
907 });
908 }
909
910 let nr_channels = data[4];
911 let subframe_size = data[5];
912 let bit_resolution = data[6];
913 let sam_freq_type = data[7];
914
915 let mut sample_rates = Vec::new();
916
917 if sam_freq_type == 0 {
918 if data.len() >= 14 {
920 let lower = read_u24_le(&data[8..11]);
921 let upper = read_u24_le(&data[11..14]);
922 sample_rates.push(SampleRateRange::range(lower, upper));
923 }
924 } else {
925 for i in 0..sam_freq_type as usize {
927 let offset = 8 + i * 3;
928 if offset + 3 <= data.len() {
929 let rate = read_u24_le(&data[offset..offset + 3]);
930 sample_rates.push(SampleRateRange::discrete(rate));
931 }
932 }
933 }
934
935 Ok(AudioFormatDescriptor {
936 format_tag: UAC_FORMAT_PCM, nr_channels,
938 subframe_size,
939 bit_resolution,
940 sample_rates,
941 })
942}
943
944fn read_u24_le(data: &[u8]) -> u32 {
946 data[0] as u32 | ((data[1] as u32) << 8) | ((data[2] as u32) << 16)
947}
948
949pub(crate) fn parse_clock_source(data: &[u8]) -> Result<ClockSource, KernelError> {
951 if data.len() < 7 {
954 return Err(KernelError::InvalidArgument {
955 name: "clock_source",
956 value: "too short",
957 });
958 }
959
960 if data[1] != CS_INTERFACE || data[2] != UAC2_CLOCK_SOURCE {
961 return Err(KernelError::InvalidArgument {
962 name: "clock_source",
963 value: "wrong subtype",
964 });
965 }
966
967 Ok(ClockSource {
968 clock_id: data[3],
969 attributes: data[4],
970 assoc_terminal: data[6],
971 })
972}
973
974pub(crate) fn build_set_sample_rate_request(endpoint: u8, sample_rate: u32) -> SampleRateRequest {
983 SampleRateRequest {
984 request_type: 0x22, request: UAC_SET_CUR,
986 value: 0x0100, index: endpoint as u16,
988 sample_rate,
989 }
990}
991
992pub(crate) fn build_get_sample_rate_request(endpoint: u8) -> SampleRateRequest {
994 SampleRateRequest {
995 request_type: 0xA2, request: UAC_GET_CUR,
997 value: 0x0100,
998 index: endpoint as u16,
999 sample_rate: 0,
1000 }
1001}
1002
1003#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1005pub struct SampleRateRequest {
1006 pub request_type: u8,
1008 pub request: u8,
1010 pub value: u16,
1012 pub index: u16,
1014 pub sample_rate: u32,
1016}
1017
1018impl SampleRateRequest {
1019 pub(crate) fn rate_bytes(&self) -> [u8; 3] {
1021 [
1022 (self.sample_rate & 0xFF) as u8,
1023 ((self.sample_rate >> 8) & 0xFF) as u8,
1024 ((self.sample_rate >> 16) & 0xFF) as u8,
1025 ]
1026 }
1027
1028 pub(crate) fn decode_rate(data: &[u8]) -> u32 {
1030 if data.len() >= 3 {
1031 read_u24_le(data)
1032 } else {
1033 0
1034 }
1035 }
1036}
1037
1038pub(crate) fn build_set_volume_request(
1044 unit_id: u8,
1045 channel: u8,
1046 interface: u16,
1047 volume: VolumeDb,
1048) -> VolumeControlRequest {
1049 VolumeControlRequest {
1050 request_type: 0x21, request: UAC_SET_CUR,
1052 value: (UAC_FU_VOLUME_CONTROL as u16) << 8 | channel as u16,
1053 index: (unit_id as u16) << 8 | interface,
1054 volume,
1055 }
1056}
1057
1058pub(crate) fn build_get_volume_request(
1060 unit_id: u8,
1061 channel: u8,
1062 interface: u16,
1063) -> VolumeControlRequest {
1064 VolumeControlRequest {
1065 request_type: 0xA1, request: UAC_GET_CUR,
1067 value: (UAC_FU_VOLUME_CONTROL as u16) << 8 | channel as u16,
1068 index: (unit_id as u16) << 8 | interface,
1069 volume: VolumeDb(0),
1070 }
1071}
1072
1073pub(crate) fn build_set_mute_request(
1075 unit_id: u8,
1076 channel: u8,
1077 interface: u16,
1078 muted: bool,
1079) -> MuteControlRequest {
1080 MuteControlRequest {
1081 request_type: 0x21,
1082 request: UAC_SET_CUR,
1083 value: (UAC_FU_MUTE_CONTROL as u16) << 8 | channel as u16,
1084 index: (unit_id as u16) << 8 | interface,
1085 muted,
1086 }
1087}
1088
1089#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1091pub struct VolumeControlRequest {
1092 pub request_type: u8,
1093 pub request: u8,
1094 pub value: u16,
1095 pub index: u16,
1096 pub volume: VolumeDb,
1097}
1098
1099impl VolumeControlRequest {
1100 pub(crate) fn volume_bytes(&self) -> [u8; 2] {
1102 self.volume.raw().to_le_bytes()
1103 }
1104
1105 pub(crate) fn decode_volume(data: &[u8]) -> VolumeDb {
1107 if data.len() >= 2 {
1108 VolumeDb(i16::from_le_bytes([data[0], data[1]]))
1109 } else {
1110 VOLUME_SILENCE
1111 }
1112 }
1113}
1114
1115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1117pub struct MuteControlRequest {
1118 pub request_type: u8,
1119 pub request: u8,
1120 pub value: u16,
1121 pub index: u16,
1122 pub muted: bool,
1123}
1124
1125pub(crate) fn enumerate_audio_device(
1135 device_address: u8,
1136 config_descriptor: &[u8],
1137) -> Result<UsbAudioDevice, KernelError> {
1138 if config_descriptor.len() < 9 {
1139 return Err(KernelError::InvalidArgument {
1140 name: "config_descriptor",
1141 value: "too short",
1142 });
1143 }
1144
1145 let mut device = UsbAudioDevice::new(device_address, UacVersion::Uac10);
1146 let mut offset = 0;
1147
1148 while offset + 2 <= config_descriptor.len() {
1150 let desc_len = config_descriptor[offset] as usize;
1151 if desc_len < 2 || offset + desc_len > config_descriptor.len() {
1152 break;
1153 }
1154
1155 let desc_type = config_descriptor[offset + 1];
1156 let desc_data = &config_descriptor[offset..offset + desc_len];
1157
1158 if desc_type == CS_INTERFACE && desc_len >= 3 {
1159 let subtype = desc_data[2];
1160 match subtype {
1161 UAC_AC_HEADER => {
1162 if let Ok((version, _total_len)) = parse_ac_header(desc_data) {
1163 device.version = version;
1164 }
1165 }
1166 UAC_INPUT_TERMINAL => {
1167 if let Ok(terminal) = parse_input_terminal(desc_data) {
1170 device.units.push(AudioUnit::InputTerminal(terminal));
1171 } else if let Ok(format) = parse_format_type_i(desc_data) {
1172 if let Some(last_stream) = device.streaming_interfaces.last_mut() {
1173 last_stream.format = format;
1174 }
1175 }
1176 }
1177 UAC_OUTPUT_TERMINAL => {
1178 if let Ok(terminal) = parse_output_terminal(desc_data) {
1179 device.units.push(AudioUnit::OutputTerminal(terminal));
1180 }
1181 }
1182 UAC_FEATURE_UNIT => {
1183 if let Ok(unit) = parse_feature_unit(desc_data) {
1184 device.units.push(AudioUnit::FeatureUnit(unit));
1185 }
1186 }
1187 UAC_MIXER_UNIT => {
1188 if let Ok(unit) = parse_mixer_unit(desc_data) {
1189 device.units.push(AudioUnit::MixerUnit(unit));
1190 }
1191 }
1192 UAC2_CLOCK_SOURCE => {
1193 if let Ok(clock) = parse_clock_source(desc_data) {
1194 device.units.push(AudioUnit::ClockSource(clock));
1195 }
1196 }
1197 _ => {} }
1199 }
1200
1201 offset += desc_len;
1202 }
1203
1204 Ok(device)
1205}
1206
1207pub const STANDARD_SAMPLE_RATES: &[u32] = &[
1213 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000,
1214];
1215
1216pub(crate) fn is_standard_sample_rate(rate: u32) -> bool {
1218 STANDARD_SAMPLE_RATES.contains(&rate)
1219}
1220
1221pub const HDMI_AUDIO_INFOFRAME_TYPE: u8 = 0x84;
1227
1228pub const HDMI_AUDIO_INFOFRAME_VERSION: u8 = 0x01;
1230
1231pub const HDMI_AUDIO_INFOFRAME_LENGTH: u8 = 0x0A;
1233
1234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1236#[repr(u8)]
1237pub enum HdmiAudioCoding {
1238 StreamHeader = 0,
1240 Pcm = 1,
1242 Ac3 = 2,
1244 Mpeg1 = 3,
1246 Mp3 = 4,
1248 Mpeg2 = 5,
1250 AacLc = 6,
1252 Dts = 7,
1254 Atrac = 8,
1256 OneBitAudio = 9,
1258 EnhancedAc3 = 10,
1260 DtsHd = 11,
1262 Mat = 12,
1264 Dst = 13,
1266 WmaPro = 14,
1268}
1269
1270#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1272pub enum HdmiChannelAllocation {
1273 Stereo = 0x00,
1275 Stereo21 = 0x01,
1277 Surround30 = 0x02,
1279 Surround31 = 0x03,
1281 Surround50 = 0x0A,
1283 Surround51 = 0x0B,
1285 Surround70 = 0x12,
1287 Surround71 = 0x13,
1289}
1290
1291impl HdmiChannelAllocation {
1292 pub(crate) fn channel_count(&self) -> u8 {
1294 match self {
1295 HdmiChannelAllocation::Stereo => 2,
1296 HdmiChannelAllocation::Stereo21 => 3,
1297 HdmiChannelAllocation::Surround30 => 3,
1298 HdmiChannelAllocation::Surround31 => 4,
1299 HdmiChannelAllocation::Surround50 => 5,
1300 HdmiChannelAllocation::Surround51 => 6,
1301 HdmiChannelAllocation::Surround70 => 7,
1302 HdmiChannelAllocation::Surround71 => 8,
1303 }
1304 }
1305
1306 pub(crate) fn code(&self) -> u8 {
1308 *self as u8
1309 }
1310}
1311
1312#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1314#[repr(u8)]
1315pub enum HdmiSampleRate {
1316 StreamHeader = 0,
1318 Rate32000 = 1,
1320 Rate44100 = 2,
1322 Rate48000 = 3,
1324 Rate88200 = 4,
1326 Rate96000 = 5,
1328 Rate176400 = 6,
1330 Rate192000 = 7,
1332}
1333
1334impl HdmiSampleRate {
1335 pub(crate) fn from_hz(hz: u32) -> Self {
1337 match hz {
1338 32000 => HdmiSampleRate::Rate32000,
1339 44100 => HdmiSampleRate::Rate44100,
1340 48000 => HdmiSampleRate::Rate48000,
1341 88200 => HdmiSampleRate::Rate88200,
1342 96000 => HdmiSampleRate::Rate96000,
1343 176400 => HdmiSampleRate::Rate176400,
1344 192000 => HdmiSampleRate::Rate192000,
1345 _ => HdmiSampleRate::StreamHeader,
1346 }
1347 }
1348
1349 #[allow(clippy::wrong_self_convention)]
1351 pub(crate) fn to_hz(&self) -> u32 {
1352 match self {
1353 HdmiSampleRate::StreamHeader => 0,
1354 HdmiSampleRate::Rate32000 => 32000,
1355 HdmiSampleRate::Rate44100 => 44100,
1356 HdmiSampleRate::Rate48000 => 48000,
1357 HdmiSampleRate::Rate88200 => 88200,
1358 HdmiSampleRate::Rate96000 => 96000,
1359 HdmiSampleRate::Rate176400 => 176400,
1360 HdmiSampleRate::Rate192000 => 192000,
1361 }
1362 }
1363}
1364
1365#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1367#[repr(u8)]
1368pub enum HdmiSampleSize {
1369 StreamHeader = 0,
1371 Bits16 = 1,
1373 Bits20 = 2,
1375 Bits24 = 3,
1377}
1378
1379impl HdmiSampleSize {
1380 pub(crate) fn from_bits(bits: u8) -> Self {
1382 match bits {
1383 16 => HdmiSampleSize::Bits16,
1384 20 => HdmiSampleSize::Bits20,
1385 24 => HdmiSampleSize::Bits24,
1386 _ => HdmiSampleSize::StreamHeader,
1387 }
1388 }
1389}
1390
1391#[derive(Debug, Clone, PartialEq, Eq)]
1400pub struct HdmiAudioInfoframe {
1401 pub coding_type: HdmiAudioCoding,
1403 pub channel_count: u8,
1405 pub sample_rate: HdmiSampleRate,
1407 pub sample_size: HdmiSampleSize,
1409 pub channel_allocation: HdmiChannelAllocation,
1411 pub level_shift: u8,
1413 pub downmix_inhibit: bool,
1415}
1416
1417impl HdmiAudioInfoframe {
1418 pub(crate) fn stereo_pcm(sample_rate: u32, bit_depth: u8) -> Self {
1420 Self {
1421 coding_type: HdmiAudioCoding::Pcm,
1422 channel_count: 2,
1423 sample_rate: HdmiSampleRate::from_hz(sample_rate),
1424 sample_size: HdmiSampleSize::from_bits(bit_depth),
1425 channel_allocation: HdmiChannelAllocation::Stereo,
1426 level_shift: 0,
1427 downmix_inhibit: false,
1428 }
1429 }
1430
1431 pub(crate) fn surround51_pcm(sample_rate: u32, bit_depth: u8) -> Self {
1433 Self {
1434 coding_type: HdmiAudioCoding::Pcm,
1435 channel_count: 6,
1436 sample_rate: HdmiSampleRate::from_hz(sample_rate),
1437 sample_size: HdmiSampleSize::from_bits(bit_depth),
1438 channel_allocation: HdmiChannelAllocation::Surround51,
1439 level_shift: 0,
1440 downmix_inhibit: false,
1441 }
1442 }
1443
1444 pub(crate) fn surround71_pcm(sample_rate: u32, bit_depth: u8) -> Self {
1446 Self {
1447 coding_type: HdmiAudioCoding::Pcm,
1448 channel_count: 8,
1449 sample_rate: HdmiSampleRate::from_hz(sample_rate),
1450 sample_size: HdmiSampleSize::from_bits(bit_depth),
1451 channel_allocation: HdmiChannelAllocation::Surround71,
1452 level_shift: 0,
1453 downmix_inhibit: false,
1454 }
1455 }
1456
1457 pub(crate) fn to_bytes(&self) -> [u8; 14] {
1466 let mut buf = [0u8; 14];
1467
1468 buf[0] = HDMI_AUDIO_INFOFRAME_TYPE;
1470 buf[1] = HDMI_AUDIO_INFOFRAME_VERSION;
1471 buf[2] = HDMI_AUDIO_INFOFRAME_LENGTH;
1472
1473 let cc = if self.channel_count > 0 {
1475 self.channel_count - 1
1476 } else {
1477 0
1478 };
1479 buf[4] = ((self.coding_type as u8) << 4) | (cc & 0x07);
1480
1481 buf[5] = ((self.sample_rate as u8) << 2) | (self.sample_size as u8);
1483
1484 buf[6] = 0x00;
1486
1487 buf[7] = self.channel_allocation.code();
1489
1490 buf[8] = (self.level_shift & 0x0F) << 3;
1492 if self.downmix_inhibit {
1493 buf[8] |= 0x80;
1494 }
1495
1496 let mut sum: u8 = 0;
1501 for (i, &byte) in buf.iter().enumerate().take(14) {
1502 if i != 3 {
1503 sum = sum.wrapping_add(byte);
1505 }
1506 }
1507 buf[3] = 0u8.wrapping_sub(sum);
1508
1509 buf
1510 }
1511
1512 pub(crate) fn verify_checksum(data: &[u8]) -> bool {
1514 if data.len() < 14 {
1515 return false;
1516 }
1517 let sum: u8 = data[..14].iter().fold(0u8, |acc, &b| acc.wrapping_add(b));
1518 sum == 0
1519 }
1520
1521 pub(crate) fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
1523 if data.len() < 14 {
1524 return Err(KernelError::InvalidArgument {
1525 name: "hdmi_infoframe",
1526 value: "too short",
1527 });
1528 }
1529
1530 if data[0] != HDMI_AUDIO_INFOFRAME_TYPE {
1531 return Err(KernelError::InvalidArgument {
1532 name: "hdmi_infoframe",
1533 value: "wrong type code",
1534 });
1535 }
1536
1537 if !Self::verify_checksum(data) {
1538 return Err(KernelError::InvalidArgument {
1539 name: "hdmi_infoframe",
1540 value: "bad checksum",
1541 });
1542 }
1543
1544 let coding_raw = (data[4] >> 4) & 0x0F;
1545 let coding_type = match coding_raw {
1546 0 => HdmiAudioCoding::StreamHeader,
1547 1 => HdmiAudioCoding::Pcm,
1548 2 => HdmiAudioCoding::Ac3,
1549 3 => HdmiAudioCoding::Mpeg1,
1550 4 => HdmiAudioCoding::Mp3,
1551 5 => HdmiAudioCoding::Mpeg2,
1552 6 => HdmiAudioCoding::AacLc,
1553 7 => HdmiAudioCoding::Dts,
1554 8 => HdmiAudioCoding::Atrac,
1555 9 => HdmiAudioCoding::OneBitAudio,
1556 10 => HdmiAudioCoding::EnhancedAc3,
1557 11 => HdmiAudioCoding::DtsHd,
1558 12 => HdmiAudioCoding::Mat,
1559 13 => HdmiAudioCoding::Dst,
1560 14 => HdmiAudioCoding::WmaPro,
1561 _ => HdmiAudioCoding::StreamHeader,
1562 };
1563
1564 let channel_count = (data[4] & 0x07) + 1;
1565
1566 let sr_raw = (data[5] >> 2) & 0x07;
1567 let sample_rate = match sr_raw {
1568 1 => HdmiSampleRate::Rate32000,
1569 2 => HdmiSampleRate::Rate44100,
1570 3 => HdmiSampleRate::Rate48000,
1571 4 => HdmiSampleRate::Rate88200,
1572 5 => HdmiSampleRate::Rate96000,
1573 6 => HdmiSampleRate::Rate176400,
1574 7 => HdmiSampleRate::Rate192000,
1575 _ => HdmiSampleRate::StreamHeader,
1576 };
1577
1578 let ss_raw = data[5] & 0x03;
1579 let sample_size = match ss_raw {
1580 1 => HdmiSampleSize::Bits16,
1581 2 => HdmiSampleSize::Bits20,
1582 3 => HdmiSampleSize::Bits24,
1583 _ => HdmiSampleSize::StreamHeader,
1584 };
1585
1586 let ca_code = data[7];
1587 let channel_allocation = match ca_code {
1588 0x00 => HdmiChannelAllocation::Stereo,
1589 0x01 => HdmiChannelAllocation::Stereo21,
1590 0x02 => HdmiChannelAllocation::Surround30,
1591 0x03 => HdmiChannelAllocation::Surround31,
1592 0x0A => HdmiChannelAllocation::Surround50,
1593 0x0B => HdmiChannelAllocation::Surround51,
1594 0x12 => HdmiChannelAllocation::Surround70,
1595 0x13 => HdmiChannelAllocation::Surround71,
1596 _ => HdmiChannelAllocation::Stereo, };
1598
1599 let level_shift = (data[8] >> 3) & 0x0F;
1600 let downmix_inhibit = data[8] & 0x80 != 0;
1601
1602 Ok(Self {
1603 coding_type,
1604 channel_count,
1605 sample_rate,
1606 sample_size,
1607 channel_allocation,
1608 level_shift,
1609 downmix_inhibit,
1610 })
1611 }
1612}
1613
1614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1626pub struct AudioClockRegeneration {
1627 pub n: u32,
1629 pub cts: u32,
1631}
1632
1633impl AudioClockRegeneration {
1634 pub(crate) fn recommended_n(sample_rate: u32) -> u32 {
1639 match sample_rate {
1640 32000 => 4096,
1641 44100 => 6272,
1642 48000 => 6144,
1643 88200 => 12544,
1644 96000 => 12288,
1645 176400 => 25088,
1646 192000 => 24576,
1647 _ => {
1648 sample_rate.saturating_mul(128) / 1000
1651 }
1652 }
1653 }
1654
1655 pub(crate) fn calculate_cts(n: u32, sample_rate: u32, tmds_clock_khz: u32) -> u32 {
1661 if sample_rate == 0 {
1662 return 0;
1663 }
1664
1665 let numerator = (n as u64)
1670 .checked_mul(tmds_clock_khz as u64)
1671 .and_then(|v| v.checked_mul(1000));
1672 let denominator = 128u64.checked_mul(sample_rate as u64);
1673
1674 match (numerator, denominator) {
1675 (Some(num), Some(den)) if den > 0 => (num / den) as u32,
1676 _ => 0,
1677 }
1678 }
1679
1680 pub fn new(sample_rate: u32, tmds_clock_khz: u32) -> Self {
1686 let n = Self::recommended_n(sample_rate);
1687 let cts = Self::calculate_cts(n, sample_rate, tmds_clock_khz);
1688 Self { n, cts }
1689 }
1690
1691 pub(crate) fn for_1080p60(sample_rate: u32) -> Self {
1693 Self::new(sample_rate, 148500)
1694 }
1695
1696 pub(crate) fn for_4k60(sample_rate: u32) -> Self {
1698 Self::new(sample_rate, 594000)
1699 }
1700
1701 pub(crate) fn for_720p60(sample_rate: u32) -> Self {
1703 Self::new(sample_rate, 74250)
1704 }
1705}
1706
1707#[derive(Debug, Clone)]
1717pub struct HdmiEld {
1718 pub eld_ver: u8,
1720 pub baseline_len: u8,
1722 pub cea_edid_ver: u8,
1724 pub monitor_name: String,
1726 pub sad_count: u8,
1728 pub sads: Vec<ShortAudioDescriptor>,
1730 pub conn_type: u8,
1732 pub supports_arc: bool,
1734 pub supports_ai: bool,
1736 pub port_id: u64,
1738 pub manufacturer_id: u16,
1740 pub product_code: u16,
1742}
1743
1744#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1748pub struct ShortAudioDescriptor {
1749 pub format_code: u8,
1751 pub max_channels: u8,
1753 pub sample_rate_mask: u8,
1757 pub detail: u8,
1760}
1761
1762impl ShortAudioDescriptor {
1763 pub(crate) fn from_bytes(data: &[u8; 3]) -> Self {
1765 Self {
1766 format_code: (data[0] >> 3) & 0x0F,
1767 max_channels: (data[0] & 0x07) + 1,
1768 sample_rate_mask: data[1] & 0x7F,
1769 detail: data[2],
1770 }
1771 }
1772
1773 pub(crate) fn supports_rate(&self, rate: u32) -> bool {
1775 let bit = match rate {
1776 32000 => 0,
1777 44100 => 1,
1778 48000 => 2,
1779 88200 => 3,
1780 96000 => 4,
1781 176400 => 5,
1782 192000 => 6,
1783 _ => return false,
1784 };
1785 self.sample_rate_mask & (1 << bit) != 0
1786 }
1787
1788 pub(crate) fn supports_pcm_depth(&self, bits: u8) -> bool {
1790 if self.format_code != 1 {
1791 return false;
1793 }
1794 match bits {
1795 16 => self.detail & 0x01 != 0,
1796 20 => self.detail & 0x02 != 0,
1797 24 => self.detail & 0x04 != 0,
1798 _ => false,
1799 }
1800 }
1801
1802 pub(crate) fn is_pcm(&self) -> bool {
1804 self.format_code == 1
1805 }
1806
1807 #[allow(clippy::wrong_self_convention)]
1809 pub(crate) fn to_bytes(&self) -> [u8; 3] {
1810 let byte0 =
1811 ((self.format_code & 0x0F) << 3) | ((self.max_channels.saturating_sub(1)) & 0x07);
1812 [byte0, self.sample_rate_mask & 0x7F, self.detail]
1813 }
1814}
1815
1816impl HdmiEld {
1817 pub(crate) fn parse(data: &[u8]) -> Result<Self, KernelError> {
1822 if data.len() < 16 {
1823 return Err(KernelError::InvalidArgument {
1824 name: "eld",
1825 value: "too short",
1826 });
1827 }
1828
1829 let eld_ver = (data[0] >> 3) & 0x1F;
1830 let baseline_len = data[2];
1831 let cea_edid_ver = (data[4] >> 5) & 0x07;
1832
1833 let sad_count = (data[4] & 0x0F).min(15); let conn_type = (data[5] >> 2) & 0x03;
1835 let supports_arc = data[5] & 0x02 != 0;
1836 let supports_ai = data[5] & 0x01 != 0;
1837
1838 let mnl = data[6] as usize;
1841
1842 let manufacturer_id = u16::from_le_bytes([data[8], data[9]]);
1843 let product_code = u16::from_le_bytes([data[10], data[11]]);
1844
1845 let port_id = if data.len() >= 20 {
1846 u64::from_le_bytes([
1847 data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
1848 ])
1849 } else {
1850 0
1851 };
1852
1853 let name_start = 20;
1855 let name_end = (name_start + mnl).min(data.len());
1856 let monitor_name = if name_start < data.len() {
1857 let name_bytes = &data[name_start..name_end];
1858 String::from_utf8_lossy(name_bytes).into_owned()
1859 } else {
1860 String::new()
1861 };
1862
1863 let sad_start = name_start + mnl;
1865 let mut sads = Vec::new();
1866 for i in 0..sad_count as usize {
1867 let offset = sad_start + i * 3;
1868 if offset + 3 <= data.len() {
1869 let sad_bytes: [u8; 3] = [data[offset], data[offset + 1], data[offset + 2]];
1870 sads.push(ShortAudioDescriptor::from_bytes(&sad_bytes));
1871 }
1872 }
1873
1874 Ok(Self {
1875 eld_ver,
1876 baseline_len,
1877 cea_edid_ver,
1878 monitor_name,
1879 sad_count,
1880 sads,
1881 conn_type,
1882 supports_arc,
1883 supports_ai,
1884 port_id,
1885 manufacturer_id,
1886 product_code,
1887 })
1888 }
1889
1890 pub(crate) fn supports_format(&self, format_code: u8, rate: u32, channels: u8) -> bool {
1892 self.sads.iter().any(|sad| {
1893 sad.format_code == format_code
1894 && sad.max_channels >= channels
1895 && sad.supports_rate(rate)
1896 })
1897 }
1898
1899 pub(crate) fn supports_stereo_pcm(&self, rate: u32, bit_depth: u8) -> bool {
1901 self.sads.iter().any(|sad| {
1902 sad.is_pcm()
1903 && sad.max_channels >= 2
1904 && sad.supports_rate(rate)
1905 && sad.supports_pcm_depth(bit_depth)
1906 })
1907 }
1908
1909 pub(crate) fn max_pcm_channels(&self) -> u8 {
1911 self.sads
1912 .iter()
1913 .filter(|sad| sad.is_pcm())
1914 .map(|sad| sad.max_channels)
1915 .max()
1916 .unwrap_or(0)
1917 }
1918
1919 pub(crate) fn supported_pcm_rates(&self) -> Vec<u32> {
1921 let mut rates = Vec::new();
1922 let rate_table: &[(u32, u8)] = &[
1923 (32000, 0),
1924 (44100, 1),
1925 (48000, 2),
1926 (88200, 3),
1927 (96000, 4),
1928 (176400, 5),
1929 (192000, 6),
1930 ];
1931
1932 for sad in &self.sads {
1933 if sad.is_pcm() {
1934 for &(rate, bit) in rate_table {
1935 if sad.sample_rate_mask & (1 << bit) != 0 && !rates.contains(&rate) {
1936 rates.push(rate);
1937 }
1938 }
1939 }
1940 }
1941
1942 rates
1943 }
1944}
1945
1946#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1952pub enum HdaWidgetType {
1953 AudioOutput,
1955 PinComplex,
1957}
1958
1959#[derive(Debug, Clone)]
1961pub struct HdmiAudioOutput {
1962 pub codec_address: u8,
1964 pub converter_nid: u16,
1966 pub pin_nid: u16,
1968 pub eld: Option<HdmiEld>,
1970 pub infoframe: Option<HdmiAudioInfoframe>,
1972 pub acr: Option<AudioClockRegeneration>,
1974 pub enabled: bool,
1976}
1977
1978impl HdmiAudioOutput {
1979 pub fn new(codec_address: u8, converter_nid: u16, pin_nid: u16) -> Self {
1981 Self {
1982 codec_address,
1983 converter_nid,
1984 pin_nid,
1985 eld: None,
1986 infoframe: None,
1987 acr: None,
1988 enabled: false,
1989 }
1990 }
1991
1992 pub(crate) fn configure_stereo_pcm(
1994 &mut self,
1995 sample_rate: u32,
1996 bit_depth: u8,
1997 tmds_clock_khz: u32,
1998 ) -> Result<(), KernelError> {
1999 if let Some(ref eld) = self.eld {
2001 if !eld.supports_stereo_pcm(sample_rate, bit_depth) {
2002 return Err(KernelError::OperationNotSupported {
2003 operation: "sink does not support requested format",
2004 });
2005 }
2006 }
2007
2008 self.infoframe = Some(HdmiAudioInfoframe::stereo_pcm(sample_rate, bit_depth));
2010
2011 self.acr = Some(AudioClockRegeneration::new(sample_rate, tmds_clock_khz));
2013
2014 Ok(())
2015 }
2016
2017 pub(crate) fn enable(&mut self) {
2019 self.enabled = true;
2020 }
2021
2022 pub(crate) fn disable(&mut self) {
2024 self.enabled = false;
2025 }
2026
2027 pub(crate) fn has_sink(&self) -> bool {
2029 self.eld.is_some()
2030 }
2031}
2032
2033#[cfg(test)]
2038mod tests {
2039 #[allow(unused_imports)]
2040 use alloc::vec;
2041
2042 use super::*;
2043
2044 #[test]
2047 fn test_iso_sync_type_from_attributes() {
2048 assert_eq!(IsoSyncType::from_attributes(0x00), IsoSyncType::None);
2049 assert_eq!(
2050 IsoSyncType::from_attributes(0x04),
2051 IsoSyncType::Asynchronous
2052 );
2053 assert_eq!(IsoSyncType::from_attributes(0x08), IsoSyncType::Adaptive);
2054 assert_eq!(IsoSyncType::from_attributes(0x0C), IsoSyncType::Synchronous);
2055 assert_eq!(
2057 IsoSyncType::from_attributes(0xF4),
2058 IsoSyncType::Asynchronous
2059 );
2060 }
2061
2062 #[test]
2063 fn test_iso_sync_type_roundtrip() {
2064 for sync in [
2065 IsoSyncType::None,
2066 IsoSyncType::Asynchronous,
2067 IsoSyncType::Adaptive,
2068 IsoSyncType::Synchronous,
2069 ] {
2070 assert_eq!(IsoSyncType::from_attributes(sync.to_attributes()), sync);
2071 }
2072 }
2073
2074 #[test]
2077 fn test_volume_db_from_db() {
2078 let vol = VolumeDb::from_db(0);
2079 assert_eq!(vol.raw(), 0);
2080 assert_eq!(vol.integer_db(), 0);
2081 assert_eq!(vol.fraction(), 0);
2082
2083 let vol_pos = VolumeDb::from_db(10);
2084 assert_eq!(vol_pos.integer_db(), 10);
2085
2086 let vol_neg = VolumeDb::from_db(-20);
2087 assert_eq!(vol_neg.integer_db(), -20);
2088 }
2089
2090 #[test]
2091 fn test_volume_db_to_linear() {
2092 assert_eq!(VOLUME_UNITY.to_linear_u16(), 65535);
2094
2095 assert_eq!(VolumeDb::from_db(10).to_linear_u16(), 65535);
2097
2098 assert_eq!(VOLUME_SILENCE.to_linear_u16(), 0);
2100 assert_eq!(VolumeDb::from_db(-96).to_linear_u16(), 0);
2101
2102 let half = VolumeDb::from_db(-6).to_linear_u16();
2104 assert!(
2105 half > 30000 && half < 35000,
2106 "Expected ~32767, got {}",
2107 half
2108 );
2109 }
2110
2111 #[test]
2112 fn test_volume_db_from_linear() {
2113 assert_eq!(VolumeDb::from_linear_u16(0), VOLUME_SILENCE);
2114 assert_eq!(VolumeDb::from_linear_u16(65535), VOLUME_UNITY);
2115 }
2116
2117 #[test]
2120 fn test_sample_rate_range_discrete() {
2121 let rate = SampleRateRange::discrete(48000);
2122 assert!(rate.is_discrete());
2123 assert!(rate.contains(48000));
2124 assert!(!rate.contains(44100));
2125 }
2126
2127 #[test]
2128 fn test_sample_rate_range_continuous() {
2129 let range = SampleRateRange::range(8000, 96000);
2130 assert!(!range.is_discrete());
2131 assert!(range.contains(44100));
2132 assert!(range.contains(48000));
2133 assert!(range.contains(8000));
2134 assert!(range.contains(96000));
2135 assert!(!range.contains(192000));
2136 }
2137
2138 #[test]
2141 fn test_audio_format_supports_rate() {
2142 let format = AudioFormatDescriptor {
2143 format_tag: UAC_FORMAT_PCM,
2144 nr_channels: 2,
2145 subframe_size: 2,
2146 bit_resolution: 16,
2147 sample_rates: vec![
2148 SampleRateRange::discrete(44100),
2149 SampleRateRange::discrete(48000),
2150 ],
2151 };
2152 assert!(format.supports_rate(44100));
2153 assert!(format.supports_rate(48000));
2154 assert!(!format.supports_rate(96000));
2155 assert!(format.is_pcm());
2156 assert_eq!(format.frame_size(), 4); }
2158
2159 #[test]
2160 fn test_audio_format_empty_rates() {
2161 let format = AudioFormatDescriptor {
2162 format_tag: UAC_FORMAT_PCM,
2163 nr_channels: 1,
2164 subframe_size: 2,
2165 bit_resolution: 16,
2166 sample_rates: Vec::new(),
2167 };
2168 assert!(format.supports_rate(44100));
2170 assert!(format.supports_rate(192000));
2171 }
2172
2173 #[test]
2176 fn test_feature_unit_controls() {
2177 let fu = FeatureUnit {
2178 unit_id: 5,
2179 source_id: 1,
2180 controls: vec![0x03, 0x01, 0x01], };
2182 assert!(fu.has_mute(0));
2183 assert!(fu.has_volume(0));
2184 assert!(fu.has_mute(1));
2185 assert!(!fu.has_volume(1));
2186 assert!(!fu.has_mute(10)); }
2188
2189 #[test]
2192 fn test_parse_ac_header() {
2193 let data = [
2195 9, CS_INTERFACE, UAC_AC_HEADER, 0x00,
2199 0x01, 0x40,
2201 0x00, 0x01, 0x01, ];
2205 let (version, total_len) = parse_ac_header(&data).unwrap();
2206 assert_eq!(version, UacVersion::Uac10);
2207 assert_eq!(total_len, 64);
2208 }
2209
2210 #[test]
2211 fn test_parse_ac_header_uac20() {
2212 let data = [
2213 9,
2214 CS_INTERFACE,
2215 UAC_AC_HEADER,
2216 0x00,
2217 0x02, 0x80,
2219 0x00,
2220 0x01,
2221 0x01,
2222 ];
2223 let (version, _) = parse_ac_header(&data).unwrap();
2224 assert_eq!(version, UacVersion::Uac20);
2225 }
2226
2227 #[test]
2228 fn test_parse_input_terminal() {
2229 let data = [
2230 12, CS_INTERFACE, UAC_INPUT_TERMINAL, 0x01, 0x01,
2235 0x02, 0x00, 0x02, 0x03,
2239 0x00, 0x00, 0x00, ];
2243 let terminal = parse_input_terminal(&data).unwrap();
2244 assert_eq!(terminal.terminal_id, 1);
2245 assert_eq!(terminal.terminal_type, 0x0201);
2246 assert_eq!(terminal.nr_channels, 2);
2247 assert_eq!(terminal.channel_config, 0x0003);
2248 }
2249
2250 #[test]
2251 fn test_parse_output_terminal() {
2252 let data = [
2253 9, CS_INTERFACE, UAC_OUTPUT_TERMINAL, 0x03, 0x01,
2258 0x03, 0x00, 0x02, 0x00, ];
2263 let terminal = parse_output_terminal(&data).unwrap();
2264 assert_eq!(terminal.terminal_id, 3);
2265 assert_eq!(terminal.terminal_type, 0x0301);
2266 assert_eq!(terminal.source_id, 2);
2267 }
2268
2269 #[test]
2270 fn test_parse_feature_unit() {
2271 let data = [
2272 10, CS_INTERFACE, UAC_FEATURE_UNIT, 0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x00, ];
2283 let fu = parse_feature_unit(&data).unwrap();
2284 assert_eq!(fu.unit_id, 2);
2285 assert_eq!(fu.source_id, 1);
2286 assert_eq!(fu.controls.len(), 3);
2287 assert!(fu.has_mute(0));
2288 assert!(fu.has_volume(0));
2289 }
2290
2291 #[test]
2292 fn test_parse_format_type_i_discrete() {
2293 let data = [
2294 14, CS_INTERFACE, UAC_AS_FORMAT_TYPE, 0x01, 0x02, 0x02, 16, 0x02, 0x44,
2303 0xAC,
2304 0x00, 0x80,
2306 0xBB,
2307 0x00, ];
2309 let fmt = parse_format_type_i(&data).unwrap();
2310 assert_eq!(fmt.nr_channels, 2);
2311 assert_eq!(fmt.subframe_size, 2);
2312 assert_eq!(fmt.bit_resolution, 16);
2313 assert_eq!(fmt.sample_rates.len(), 2);
2314 assert!(fmt.supports_rate(44100));
2315 assert!(fmt.supports_rate(48000));
2316 assert!(!fmt.supports_rate(96000));
2317 }
2318
2319 #[test]
2320 fn test_parse_format_type_i_continuous() {
2321 let data = [
2322 14,
2323 CS_INTERFACE,
2324 UAC_AS_FORMAT_TYPE,
2325 0x01, 0x02, 0x02, 16, 0x00, 0x40,
2331 0x1F,
2332 0x00, 0x00,
2334 0xEE,
2335 0x02, ];
2337 let fmt = parse_format_type_i(&data).unwrap();
2338 assert_eq!(fmt.sample_rates.len(), 1);
2339 assert!(!fmt.sample_rates[0].is_discrete());
2340 assert!(fmt.supports_rate(44100));
2341 assert!(fmt.supports_rate(192000));
2342 }
2343
2344 #[test]
2347 fn test_sample_rate_request_bytes() {
2348 let req = build_set_sample_rate_request(0x01, 48000);
2349 let bytes = req.rate_bytes();
2350 assert_eq!(bytes, [0x80, 0xBB, 0x00]);
2351 assert_eq!(SampleRateRequest::decode_rate(&bytes), 48000);
2352 }
2353
2354 #[test]
2355 fn test_sample_rate_44100() {
2356 let req = build_set_sample_rate_request(0x01, 44100);
2357 let bytes = req.rate_bytes();
2358 assert_eq!(SampleRateRequest::decode_rate(&bytes), 44100);
2359 }
2360
2361 #[test]
2364 fn test_volume_control_request() {
2365 let req = build_set_volume_request(2, 0, 0, VolumeDb::from_db(-10));
2366 assert_eq!(req.request, UAC_SET_CUR);
2367 let bytes = req.volume_bytes();
2368 let decoded = VolumeControlRequest::decode_volume(&bytes);
2369 assert_eq!(decoded.integer_db(), -10);
2370 }
2371
2372 #[test]
2375 fn test_hdmi_infoframe_stereo_pcm() {
2376 let frame = HdmiAudioInfoframe::stereo_pcm(48000, 16);
2377 assert_eq!(frame.coding_type, HdmiAudioCoding::Pcm);
2378 assert_eq!(frame.channel_count, 2);
2379 assert_eq!(frame.sample_rate, HdmiSampleRate::Rate48000);
2380 assert_eq!(frame.sample_size, HdmiSampleSize::Bits16);
2381 assert_eq!(frame.channel_allocation, HdmiChannelAllocation::Stereo);
2382 }
2383
2384 #[test]
2385 fn test_hdmi_infoframe_serialize_parse_roundtrip() {
2386 let original = HdmiAudioInfoframe::stereo_pcm(48000, 16);
2387 let bytes = original.to_bytes();
2388
2389 assert!(HdmiAudioInfoframe::verify_checksum(&bytes));
2391
2392 assert_eq!(bytes[0], HDMI_AUDIO_INFOFRAME_TYPE);
2394 assert_eq!(bytes[1], HDMI_AUDIO_INFOFRAME_VERSION);
2395
2396 let parsed = HdmiAudioInfoframe::from_bytes(&bytes).unwrap();
2398 assert_eq!(parsed, original);
2399 }
2400
2401 #[test]
2402 fn test_hdmi_infoframe_51_roundtrip() {
2403 let original = HdmiAudioInfoframe::surround51_pcm(44100, 24);
2404 let bytes = original.to_bytes();
2405 assert!(HdmiAudioInfoframe::verify_checksum(&bytes));
2406 let parsed = HdmiAudioInfoframe::from_bytes(&bytes).unwrap();
2407 assert_eq!(parsed, original);
2408 }
2409
2410 #[test]
2411 fn test_hdmi_infoframe_bad_checksum() {
2412 let frame = HdmiAudioInfoframe::stereo_pcm(48000, 16);
2413 let mut bytes = frame.to_bytes();
2414 bytes[3] = bytes[3].wrapping_add(1); assert!(!HdmiAudioInfoframe::verify_checksum(&bytes));
2416 assert!(HdmiAudioInfoframe::from_bytes(&bytes).is_err());
2417 }
2418
2419 #[test]
2422 fn test_acr_recommended_n() {
2423 assert_eq!(AudioClockRegeneration::recommended_n(48000), 6144);
2424 assert_eq!(AudioClockRegeneration::recommended_n(44100), 6272);
2425 assert_eq!(AudioClockRegeneration::recommended_n(32000), 4096);
2426 assert_eq!(AudioClockRegeneration::recommended_n(96000), 12288);
2427 assert_eq!(AudioClockRegeneration::recommended_n(192000), 24576);
2428 }
2429
2430 #[test]
2431 fn test_acr_cts_calculation() {
2432 let cts = AudioClockRegeneration::calculate_cts(6144, 48000, 148500);
2436 assert_eq!(cts, 148500);
2437 }
2438
2439 #[test]
2440 fn test_acr_1080p60() {
2441 let acr = AudioClockRegeneration::for_1080p60(48000);
2442 assert_eq!(acr.n, 6144);
2443 assert_eq!(acr.cts, 148500);
2444 }
2445
2446 #[test]
2449 fn test_channel_allocation_count() {
2450 assert_eq!(HdmiChannelAllocation::Stereo.channel_count(), 2);
2451 assert_eq!(HdmiChannelAllocation::Surround51.channel_count(), 6);
2452 assert_eq!(HdmiChannelAllocation::Surround71.channel_count(), 8);
2453 }
2454
2455 #[test]
2458 fn test_sad_from_bytes() {
2459 let bytes: [u8; 3] = [
2461 (1 << 3) | 0x01, 0x06, 0x05, ];
2465 let sad = ShortAudioDescriptor::from_bytes(&bytes);
2466 assert_eq!(sad.format_code, 1);
2467 assert_eq!(sad.max_channels, 2);
2468 assert!(sad.is_pcm());
2469 assert!(sad.supports_rate(44100));
2470 assert!(sad.supports_rate(48000));
2471 assert!(!sad.supports_rate(96000));
2472 assert!(sad.supports_pcm_depth(16));
2473 assert!(!sad.supports_pcm_depth(20));
2474 assert!(sad.supports_pcm_depth(24));
2475 }
2476
2477 #[test]
2478 fn test_sad_roundtrip() {
2479 let original = ShortAudioDescriptor {
2480 format_code: 1,
2481 max_channels: 6,
2482 sample_rate_mask: 0x07, detail: 0x07, };
2485 let bytes = original.to_bytes();
2486 let parsed = ShortAudioDescriptor::from_bytes(&bytes);
2487 assert_eq!(parsed.format_code, original.format_code);
2488 assert_eq!(parsed.max_channels, original.max_channels);
2489 assert_eq!(parsed.sample_rate_mask, original.sample_rate_mask);
2490 assert_eq!(parsed.detail, original.detail);
2491 }
2492
2493 #[test]
2496 fn test_hdmi_sample_rate_from_hz() {
2497 assert_eq!(HdmiSampleRate::from_hz(48000), HdmiSampleRate::Rate48000);
2498 assert_eq!(HdmiSampleRate::from_hz(44100), HdmiSampleRate::Rate44100);
2499 assert_eq!(HdmiSampleRate::from_hz(192000), HdmiSampleRate::Rate192000);
2500 assert_eq!(HdmiSampleRate::from_hz(12345), HdmiSampleRate::StreamHeader);
2501 }
2502
2503 #[test]
2504 fn test_hdmi_sample_rate_to_hz() {
2505 assert_eq!(HdmiSampleRate::Rate48000.to_hz(), 48000);
2506 assert_eq!(HdmiSampleRate::Rate44100.to_hz(), 44100);
2507 assert_eq!(HdmiSampleRate::StreamHeader.to_hz(), 0);
2508 }
2509
2510 #[test]
2513 fn test_standard_sample_rates() {
2514 assert!(is_standard_sample_rate(44100));
2515 assert!(is_standard_sample_rate(48000));
2516 assert!(is_standard_sample_rate(96000));
2517 assert!(!is_standard_sample_rate(12345));
2518 }
2519
2520 #[test]
2523 fn test_usb_audio_device_find_units() {
2524 let mut dev = UsbAudioDevice::new(1, UacVersion::Uac10);
2525
2526 dev.units.push(AudioUnit::InputTerminal(InputTerminal {
2527 terminal_id: 1,
2528 terminal_type: UAC_TERMINAL_MICROPHONE,
2529 assoc_terminal: 0,
2530 nr_channels: 1,
2531 channel_config: 0x01,
2532 }));
2533
2534 dev.units.push(AudioUnit::FeatureUnit(FeatureUnit {
2535 unit_id: 2,
2536 source_id: 1,
2537 controls: vec![0x03],
2538 }));
2539
2540 dev.units.push(AudioUnit::OutputTerminal(OutputTerminal {
2541 terminal_id: 3,
2542 terminal_type: UAC_TERMINAL_SPEAKER,
2543 assoc_terminal: 0,
2544 source_id: 2,
2545 }));
2546
2547 assert!(dev.find_input_terminal(1).is_some());
2548 assert!(dev.find_input_terminal(99).is_none());
2549 assert!(dev.find_output_terminal(3).is_some());
2550 assert!(dev.find_feature_unit(2).is_some());
2551 assert_eq!(dev.feature_units().len(), 1);
2552 assert_eq!(dev.unit_count(), 3);
2553 }
2554
2555 #[test]
2558 fn test_audio_unit_id() {
2559 let unit = AudioUnit::FeatureUnit(FeatureUnit {
2560 unit_id: 42,
2561 source_id: 1,
2562 controls: Vec::new(),
2563 });
2564 assert_eq!(unit.id(), 42);
2565
2566 let unit2 = AudioUnit::ClockSource(ClockSource {
2567 clock_id: 7,
2568 attributes: 0x01,
2569 assoc_terminal: 0,
2570 });
2571 assert_eq!(unit2.id(), 7);
2572 }
2573
2574 #[test]
2577 fn test_clock_source_attributes() {
2578 let clock = ClockSource {
2579 clock_id: 1,
2580 attributes: 0x03, assoc_terminal: 0,
2582 };
2583 assert!(clock.is_external());
2584 assert!(clock.is_sof_synced());
2585
2586 let internal = ClockSource {
2587 clock_id: 2,
2588 attributes: 0x00,
2589 assoc_terminal: 0,
2590 };
2591 assert!(!internal.is_external());
2592 assert!(!internal.is_sof_synced());
2593 }
2594
2595 #[test]
2598 fn test_streaming_interface_direction() {
2599 let output = AudioStreamingInterface {
2600 interface_num: 1,
2601 alternate_setting: 1,
2602 terminal_link: 1,
2603 format: AudioFormatDescriptor {
2604 format_tag: UAC_FORMAT_PCM,
2605 nr_channels: 2,
2606 subframe_size: 2,
2607 bit_resolution: 16,
2608 sample_rates: Vec::new(),
2609 },
2610 endpoint_address: 0x01, max_packet_size: 192,
2612 sync_type: IsoSyncType::Adaptive,
2613 sync_endpoint: 0,
2614 };
2615 assert!(output.is_output());
2616 assert!(!output.is_input());
2617
2618 let input = AudioStreamingInterface {
2619 endpoint_address: 0x82, ..output.clone()
2621 };
2622 assert!(input.is_input());
2623 assert!(!input.is_output());
2624 }
2625
2626 #[test]
2627 fn test_streaming_bytes_per_frame() {
2628 let stream = AudioStreamingInterface {
2629 interface_num: 1,
2630 alternate_setting: 1,
2631 terminal_link: 1,
2632 format: AudioFormatDescriptor {
2633 format_tag: UAC_FORMAT_PCM,
2634 nr_channels: 2,
2635 subframe_size: 2,
2636 bit_resolution: 16,
2637 sample_rates: Vec::new(),
2638 },
2639 endpoint_address: 0x01,
2640 max_packet_size: 192,
2641 sync_type: IsoSyncType::Adaptive,
2642 sync_endpoint: 0,
2643 };
2644 assert_eq!(stream.bytes_per_usb_frame(48000), 192);
2646 assert_eq!(stream.bytes_per_usb_frame(44100), 176);
2648 }
2649
2650 #[test]
2653 fn test_hdmi_audio_output_lifecycle() {
2654 let mut output = HdmiAudioOutput::new(0, 0x02, 0x05);
2655 assert!(!output.has_sink());
2656 assert!(!output.enabled);
2657
2658 output.enable();
2659 assert!(output.enabled);
2660 output.disable();
2661 assert!(!output.enabled);
2662 }
2663
2664 #[test]
2667 fn test_mute_control_request() {
2668 let req = build_set_mute_request(2, 0, 0, true);
2669 assert_eq!(req.request, UAC_SET_CUR);
2670 assert!(req.muted);
2671 assert_eq!(req.value >> 8, UAC_FU_MUTE_CONTROL as u16);
2672 }
2673
2674 #[test]
2677 fn test_read_u24_le() {
2678 assert_eq!(read_u24_le(&[0x44, 0xAC, 0x00]), 44100);
2679 assert_eq!(read_u24_le(&[0x80, 0xBB, 0x00]), 48000);
2680 assert_eq!(read_u24_le(&[0x00, 0xEE, 0x02]), 192000);
2681 }
2682}