diff options
Diffstat (limited to 'embassy-usb/src/class/uac1/speaker.rs')
| -rw-r--r-- | embassy-usb/src/class/uac1/speaker.rs | 778 |
1 files changed, 778 insertions, 0 deletions
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 | |||
| 13 | use core::cell::{Cell, RefCell}; | ||
| 14 | use core::future::poll_fn; | ||
| 15 | use core::marker::PhantomData; | ||
| 16 | use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; | ||
| 17 | use core::task::Poll; | ||
| 18 | |||
| 19 | use embassy_sync::blocking_mutex::CriticalSectionMutex; | ||
| 20 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 21 | use heapless::Vec; | ||
| 22 | |||
| 23 | use super::class_codes::*; | ||
| 24 | use super::terminal_type::TerminalType; | ||
| 25 | use super::{Channel, ChannelConfig, FeedbackRefresh, SampleWidth, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX}; | ||
| 26 | use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; | ||
| 27 | use crate::descriptor::{SynchronizationType, UsageType}; | ||
| 28 | use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut, EndpointType}; | ||
| 29 | use crate::types::InterfaceNumber; | ||
| 30 | use crate::{Builder, Handler}; | ||
| 31 | |||
| 32 | /// Maximum allowed sampling rate (3 bytes) in Hz. | ||
| 33 | const MAX_SAMPLE_RATE_HZ: u32 = 0x7FFFFF; | ||
| 34 | |||
| 35 | /// Arbitrary unique identifier for the input unit. | ||
| 36 | const INPUT_UNIT_ID: u8 = 0x01; | ||
| 37 | |||
| 38 | /// Arbitrary unique identifier for the feature unit. | ||
| 39 | const FEATURE_UNIT_ID: u8 = 0x02; | ||
| 40 | |||
| 41 | /// Arbitrary unique identifier for the output unit. | ||
| 42 | const 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. | ||
| 46 | const VOLUME_STEPS_PER_DB: i16 = 256; | ||
| 47 | const MIN_VOLUME_DB: i16 = -100; | ||
| 48 | const MAX_VOLUME_DB: i16 = 0; | ||
| 49 | |||
| 50 | // Maximum number of supported discrete sample rates. | ||
| 51 | const 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))] | ||
| 56 | pub 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. | ||
| 64 | pub struct State<'d> { | ||
| 65 | control: Option<Control<'d>>, | ||
| 66 | shared: SharedControl<'d>, | ||
| 67 | } | ||
| 68 | |||
| 69 | impl<'d> Default for State<'d> { | ||
| 70 | fn default() -> Self { | ||
| 71 | Self::new() | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | impl<'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. | ||
| 86 | pub struct Speaker<'d, D: Driver<'d>> { | ||
| 87 | phantom: PhantomData<&'d D>, | ||
| 88 | } | ||
| 89 | |||
| 90 | impl<'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))] | ||
| 341 | pub 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 | |||
| 348 | impl 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 | |||
| 357 | struct 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. | ||
| 364 | struct 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 | |||
| 379 | impl<'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 | |||
| 391 | impl<'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. | ||
| 407 | pub struct Stream<'d, D: Driver<'d>> { | ||
| 408 | streaming_endpoint: D::EndpointOut, | ||
| 409 | } | ||
| 410 | |||
| 411 | impl<'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. | ||
| 424 | pub struct Feedback<'d, D: Driver<'d>> { | ||
| 425 | feedback_endpoint: D::EndpointIn, | ||
| 426 | } | ||
| 427 | |||
| 428 | impl<'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`]. | ||
| 444 | pub struct ControlMonitor<'d> { | ||
| 445 | shared: &'d SharedControl<'d>, | ||
| 446 | } | ||
| 447 | |||
| 448 | impl<'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 | |||
| 486 | impl<'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 | |||
| 712 | impl<'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 | } | ||
