aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-usb/src/class/mod.rs1
-rw-r--r--embassy-usb/src/class/uac1/class_codes.rs151
-rw-r--r--embassy-usb/src/class/uac1/mod.rs134
-rw-r--r--embassy-usb/src/class/uac1/speaker.rs778
-rw-r--r--embassy-usb/src/class/uac1/terminal_type.rs50
5 files changed, 1114 insertions, 0 deletions
diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs
index b883ed4e5..4bd89eb66 100644
--- a/embassy-usb/src/class/mod.rs
+++ b/embassy-usb/src/class/mod.rs
@@ -3,4 +3,5 @@ pub mod cdc_acm;
3pub mod cdc_ncm; 3pub mod cdc_ncm;
4pub mod hid; 4pub mod hid;
5pub mod midi; 5pub mod midi;
6pub mod uac1;
6pub mod web_usb; 7pub mod web_usb;
diff --git a/embassy-usb/src/class/uac1/class_codes.rs b/embassy-usb/src/class/uac1/class_codes.rs
new file mode 100644
index 000000000..3f6956771
--- /dev/null
+++ b/embassy-usb/src/class/uac1/class_codes.rs
@@ -0,0 +1,151 @@
1//! Audio Device Class Codes as defined in Universal Serial Bus Device Class
2//! Definition for Audio Devices, Release 1.0, Appendix A and Universal Serial
3//! Bus Device Class Definition for Audio Data Formats, Release 1.0, Appendix
4//! A.1.1 (Audio Data Format Type I Codes)
5#![allow(dead_code)]
6
7/// The current version of the ADC specification (1.0)
8pub const ADC_VERSION: u16 = 0x0100;
9
10/// The current version of the USB device (1.0)
11pub const DEVICE_VERSION: u16 = 0x0100;
12
13/// Audio Interface Class Code
14pub const USB_AUDIO_CLASS: u8 = 0x01;
15
16// Audio Interface Subclass Codes
17pub const USB_UNDEFINED_SUBCLASS: u8 = 0x00;
18pub const USB_AUDIOCONTROL_SUBCLASS: u8 = 0x01;
19pub const USB_AUDIOSTREAMING_SUBCLASS: u8 = 0x02;
20pub const USB_MIDISTREAMING_SUBCLASS: u8 = 0x03;
21
22// Audio Protocol Code
23pub const PROTOCOL_NONE: u8 = 0x00;
24
25// Audio Class-Specific Descriptor Types
26pub const CS_UNDEFINED: u8 = 0x20;
27pub const CS_DEVICE: u8 = 0x21;
28pub const CS_CONFIGURATION: u8 = 0x22;
29pub const CS_STRING: u8 = 0x23;
30pub const CS_INTERFACE: u8 = 0x24;
31pub const CS_ENDPOINT: u8 = 0x25;
32
33// Descriptor Subtype
34pub const AC_DESCRIPTOR_UNDEFINED: u8 = 0x00;
35pub const HEADER_SUBTYPE: u8 = 0x01;
36pub const INPUT_TERMINAL: u8 = 0x02;
37pub const OUTPUT_TERMINAL: u8 = 0x03;
38pub const MIXER_UNIT: u8 = 0x04;
39pub const SELECTOR_UNIT: u8 = 0x05;
40pub const FEATURE_UNIT: u8 = 0x06;
41pub const PROCESSING_UNIT: u8 = 0x07;
42pub const EXTENSION_UNIT: u8 = 0x08;
43
44// Audio Class-Specific AS Interface Descriptor Subtypes
45pub const AS_DESCRIPTOR_UNDEFINED: u8 = 0x00;
46pub const AS_GENERAL: u8 = 0x01;
47pub const FORMAT_TYPE: u8 = 0x02;
48pub const FORMAT_SPECIFIC: u8 = 0x03;
49
50// Processing Unit Process Types
51pub const PROCESS_UNDEFINED: u16 = 0x00;
52pub const UP_DOWNMIX_PROCESS: u16 = 0x01;
53pub const DOLBY_PROLOGIC_PROCESS: u16 = 0x02;
54pub const DDD_STEREO_EXTENDER_PROCESS: u16 = 0x03;
55pub const REVERBERATION_PROCESS: u16 = 0x04;
56pub const CHORUS_PROCESS: u16 = 0x05;
57pub const DYN_RANGE_COMP_PROCESS: u16 = 0x06;
58
59// Audio Class-Specific Endpoint Descriptor Subtypes
60pub const EP_DESCRIPTOR_UNDEFINED: u8 = 0x00;
61pub const EP_GENERAL: u8 = 0x01;
62
63// Audio Class-Specific Request Codes
64pub const REQUEST_CODE_UNDEFINED: u8 = 0x00;
65pub const SET_CUR: u8 = 0x01;
66pub const GET_CUR: u8 = 0x81;
67pub const SET_MIN: u8 = 0x02;
68pub const GET_MIN: u8 = 0x82;
69pub const SET_MAX: u8 = 0x03;
70pub const GET_MAX: u8 = 0x83;
71pub const SET_RES: u8 = 0x04;
72pub const GET_RES: u8 = 0x84;
73pub const SET_MEM: u8 = 0x05;
74pub const GET_MEM: u8 = 0x85;
75pub const GET_STAT: u8 = 0xFF;
76
77// Terminal Control Selectors
78pub const TE_CONTROL_UNDEFINED: u8 = 0x00;
79pub const COPY_PROTECT_CONTROL: u8 = 0x01;
80
81// Feature Unit Control Selectors
82pub const FU_CONTROL_UNDEFINED: u8 = 0x00;
83pub const MUTE_CONTROL: u8 = 0x01;
84pub const VOLUME_CONTROL: u8 = 0x02;
85pub const BASS_CONTROL: u8 = 0x03;
86pub const MID_CONTROL: u8 = 0x04;
87pub const TREBLE_CONTROL: u8 = 0x05;
88pub const GRAPHIC_EQUALIZER_CONTROL: u8 = 0x06;
89pub const AUTOMATIC_GAIN_CONTROL: u8 = 0x07;
90pub const DELAY_CONTROL: u8 = 0x08;
91pub const BASS_BOOST_CONTROL: u8 = 0x09;
92pub const LOUDNESS_CONTROL: u8 = 0x0A;
93
94// Up/Down-mix Processing Unit Control Selectors
95pub const UD_CONTROL_UNDEFINED: u8 = 0x00;
96pub const UD_ENABLE_CONTROL: u8 = 0x01;
97pub const UD_MODE_SELECT_CONTROL: u8 = 0x02;
98
99// Dolby Prologic Processing Unit Control Selectors
100pub const DP_CONTROL_UNDEFINED: u8 = 0x00;
101pub const DP_ENABLE_CONTROL: u8 = 0x01;
102pub const DP_MODE_SELECT_CONTROL: u8 = 0x2;
103
104// 3D Stereo Extender Processing Unit Control Selectors
105pub const DDD_CONTROL_UNDEFINED: u8 = 0x00;
106pub const DDD_ENABLE_CONTROL: u8 = 0x01;
107pub const DDD_SPACIOUSNESS_CONTROL: u8 = 0x03;
108
109// Reverberation Processing Unit Control Selectors
110pub const RV_CONTROL_UNDEFINED: u8 = 0x00;
111pub const RV_ENABLE_CONTROL: u8 = 0x01;
112pub const REVERB_LEVEL_CONTROL: u8 = 0x02;
113pub const REVERB_TIME_CONTROL: u8 = 0x03;
114pub const REVERB_FEEDBACK_CONTROL: u8 = 0x04;
115
116// Chorus Processing Unit Control Selectors
117pub const CH_CONTROL_UNDEFINED: u8 = 0x00;
118pub const CH_ENABLE_CONTROL: u8 = 0x01;
119pub const CHORUS_LEVEL_CONTROL: u8 = 0x02;
120pub const CHORUS_RATE_CONTROL: u8 = 0x03;
121pub const CHORUS_DEPTH_CONTROL: u8 = 0x04;
122
123// Dynamic Range Compressor Processing Unit Control Selectors
124pub const DR_CONTROL_UNDEFINED: u8 = 0x00;
125pub const DR_ENABLE_CONTROL: u8 = 0x01;
126pub const COMPRESSION_RATE_CONTROL: u8 = 0x02;
127pub const MAXAMPL_CONTROL: u8 = 0x03;
128pub const THRESHOLD_CONTROL: u8 = 0x04;
129pub const ATTACK_TIME: u8 = 0x05;
130pub const RELEASE_TIME: u8 = 0x06;
131
132// Extension Unit Control Selectors
133pub const XU_CONTROL_UNDEFINED: u16 = 0x00;
134pub const XU_ENABLE_CONTROL: u16 = 0x01;
135
136// Endpoint Control Selectors
137pub const EP_CONTROL_UNDEFINED: u8 = 0x00;
138pub const SAMPLING_FREQ_CONTROL: u8 = 0x01;
139pub const PITCH_CONTROL: u8 = 0x02;
140
141// Format Type Codes
142pub const FORMAT_TYPE_UNDEFINED: u8 = 0x00;
143pub const FORMAT_TYPE_I: u8 = 0x01;
144
145// Audio Data Format Type I Codes
146pub const TYPE_I_UNDEFINED: u16 = 0x0000;
147pub const PCM: u16 = 0x0001;
148pub const PCM8: u16 = 0x0002;
149pub const IEEE_FLOAT: u16 = 0x0003;
150pub const ALAW: u16 = 0x0004;
151pub const MULAW: u16 = 0x0005;
diff --git a/embassy-usb/src/class/uac1/mod.rs b/embassy-usb/src/class/uac1/mod.rs
new file mode 100644
index 000000000..3d5f4e524
--- /dev/null
+++ b/embassy-usb/src/class/uac1/mod.rs
@@ -0,0 +1,134 @@
1//! USB Audio Class 1.0 implementations for different applications.
2//!
3//! Contains:
4//! - The `speaker` class with a single audio streaming interface (host to device)
5
6pub mod speaker;
7
8mod class_codes;
9mod terminal_type;
10
11/// The maximum supported audio channel index (corresponds to `Top`).
12/// FIXME: Use `core::mem::variant_count(...)` when stabilized.
13const MAX_AUDIO_CHANNEL_INDEX: usize = 12;
14
15/// The maximum number of supported audio channels.
16///
17/// Includes all twelve channels from `Channel`, plus the Master channel.
18const MAX_AUDIO_CHANNEL_COUNT: usize = MAX_AUDIO_CHANNEL_INDEX + 1;
19
20/// USB Audio Channel
21#[derive(Debug, Clone, Copy, PartialEq)]
22#[allow(missing_docs)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum Channel {
25 LeftFront,
26 RightFront,
27 CenterFront,
28 Lfe,
29 LeftSurround,
30 RightSurround,
31 LeftOfCenter,
32 RightOfCenter,
33 Surround,
34 SideLeft,
35 SideRight,
36 Top,
37}
38
39impl Channel {
40 /// Map a `Channel` to its corresponding USB Audio `ChannelConfig`.
41 fn get_channel_config(&self) -> ChannelConfig {
42 match self {
43 Channel::LeftFront => ChannelConfig::LeftFront,
44 Channel::RightFront => ChannelConfig::RightFront,
45 Channel::CenterFront => ChannelConfig::CenterFront,
46 Channel::Lfe => ChannelConfig::Lfe,
47 Channel::LeftSurround => ChannelConfig::LeftSurround,
48 Channel::RightSurround => ChannelConfig::RightSurround,
49 Channel::LeftOfCenter => ChannelConfig::LeftOfCenter,
50 Channel::RightOfCenter => ChannelConfig::RightOfCenter,
51 Channel::Surround => ChannelConfig::Surround,
52 Channel::SideLeft => ChannelConfig::SideLeft,
53 Channel::SideRight => ChannelConfig::SideRight,
54 Channel::Top => ChannelConfig::Top,
55 }
56 }
57}
58
59/// USB Audio Channel configuration
60#[repr(u16)]
61#[non_exhaustive]
62// #[derive(Copy, Clone, Eq, PartialEq, Debug)]
63enum ChannelConfig {
64 None = 0x0000,
65 LeftFront = 0x0001,
66 RightFront = 0x0002,
67 CenterFront = 0x0004,
68 Lfe = 0x0008,
69 LeftSurround = 0x0010,
70 RightSurround = 0x0020,
71 LeftOfCenter = 0x0040,
72 RightOfCenter = 0x0080,
73 Surround = 0x0100,
74 SideLeft = 0x0200,
75 SideRight = 0x0400,
76 Top = 0x0800,
77}
78
79impl From<ChannelConfig> for u16 {
80 fn from(t: ChannelConfig) -> u16 {
81 t as u16
82 }
83}
84
85/// Feedback period adjustment `bRefresh` [UAC 3.7.2.2]
86///
87/// From the specification: "A new Ff value is available every 2^(10 – P) frames with P ranging from 1 to 9. The
88/// bRefresh field of the synch standard endpoint descriptor is used to report the exponent (10-P) to the Host."
89///
90/// This means:
91/// - 512 ms (2^9 frames) to 2 ms (2^1 frames) for USB full-speed
92/// - 64 ms (2^9 microframes) to 0.25 ms (2^1 microframes) for USB high-speed
93#[repr(u8)]
94#[allow(missing_docs)]
95#[derive(Clone, Copy)]
96pub enum FeedbackRefresh {
97 Period2Frames = 1,
98 Period4Frames = 2,
99 Period8Frames = 3,
100 Period16Frames = 4,
101 Period32Frames = 5,
102 Period64Frames = 6,
103 Period128Frames = 7,
104 Period256Frames = 8,
105 Period512Frames = 9,
106}
107
108impl FeedbackRefresh {
109 /// Gets the number of frames, after which a new feedback frame is returned.
110 pub const fn frame_count(&self) -> usize {
111 1 << (*self as usize)
112 }
113}
114
115/// Audio sample width.
116///
117/// Stored in number of bytes per sample.
118#[repr(u8)]
119#[derive(Clone, Copy)]
120pub enum SampleWidth {
121 /// 16 bit audio
122 Width2Byte = 2,
123 /// 24 bit audio
124 Width3Byte = 3,
125 /// 32 bit audio
126 Width4Byte = 4,
127}
128
129impl SampleWidth {
130 /// Get the audio sample resolution in number of bit.
131 pub const fn in_bit(self) -> usize {
132 8 * self as usize
133 }
134}
diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs
new file mode 100644
index 000000000..96456d94a
--- /dev/null
+++ b/embassy-usb/src/class/uac1/speaker.rs
@@ -0,0 +1,778 @@
1//! USB Audio Class 1.0 - Speaker device
2//!
3//! Provides a class with a single audio streaming interface (host to device),
4//! that advertises itself as a speaker. Includes explicit sample rate feedback.
5//!
6//! Various aspects of the audio stream can be configured, for example:
7//! - sample rate
8//! - sample resolution
9//! - audio channel count and assignment
10//!
11//! The class provides volume and mute controls for each channel.
12
13use core::cell::{Cell, RefCell};
14use core::future::poll_fn;
15use core::marker::PhantomData;
16use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
17use core::task::Poll;
18
19use embassy_sync::blocking_mutex::CriticalSectionMutex;
20use embassy_sync::waitqueue::WakerRegistration;
21use heapless::Vec;
22
23use super::class_codes::*;
24use super::terminal_type::TerminalType;
25use super::{Channel, ChannelConfig, FeedbackRefresh, SampleWidth, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX};
26use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
27use crate::descriptor::{SynchronizationType, UsageType};
28use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut, EndpointType};
29use crate::types::InterfaceNumber;
30use crate::{Builder, Handler};
31
32/// Maximum allowed sampling rate (3 bytes) in Hz.
33const MAX_SAMPLE_RATE_HZ: u32 = 0x7FFFFF;
34
35/// Arbitrary unique identifier for the input unit.
36const INPUT_UNIT_ID: u8 = 0x01;
37
38/// Arbitrary unique identifier for the feature unit.
39const FEATURE_UNIT_ID: u8 = 0x02;
40
41/// Arbitrary unique identifier for the output unit.
42const OUTPUT_UNIT_ID: u8 = 0x03;
43
44// Volume settings go from -25600 to 0, in steps of 256.
45// Therefore, the volume settings are 8q8 values in units of dB.
46const VOLUME_STEPS_PER_DB: i16 = 256;
47const MIN_VOLUME_DB: i16 = -100;
48const MAX_VOLUME_DB: i16 = 0;
49
50// Maximum number of supported discrete sample rates.
51const MAX_SAMPLE_RATE_COUNT: usize = 10;
52
53/// The volume of an audio channel.
54#[derive(Debug, Clone, Copy)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56pub enum Volume {
57 /// The channel is muted.
58 Muted,
59 /// The channel volume in dB. Ranges from `MIN_VOLUME_DB` (quietest) to `MAX_VOLUME_DB` (loudest).
60 DeciBel(f32),
61}
62
63/// Internal state for the USB Audio Class.
64pub struct State<'d> {
65 control: Option<Control<'d>>,
66 shared: SharedControl<'d>,
67}
68
69impl<'d> Default for State<'d> {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl<'d> State<'d> {
76 /// Create a new `State`.
77 pub fn new() -> Self {
78 Self {
79 control: None,
80 shared: SharedControl::default(),
81 }
82 }
83}
84
85/// Implementation of the USB audio class 1.0.
86pub struct Speaker<'d, D: Driver<'d>> {
87 phantom: PhantomData<&'d D>,
88}
89
90impl<'d, D: Driver<'d>> Speaker<'d, D> {
91 /// Creates a new [`Speaker`] device, split into a stream, feedback, and a control change notifier.
92 ///
93 /// The packet size should be chosen, based on the expected transfer size of samples per (micro)frame.
94 /// For example, a stereo stream at 32 bit resolution and 48 kHz sample rate yields packets of 384 byte for
95 /// full-speed USB (1 ms frame interval) or 48 byte for high-speed USB (125 us microframe interval).
96 /// When using feedback, the packet size varies and thus, the `max_packet_size` should be increased (e.g. to double).
97 ///
98 /// # Arguments
99 ///
100 /// * `builder` - The builder for the class.
101 /// * `state` - The internal state of the class.
102 /// * `max_packet_size` - The maximum packet size per (micro)frame.
103 /// * `resolution` - The audio sample resolution.
104 /// * `sample_rates_hz` - The supported sample rates in Hz.
105 /// * `channels` - The advertised audio channels (up to 12). Entries must be unique, or this function panics.
106 /// * `feedback_refresh_period` - The refresh period for the feedback value.
107 pub fn new(
108 builder: &mut Builder<'d, D>,
109 state: &'d mut State<'d>,
110 max_packet_size: u16,
111 resolution: SampleWidth,
112 sample_rates_hz: &[u32],
113 channels: &'d [Channel],
114 feedback_refresh_period: FeedbackRefresh,
115 ) -> (Stream<'d, D>, Feedback<'d, D>, ControlMonitor<'d>) {
116 // The class and subclass fields of the IAD aren't required to match the class and subclass fields of
117 // the interfaces in the interface collection that the IAD describes. Microsoft recommends that
118 // the first interface of the collection has class and subclass fields that match the class and
119 // subclass fields of the IAD.
120 let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE);
121
122 // Audio control interface (mandatory) [UAC 4.3.1]
123 let mut interface = func.interface();
124 let control_interface = interface.interface_number().into();
125 let streaming_interface = u8::from(control_interface) + 1;
126 let mut alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE, None);
127
128 // Terminal topology:
129 // Input terminal (receives audio stream) -> Feature Unit (mute and volume) -> Output terminal (e.g. towards speaker)
130
131 // =======================================
132 // Input Terminal Descriptor [UAC 3.3.2.1]
133 // Audio input
134 let terminal_type: u16 = TerminalType::UsbStreaming.into();
135
136 // Assemble channel configuration field
137 let mut channel_config: u16 = ChannelConfig::None.into();
138 for channel in channels {
139 let channel: u16 = channel.get_channel_config().into();
140
141 if channel_config & channel != 0 {
142 panic!("Invalid channel config, duplicate channel {}.", channel);
143 }
144 channel_config |= channel;
145 }
146
147 let input_terminal_descriptor = [
148 INPUT_TERMINAL, // bDescriptorSubtype
149 INPUT_UNIT_ID, // bTerminalID
150 terminal_type as u8,
151 (terminal_type >> 8) as u8, // wTerminalType
152 0x00, // bAssocTerminal (none)
153 channels.len() as u8, // bNrChannels
154 channel_config as u8,
155 (channel_config >> 8) as u8, // wChannelConfig
156 0x00, // iChannelNames (none)
157 0x00, // iTerminal (none)
158 ];
159
160 // ========================================
161 // Output Terminal Descriptor [UAC 4.3.2.2]
162 // Speaker output
163 let terminal_type: u16 = TerminalType::OutSpeaker.into();
164 let output_terminal_descriptor = [
165 OUTPUT_TERMINAL, // bDescriptorSubtype
166 OUTPUT_UNIT_ID, // bTerminalID
167 terminal_type as u8,
168 (terminal_type >> 8) as u8, // wTerminalType
169 0x00, // bAssocTerminal (none)
170 FEATURE_UNIT_ID, // bSourceID (the feature unit)
171 0x00, // iTerminal (none)
172 ];
173
174 // =====================================
175 // Feature Unit Descriptor [UAC 4.3.2.5]
176 // Mute and volume control
177 let controls = MUTE_CONTROL | VOLUME_CONTROL;
178
179 const FEATURE_UNIT_DESCRIPTOR_SIZE: usize = 5;
180 let mut feature_unit_descriptor: Vec<u8, { FEATURE_UNIT_DESCRIPTOR_SIZE + MAX_AUDIO_CHANNEL_COUNT + 1 }> =
181 Vec::from_slice(&[
182 FEATURE_UNIT, // bDescriptorSubtype (Feature Unit)
183 FEATURE_UNIT_ID, // bUnitID
184 INPUT_UNIT_ID, // bSourceID
185 1, // bControlSize (one byte per control)
186 FU_CONTROL_UNDEFINED, // Master controls (disabled, use only per-channel control)
187 ])
188 .unwrap();
189
190 // Add per-channel controls
191 for _channel in channels {
192 feature_unit_descriptor.push(controls).unwrap();
193 }
194 feature_unit_descriptor.push(0x00).unwrap(); // iFeature (none)
195
196 // ===============================================
197 // Format desciptor [UAC 4.5.3]
198 // Used later, for operational streaming interface
199 let mut format_descriptor: Vec<u8, { 6 + 3 * MAX_SAMPLE_RATE_COUNT }> = Vec::from_slice(&[
200 FORMAT_TYPE, // bDescriptorSubtype
201 FORMAT_TYPE_I, // bFormatType
202 channels.len() as u8, // bNrChannels
203 resolution as u8, // bSubframeSize
204 resolution.in_bit() as u8, // bBitResolution
205 ])
206 .unwrap();
207
208 format_descriptor.push(sample_rates_hz.len() as u8).unwrap();
209
210 for sample_rate_hz in sample_rates_hz {
211 assert!(*sample_rate_hz <= MAX_SAMPLE_RATE_HZ);
212 format_descriptor.push((sample_rate_hz & 0xFF) as u8).unwrap();
213 format_descriptor.push(((sample_rate_hz >> 8) & 0xFF) as u8).unwrap();
214 format_descriptor.push(((sample_rate_hz >> 16) & 0xFF) as u8).unwrap();
215 }
216
217 // ==================================================
218 // Class-specific AC Interface Descriptor [UAC 4.3.2]
219 const DESCRIPTOR_HEADER_SIZE: usize = 2;
220 const INTERFACE_DESCRIPTOR_SIZE: usize = 7;
221
222 let mut total_descriptor_length = 0;
223
224 for size in [
225 INTERFACE_DESCRIPTOR_SIZE,
226 input_terminal_descriptor.len(),
227 feature_unit_descriptor.len(),
228 output_terminal_descriptor.len(),
229 ] {
230 total_descriptor_length += size + DESCRIPTOR_HEADER_SIZE;
231 }
232
233 let interface_descriptor: [u8; INTERFACE_DESCRIPTOR_SIZE] = [
234 HEADER_SUBTYPE, // bDescriptorSubtype (Header)
235 ADC_VERSION as u8,
236 (ADC_VERSION >> 8) as u8, // bcdADC
237 total_descriptor_length as u8,
238 (total_descriptor_length >> 8) as u8, // wTotalLength
239 0x01, // bInCollection (1 streaming interface)
240 streaming_interface, // baInterfaceNr
241 ];
242
243 alt.descriptor(CS_INTERFACE, &interface_descriptor);
244 alt.descriptor(CS_INTERFACE, &input_terminal_descriptor);
245 alt.descriptor(CS_INTERFACE, &feature_unit_descriptor);
246 alt.descriptor(CS_INTERFACE, &output_terminal_descriptor);
247
248 // =====================================================
249 // Audio streaming interface, zero-bandwidth [UAC 4.5.1]
250 let mut interface = func.interface();
251 let alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOSTREAMING_SUBCLASS, PROTOCOL_NONE, None);
252 drop(alt);
253
254 // ==================================================
255 // Audio streaming interface, operational [UAC 4.5.1]
256 let mut alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOSTREAMING_SUBCLASS, PROTOCOL_NONE, None);
257
258 alt.descriptor(
259 CS_INTERFACE,
260 &[
261 AS_GENERAL, // bDescriptorSubtype
262 INPUT_UNIT_ID, // bTerminalLink
263 0x00, // bDelay (none)
264 PCM as u8,
265 (PCM >> 8) as u8, // wFormatTag (PCM format)
266 ],
267 );
268
269 alt.descriptor(CS_INTERFACE, &format_descriptor);
270
271 let streaming_endpoint = alt.alloc_endpoint_out(EndpointType::Isochronous, max_packet_size, 1);
272 let feedback_endpoint = alt.alloc_endpoint_in(
273 EndpointType::Isochronous,
274 4, // Feedback packets are 24 bit (10.14 format).
275 1,
276 );
277
278 // Write the descriptor for the streaming endpoint, after knowing the address of the feedback endpoint.
279 alt.endpoint_descriptor(
280 streaming_endpoint.info(),
281 SynchronizationType::Asynchronous,
282 UsageType::DataEndpoint,
283 &[
284 0x00, // bRefresh (0)
285 feedback_endpoint.info().addr.into(), // bSynchAddress (the feedback endpoint)
286 ],
287 );
288
289 alt.descriptor(
290 CS_ENDPOINT,
291 &[
292 AS_GENERAL, // bDescriptorSubtype (General)
293 SAMPLING_FREQ_CONTROL, // bmAttributes (support sampling frequency control)
294 0x02, // bLockDelayUnits (PCM)
295 0x0000 as u8,
296 (0x0000 >> 8) as u8, // wLockDelay (0)
297 ],
298 );
299
300 // Write the feedback endpoint descriptor after the streaming endpoint descriptor
301 // This is demanded by the USB audio class specification.
302 alt.endpoint_descriptor(
303 feedback_endpoint.info(),
304 SynchronizationType::NoSynchronization,
305 UsageType::FeedbackEndpoint,
306 &[
307 feedback_refresh_period as u8, // bRefresh
308 0x00, // bSynchAddress (none)
309 ],
310 );
311
312 // Free up the builder.
313 drop(func);
314
315 // Store channel information
316 state.shared.channels = channels;
317
318 state.control = Some(Control {
319 shared: &state.shared,
320 streaming_endpoint_address: streaming_endpoint.info().addr.into(),
321 control_interface_number: control_interface,
322 });
323
324 builder.handler(state.control.as_mut().unwrap());
325
326 let control = &state.shared;
327
328 (
329 Stream { streaming_endpoint },
330 Feedback { feedback_endpoint },
331 ControlMonitor { shared: control },
332 )
333 }
334}
335
336/// Audio settings for the feature unit.
337///
338/// Contains volume and mute control.
339#[derive(Clone, Copy, Debug)]
340#[cfg_attr(feature = "defmt", derive(defmt::Format))]
341pub struct AudioSettings {
342 /// Channel mute states.
343 muted: [bool; MAX_AUDIO_CHANNEL_COUNT],
344 /// Channel volume levels in 8.8 format (in dB).
345 volume_8q8_db: [i16; MAX_AUDIO_CHANNEL_COUNT],
346}
347
348impl Default for AudioSettings {
349 fn default() -> Self {
350 AudioSettings {
351 muted: [true; MAX_AUDIO_CHANNEL_COUNT],
352 volume_8q8_db: [MAX_VOLUME_DB * VOLUME_STEPS_PER_DB; MAX_AUDIO_CHANNEL_COUNT],
353 }
354 }
355}
356
357struct Control<'d> {
358 control_interface_number: InterfaceNumber,
359 streaming_endpoint_address: u8,
360 shared: &'d SharedControl<'d>,
361}
362
363/// Shared data between [`Control`] and the [`Speaker`] class.
364struct SharedControl<'d> {
365 /// The collection of audio settings (volumes, mute states).
366 audio_settings: CriticalSectionMutex<Cell<AudioSettings>>,
367
368 /// Channel assignments.
369 channels: &'d [Channel],
370
371 /// The audio sample rate in Hz.
372 sample_rate_hz: AtomicU32,
373
374 // Notification mechanism.
375 waker: RefCell<WakerRegistration>,
376 changed: AtomicBool,
377}
378
379impl<'d> Default for SharedControl<'d> {
380 fn default() -> Self {
381 SharedControl {
382 audio_settings: CriticalSectionMutex::new(Cell::new(AudioSettings::default())),
383 channels: &[],
384 sample_rate_hz: AtomicU32::new(0),
385 waker: RefCell::new(WakerRegistration::new()),
386 changed: AtomicBool::new(false),
387 }
388 }
389}
390
391impl<'d> SharedControl<'d> {
392 async fn changed(&self) {
393 poll_fn(|context| {
394 if self.changed.load(Ordering::Relaxed) {
395 self.changed.store(false, Ordering::Relaxed);
396 Poll::Ready(())
397 } else {
398 self.waker.borrow_mut().register(context.waker());
399 Poll::Pending
400 }
401 })
402 .await;
403 }
404}
405
406/// Used for reading audio frames.
407pub struct Stream<'d, D: Driver<'d>> {
408 streaming_endpoint: D::EndpointOut,
409}
410
411impl<'d, D: Driver<'d>> Stream<'d, D> {
412 /// Reads a single packet from the OUT endpoint
413 pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
414 self.streaming_endpoint.read(data).await
415 }
416
417 /// Waits for the USB host to enable this interface
418 pub async fn wait_connection(&mut self) {
419 self.streaming_endpoint.wait_enabled().await;
420 }
421}
422
423/// Used for writing sample rate information over the feedback endpoint.
424pub struct Feedback<'d, D: Driver<'d>> {
425 feedback_endpoint: D::EndpointIn,
426}
427
428impl<'d, D: Driver<'d>> Feedback<'d, D> {
429 /// Writes a single packet into the IN endpoint.
430 pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
431 self.feedback_endpoint.write(data).await
432 }
433
434 /// Waits for the USB host to enable this interface.
435 pub async fn wait_connection(&mut self) {
436 self.feedback_endpoint.wait_enabled().await;
437 }
438}
439
440/// Control status change monitor
441///
442/// Await [`ControlMonitor::changed`] for being notified of configuration changes. Afterwards, the updated
443/// configuration settings can be read with [`ControlMonitor::volume`] and [`ControlMonitor::sample_rate_hz`].
444pub struct ControlMonitor<'d> {
445 shared: &'d SharedControl<'d>,
446}
447
448impl<'d> ControlMonitor<'d> {
449 fn audio_settings(&self) -> AudioSettings {
450 let audio_settings = self.shared.audio_settings.lock(|x| x.get());
451
452 audio_settings
453 }
454
455 fn get_logical_channel(&self, search_channel: Channel) -> Option<usize> {
456 let index = self.shared.channels.iter().position(|&c| c == search_channel)?;
457
458 // The logical channels start at one (zero is the master channel).
459 Some(index + 1)
460 }
461
462 /// Get the volume of a selected channel.
463 pub fn volume(&self, channel: Channel) -> Option<Volume> {
464 let channel_index = self.get_logical_channel(channel)?;
465
466 if self.audio_settings().muted[channel_index] {
467 return Some(Volume::Muted);
468 }
469
470 Some(Volume::DeciBel(
471 (self.audio_settings().volume_8q8_db[channel_index] as f32) / 256.0f32,
472 ))
473 }
474
475 /// Get the streaming endpoint's sample rate in Hz.
476 pub fn sample_rate_hz(&self) -> u32 {
477 self.shared.sample_rate_hz.load(Ordering::Relaxed)
478 }
479
480 /// Return a future for when the control settings change.
481 pub async fn changed(&self) {
482 self.shared.changed().await;
483 }
484}
485
486impl<'d> Control<'d> {
487 fn changed(&mut self) {
488 self.shared.changed.store(true, Ordering::Relaxed);
489 self.shared.waker.borrow_mut().wake();
490 }
491
492 fn interface_set_mute_state(
493 &mut self,
494 audio_settings: &mut AudioSettings,
495 channel_index: u8,
496 data: &[u8],
497 ) -> OutResponse {
498 let mute_state = data[0] != 0;
499
500 match channel_index as usize {
501 ..=MAX_AUDIO_CHANNEL_INDEX => {
502 audio_settings.muted[channel_index as usize] = mute_state;
503 }
504 _ => {
505 debug!("Failed to set channel {} mute state: {}", channel_index, mute_state);
506 return OutResponse::Rejected;
507 }
508 }
509
510 debug!("Set channel {} mute state: {}", channel_index, mute_state);
511 OutResponse::Accepted
512 }
513
514 fn interface_set_volume(
515 &mut self,
516 audio_settings: &mut AudioSettings,
517 channel_index: u8,
518 data: &[u8],
519 ) -> OutResponse {
520 let volume = i16::from_ne_bytes(data[..2].try_into().expect("Failed to read volume."));
521
522 match channel_index as usize {
523 ..=MAX_AUDIO_CHANNEL_INDEX => {
524 audio_settings.volume_8q8_db[channel_index as usize] = volume;
525 }
526 _ => {
527 debug!("Failed to set channel {} volume: {}", channel_index, volume);
528 return OutResponse::Rejected;
529 }
530 }
531
532 debug!("Set channel {} volume: {}", channel_index, volume);
533 OutResponse::Accepted
534 }
535
536 fn interface_set_request(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
537 let interface_number = req.index as u8;
538 let entity_index = (req.index >> 8) as u8;
539 let channel_index = req.value as u8;
540 let control_unit = (req.value >> 8) as u8;
541
542 if interface_number != self.control_interface_number.into() {
543 debug!("Unhandled interface set request for interface {}", interface_number);
544 return None;
545 }
546
547 if entity_index != FEATURE_UNIT_ID {
548 debug!("Unsupported interface set request for entity {}", entity_index);
549 return Some(OutResponse::Rejected);
550 }
551
552 if req.request != SET_CUR {
553 debug!("Unsupported interface set request type {}", req.request);
554 return Some(OutResponse::Rejected);
555 }
556
557 let mut audio_settings = self.shared.audio_settings.lock(|x| x.get());
558 let response = match control_unit {
559 MUTE_CONTROL => self.interface_set_mute_state(&mut audio_settings, channel_index, data),
560 VOLUME_CONTROL => self.interface_set_volume(&mut audio_settings, channel_index, data),
561 _ => OutResponse::Rejected,
562 };
563
564 if response == OutResponse::Rejected {
565 return Some(response);
566 }
567
568 // Store updated settings
569 self.shared.audio_settings.lock(|x| x.set(audio_settings));
570
571 self.changed();
572
573 Some(OutResponse::Accepted)
574 }
575
576 fn endpoint_set_request(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
577 let control_selector = (req.value >> 8) as u8;
578 let endpoint_address = req.index as u8;
579
580 if endpoint_address != self.streaming_endpoint_address {
581 debug!(
582 "Unhandled endpoint set request for endpoint {} and control {} with data {}",
583 endpoint_address, control_selector, data
584 );
585 return None;
586 }
587
588 if control_selector != SAMPLING_FREQ_CONTROL {
589 debug!(
590 "Unsupported endpoint set request for control selector {}",
591 control_selector
592 );
593 return Some(OutResponse::Rejected);
594 }
595
596 let sample_rate_hz: u32 = (data[0] as u32) | (data[1] as u32) << 8 | (data[2] as u32) << 16;
597 self.shared.sample_rate_hz.store(sample_rate_hz, Ordering::Relaxed);
598
599 debug!("Set endpoint {} sample rate to {} Hz", endpoint_address, sample_rate_hz);
600
601 self.changed();
602
603 Some(OutResponse::Accepted)
604 }
605
606 fn interface_get_request<'r>(&'r mut self, req: Request, buf: &'r mut [u8]) -> Option<InResponse<'r>> {
607 let interface_number = req.index as u8;
608 let entity_index = (req.index >> 8) as u8;
609 let channel_index = req.value as u8;
610 let control_unit = (req.value >> 8) as u8;
611
612 if interface_number != self.control_interface_number.into() {
613 debug!("Unhandled interface get request for interface {}.", interface_number);
614 return None;
615 }
616
617 if entity_index != FEATURE_UNIT_ID {
618 // Only this function unit can be handled at the moment.
619 debug!("Unsupported interface get request for entity {}.", entity_index);
620 return Some(InResponse::Rejected);
621 }
622
623 let audio_settings = self.shared.audio_settings.lock(|x| x.get());
624
625 match req.request {
626 GET_CUR => match control_unit {
627 VOLUME_CONTROL => {
628 let volume: i16;
629
630 match channel_index as usize {
631 ..=MAX_AUDIO_CHANNEL_INDEX => volume = audio_settings.volume_8q8_db[channel_index as usize],
632 _ => return Some(InResponse::Rejected),
633 }
634
635 buf[0] = volume as u8;
636 buf[1] = (volume >> 8) as u8;
637
638 debug!("Got channel {} volume: {}.", channel_index, volume);
639 return Some(InResponse::Accepted(&buf[..2]));
640 }
641 MUTE_CONTROL => {
642 let mute_state: bool;
643
644 match channel_index as usize {
645 ..=MAX_AUDIO_CHANNEL_INDEX => mute_state = audio_settings.muted[channel_index as usize],
646 _ => return Some(InResponse::Rejected),
647 }
648
649 buf[0] = mute_state.into();
650 debug!("Got channel {} mute state: {}.", channel_index, mute_state);
651 return Some(InResponse::Accepted(&buf[..1]));
652 }
653 _ => return Some(InResponse::Rejected),
654 },
655 GET_MIN => match control_unit {
656 VOLUME_CONTROL => {
657 let min_volume = MIN_VOLUME_DB * VOLUME_STEPS_PER_DB;
658 buf[0] = min_volume as u8;
659 buf[1] = (min_volume >> 8) as u8;
660 return Some(InResponse::Accepted(&buf[..2]));
661 }
662 _ => return Some(InResponse::Rejected),
663 },
664 GET_MAX => match control_unit {
665 VOLUME_CONTROL => {
666 let max_volume = MAX_VOLUME_DB * VOLUME_STEPS_PER_DB;
667 buf[0] = max_volume as u8;
668 buf[1] = (max_volume >> 8) as u8;
669 return Some(InResponse::Accepted(&buf[..2]));
670 }
671 _ => return Some(InResponse::Rejected),
672 },
673 GET_RES => match control_unit {
674 VOLUME_CONTROL => {
675 buf[0] = VOLUME_STEPS_PER_DB as u8;
676 buf[1] = (VOLUME_STEPS_PER_DB >> 8) as u8;
677 return Some(InResponse::Accepted(&buf[..2]));
678 }
679 _ => return Some(InResponse::Rejected),
680 },
681 _ => return Some(InResponse::Rejected),
682 }
683 }
684
685 fn endpoint_get_request<'r>(&'r mut self, req: Request, buf: &'r mut [u8]) -> Option<InResponse<'r>> {
686 let control_selector = (req.value >> 8) as u8;
687 let endpoint_address = req.index as u8;
688
689 if endpoint_address != self.streaming_endpoint_address {
690 debug!("Unhandled endpoint get request for endpoint {}.", endpoint_address);
691 return None;
692 }
693
694 if control_selector != SAMPLING_FREQ_CONTROL as u8 {
695 debug!(
696 "Unsupported endpoint get request for control selector {}.",
697 control_selector
698 );
699 return Some(InResponse::Rejected);
700 }
701
702 let sample_rate_hz = self.shared.sample_rate_hz.load(Ordering::Relaxed);
703
704 buf[0] = (sample_rate_hz & 0xFF) as u8;
705 buf[1] = ((sample_rate_hz >> 8) & 0xFF) as u8;
706 buf[2] = ((sample_rate_hz >> 16) & 0xFF) as u8;
707
708 Some(InResponse::Accepted(&buf[..3]))
709 }
710}
711
712impl<'d> Handler for Control<'d> {
713 /// Called when the USB device has been enabled or disabled.
714 fn enabled(&mut self, enabled: bool) {
715 debug!("USB device enabled: {}", enabled);
716 }
717
718 /// Called when the host has set the address of the device to `addr`.
719 fn addressed(&mut self, addr: u8) {
720 debug!("Host set address to: {}", addr);
721 }
722
723 /// Called when the host has enabled or disabled the configuration of the device.
724 fn configured(&mut self, configured: bool) {
725 debug!("USB device configured: {}", configured);
726 }
727
728 /// Called when remote wakeup feature is enabled or disabled.
729 fn remote_wakeup_enabled(&mut self, enabled: bool) {
730 debug!("USB remote wakeup enabled: {}", enabled);
731 }
732
733 /// Called when a "set alternate setting" control request is done on the interface.
734 fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) {
735 debug!(
736 "USB set interface number {} to alt setting {}.",
737 iface, alternate_setting
738 );
739 }
740
741 /// Called after a USB reset after the bus reset sequence is complete.
742 fn reset(&mut self) {
743 let shared = self.shared;
744 shared.audio_settings.lock(|x| x.set(AudioSettings::default()));
745
746 shared.changed.store(true, Ordering::Relaxed);
747 shared.waker.borrow_mut().wake();
748 }
749
750 /// Called when the bus has entered or exited the suspend state.
751 fn suspended(&mut self, suspended: bool) {
752 debug!("USB device suspended: {}", suspended);
753 }
754
755 // Handle control set requests.
756 fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
757 match req.request_type {
758 RequestType::Class => match req.recipient {
759 Recipient::Interface => self.interface_set_request(req, data),
760 Recipient::Endpoint => self.endpoint_set_request(req, data),
761 _ => Some(OutResponse::Rejected),
762 },
763 _ => None,
764 }
765 }
766
767 // Handle control get requests.
768 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
769 match req.request_type {
770 RequestType::Class => match req.recipient {
771 Recipient::Interface => self.interface_get_request(req, buf),
772 Recipient::Endpoint => self.endpoint_get_request(req, buf),
773 _ => None,
774 },
775 _ => None,
776 }
777 }
778}
diff --git a/embassy-usb/src/class/uac1/terminal_type.rs b/embassy-usb/src/class/uac1/terminal_type.rs
new file mode 100644
index 000000000..65474a714
--- /dev/null
+++ b/embassy-usb/src/class/uac1/terminal_type.rs
@@ -0,0 +1,50 @@
1//! USB Audio Terminal Types from Universal Serial Bus Device Class Definition
2//! for Terminal Types, Release 1.0
3
4/// USB Audio Terminal Types from "Universal Serial Bus Device Class Definition
5/// for Terminal Types, Release 1.0"
6#[repr(u16)]
7#[non_exhaustive]
8#[derive(Copy, Clone, Eq, PartialEq, Debug)]
9#[allow(missing_docs)]
10pub enum TerminalType {
11 // USB Terminal Types
12 UsbUndefined = 0x0100,
13 UsbStreaming = 0x0101,
14 UsbVendor = 0x01ff,
15
16 // Input Terminal Types
17 InUndefined = 0x0200,
18 InMicrophone = 0x0201,
19 InDesktopMicrophone = 0x0202,
20 InPersonalMicrophone = 0x0203,
21 InOmniDirectionalMicrophone = 0x0204,
22 InMicrophoneArray = 0x0205,
23 InProcessingMicrophoneArray = 0x0206,
24
25 // Output Terminal Types
26 OutUndefined = 0x0300,
27 OutSpeaker = 0x0301,
28 OutHeadphones = 0x0302,
29 OutHeadMountedDisplayAudio = 0x0303,
30 OutDesktopSpeaker = 0x0304,
31 OutRoomSpeaker = 0x0305,
32 OutCommunicationSpeaker = 0x0306,
33 OutLowFrequencyEffectsSpeaker = 0x0307,
34
35 // External Terminal Types
36 ExtUndefined = 0x0600,
37 ExtAnalogConnector = 0x0601,
38 ExtDigitalAudioInterface = 0x0602,
39 ExtLineConnector = 0x0603,
40 ExtLegacyAudioConnector = 0x0604,
41 ExtSpdifConnector = 0x0605,
42 Ext1394DaStream = 0x0606,
43 Ext1394DvStreamSoundtrack = 0x0607,
44}
45
46impl From<TerminalType> for u16 {
47 fn from(t: TerminalType) -> u16 {
48 t as u16
49 }
50}