usbd_audio/
lib.rs

1//! USB Audio class
2//!
3//! This crate provides a USB device class based on "Universal Serial Bus Device
4//! Class Definition for Audio Devices", Release 1.0 (experimental
5//! implementation without the aim of standard compliance).
6//!
7//! Since the USB descriptor can be quite large, it may be required to activate the feature
8//! `control-buffer-256` of the `usb-device` crate.
9//!
10//! Example
11//!
12//! ```ignore
13//! let mut usb_bus = ... // create a UsbBusAllocator in a platform specific way
14//!
15//! let mut usb_audio = AudioClassBuilder::new()
16//!     .input(
17//!         StreamConfig::new_discrete(
18//!             Format::S16le,
19//!             1,
20//!             &[48000],
21//!             TerminalType::InMicrophone).unwrap())
22//!     .output(
23//!         StreamConfig::new_discrete(
24//!             Format::S24le,
25//!             2,
26//!             &[44100, 48000, 96000],
27//!             TerminalType::OutSpeaker).unwrap())
28//!     .build(&usb_bus)
29//!     .unwrap();
30//! ```
31//!
32//! This example creates an audio device having a one channel (Mono) microphone
33//! with a fixed sampling frequency of 48 KHz and a two channel (Stereo) speaker
34//! output that supports three different sampling rates.
35#![no_std]
36
37use class_codes::*;
38use core::convert::From;
39use usb_device::control::{Recipient, Request, RequestType};
40use usb_device::device::DEFAULT_ALTERNATE_SETTING;
41use usb_device::endpoint::{Endpoint, EndpointDirection, In, Out};
42use usb_device::{class_prelude::*, UsbDirection};
43
44mod terminal_type;
45pub use terminal_type::TerminalType;
46mod class_codes;
47
48const ID_INPUT_TERMINAL: u8 = 0x01;
49const ID_OUTPUT_TERMINAL: u8 = 0x02;
50
51const MAX_ISO_EP_SIZE: u32 = 1023;
52
53#[derive(Clone, Copy, Debug)]
54pub enum Format {
55    /// Signed, 16 bits per subframe, little endian
56    S16le,
57    /// Signed, 24 bits per subframe, little endian
58    S24le,
59}
60
61/// Sampling rates that shall be supported by an steaming endpoint
62#[derive(Debug)]
63pub enum Rates<'a> {
64    /// A continuous range of sampling rates in samples/second defined by a
65    /// tuple including a minimum value and a maximum value. The maximum value
66    /// must be greater than the minimum value.
67    Continuous(u32, u32),
68    /// A set of discrete sampling rates in samples/second
69    Discrete(&'a [u32]),
70}
71
72#[derive(Debug)]
73pub struct StreamConfig<'a> {
74    format: Format,
75    channels: u8,
76    rates: Rates<'a>,
77    terminal_type: TerminalType,
78    /// ISO endpoint size calculated from format, channels and rates (may be
79    /// removed in future)
80    ep_size: u16,
81}
82
83impl StreamConfig<'_> {
84    /// Create a stream configuration with one or more discrete sampling rates
85    /// indicated in samples/second. An input stream or an output stream will
86    /// have an Input Terminal or Output Terminal of Terminal Type
87    /// `terminal_type`, respectively.
88    pub fn new_discrete(
89        format: Format,
90        channels: u8,
91        rates: &'_ [u32],
92        terminal_type: TerminalType,
93    ) -> Result<StreamConfig<'_>> {
94        let max_rate = rates.iter().max().unwrap();
95        let ep_size = Self::ep_size(format, channels, *max_rate)?;
96        let rates = Rates::Discrete(rates);
97        Ok(StreamConfig {
98            format,
99            channels,
100            rates,
101            terminal_type,
102            ep_size,
103        })
104    }
105
106    /// Create a stream configuration with a continuous range of supported
107    /// sampling rates indicated in samples/second. An input stream or an output
108    /// stream will have an Input Terminal or Output Terminal of Terminal Type
109    /// `terminal_type`, respectively.
110    pub fn new_continuous(
111        format: Format,
112        channels: u8,
113        min_rate: u32,
114        max_rate: u32,
115        terminal_type: TerminalType,
116    ) -> Result<StreamConfig<'static>> {
117        if min_rate >= max_rate {
118            return Err(Error::InvalidValue);
119        }
120        let ep_size = Self::ep_size(format, channels, max_rate)?;
121        let rates = Rates::Continuous(min_rate, max_rate);
122        Ok(StreamConfig {
123            format,
124            channels,
125            rates,
126            terminal_type,
127            ep_size,
128        })
129    }
130
131    /// calculate ISO endpoint size from format, channels and rates
132    fn ep_size(format: Format, channels: u8, max_rate: u32) -> Result<u16> {
133        let octets_per_frame = channels as u32
134            * match format {
135                Format::S16le => 2,
136                Format::S24le => 3,
137            };
138        let ep_size = octets_per_frame * max_rate / 1000;
139        if ep_size > MAX_ISO_EP_SIZE {
140            return Err(Error::BandwidthExceeded);
141        }
142        Ok(ep_size as u16)
143    }
144}
145
146/// USB audio errors, including possible USB Stack errors
147#[derive(Debug)]
148pub enum Error {
149    InvalidValue,
150    BandwidthExceeded,
151    StreamNotInitialized,
152    UsbError(usb_device::UsbError),
153}
154
155impl From<UsbError> for Error {
156    fn from(err: UsbError) -> Self {
157        Error::UsbError(err)
158    }
159}
160
161/// Result type alias for the USB Audio Class
162type Result<T> = core::result::Result<T, Error>;
163
164/// Internal state related to audio streaming in a certain direction
165struct AudioStream<'a, B: UsbBus, D: EndpointDirection> {
166    stream_config: StreamConfig<'a>,
167    interface: InterfaceNumber,
168    endpoint: Endpoint<'a, B, D>,
169    alt_setting: u8,
170}
171
172macro_rules! append {
173    ($iter:ident, $value:expr) => {
174        *($iter.next().ok_or(UsbError::BufferOverflow)?.1) = $value;
175    };
176}
177
178macro_rules! append_u24le {
179    ($iter:ident, $value:expr) => {
180        append!($iter, $value as u8);
181        append!($iter, ($value >> 8) as u8);
182        append!($iter, ($value >> 16) as u8);
183    };
184}
185
186impl<B: UsbBus, D: EndpointDirection> AudioStream<'_, B, D> {
187    fn write_ac_descriptors(&self, writer: &mut DescriptorWriter) -> usb_device::Result<()> {
188        let is_input = self.endpoint.address().direction() == UsbDirection::In;
189        let terminal_type: u16 = self.stream_config.terminal_type.into();
190        let id_offset = if is_input { 0 } else { 4 };
191
192        // write Input Terminal Descriptor (12 bytes)
193        let tt = if is_input {
194            terminal_type
195        } else {
196            TerminalType::UsbStreaming.into()
197        }
198        .to_le_bytes();
199
200        writer.write(
201            CS_INTERFACE,
202            &[
203                INPUT_TERMINAL,                // bDescriptorSubtype
204                ID_INPUT_TERMINAL + id_offset, // bTerminalID
205                tt[0],                         // wTerminalType
206                tt[1],
207                0x00,                        // bAssocTerminal
208                self.stream_config.channels, // bNrChannels
209                0x03,
210                0x00, // wChannelConfig: Left Front and Right Front
211                0x00, // iChannelNames
212                0x00, // iTerminal
213            ],
214        )?;
215
216        // write Output Terminal Descriptor (9 bytes)
217        let tt = if is_input {
218            TerminalType::UsbStreaming.into()
219        } else {
220            terminal_type
221        }
222        .to_le_bytes();
223        writer.write(
224            CS_INTERFACE,
225            &[
226                OUTPUT_TERMINAL,                // bDescriptorSubtype
227                ID_OUTPUT_TERMINAL + id_offset, // bTerminalID
228                tt[0],                          // wTerminalType
229                tt[1],
230                0x00,                          // bAssocTerminal
231                ID_INPUT_TERMINAL + id_offset, // bSourceID
232                0x00,                          // iTerminal
233            ],
234        )
235    }
236
237    fn write_as_and_ep_descriptors(&self, writer: &mut DescriptorWriter) -> usb_device::Result<()> {
238        let is_input = self.endpoint.address().direction() == UsbDirection::In;
239        let id_offset = if is_input { 0 } else { 4 };
240        // Standard AS Interface Descriptor (Alt. Set. 0)
241        writer.interface(self.interface, AUDIO, AUDIOSTREAMING, 0x00)?;
242
243        // Standard AS Interface Descriptor (Alt. Set. 1)
244        writer.interface_alt(self.interface, 0x01, AUDIO, AUDIOSTREAMING, 0x00, None)?;
245
246        // Class-specific AS General Interface Descriptor
247        let terminal_link = id_offset
248            + if is_input {
249                ID_OUTPUT_TERMINAL
250            } else {
251                ID_INPUT_TERMINAL
252            };
253        writer.write(
254            CS_INTERFACE,
255            &[
256                AS_GENERAL,    // bDescriptorSubtype:
257                terminal_link, // bTerminalLink
258                0x01,          // bDelay
259                PCM as u8,
260                (PCM >> 8) as u8, // wFormatTag
261            ],
262        )?;
263
264        // Type 1 Format Type Descriptor
265        let mut format_desc = [0x00u8; 128];
266        let mut iter = format_desc.iter_mut().enumerate();
267        append!(iter, FORMAT_TYPE); // bDescriptorSubtype;
268        append!(iter, FORMAT_TYPE_I); // bFormatType
269        append!(iter, self.stream_config.channels); // bNrChannels
270        append!(
271            iter,
272            match self.stream_config.format {
273                // bSubFrameSize
274                Format::S16le => 2,
275                Format::S24le => 3,
276            }
277        );
278        append!(
279            iter,
280            match self.stream_config.format {
281                // bBitResolution
282                Format::S16le => 16,
283                Format::S24le => 24,
284            }
285        );
286        match self.stream_config.rates {
287            Rates::Continuous(min, max) => {
288                append!(iter, 0x00); // bSamFreqType
289                append_u24le!(iter, min);
290                append_u24le!(iter, max);
291            }
292            Rates::Discrete(rates) => {
293                append!(iter, rates.len() as u8); // bSamFreqType
294                for rate in rates {
295                    append_u24le!(iter, *rate);
296                }
297            }
298        }
299        let length = iter.next().unwrap().0;
300        writer.write(CS_INTERFACE, &format_desc[..length])?;
301
302        // Standard Endpoint Descriptor
303        writer.endpoint(&self.endpoint)?;
304
305        // Class-specific Isoc. Audio Data Endpoint Descriptor
306        writer.write(
307            0x25,
308            &[
309                // bDescriptorType: CS_ENDPOINT
310                0x01, // bDescriptorSubtype: GENERAL
311                0x00, // bmAttributes
312                0x00, // bLockDelayUnits
313                0x00, 0x00, // wLockDelay
314            ],
315        )
316    }
317}
318
319/// Builder class to create an `AudioClass` structure.
320pub struct AudioClassBuilder<'a> {
321    input: Option<StreamConfig<'a>>,
322    output: Option<StreamConfig<'a>>,
323}
324
325impl<'a> AudioClassBuilder<'a> {
326    /// Create a new AudioClassBuilder
327    pub fn new() -> AudioClassBuilder<'static> {
328        AudioClassBuilder {
329            input: None,
330            output: None,
331        }
332    }
333
334    /// Configure the input audio stream according to a `StreamConfig`.
335    /// At most one input stream can be configured. When calling this method
336    /// multiple times, the last call matters.
337    pub fn input(self, input: StreamConfig<'a>) -> AudioClassBuilder<'a> {
338        AudioClassBuilder {
339            input: Some(input),
340            output: self.output,
341        }
342    }
343
344    /// Configure the output audio stream according to a `StreamConfig`.
345    /// At most one output stream can be configured. When calling this method
346    /// multiple times, the last call matters.
347    pub fn output(self, output: StreamConfig<'a>) -> AudioClassBuilder<'a> {
348        AudioClassBuilder {
349            input: self.input,
350            output: Some(output),
351        }
352    }
353
354    /// Create the `AudioClass` structure
355    pub fn build<B: UsbBus>(self, alloc: &'a UsbBusAllocator<B>) -> Result<AudioClass<'a, B>> {
356        let control_iface = alloc.interface();
357        let mut ac = AudioClass {
358            control_iface,
359            input: None,
360            output: None,
361        };
362        if let Some(stream_config) = self.input {
363            let interface = alloc.interface();
364            let endpoint = alloc.alloc(
365                None,
366                EndpointType::Isochronous {
367                    synchronization: IsochronousSynchronizationType::Asynchronous,
368                    usage: IsochronousUsageType::Data,
369                },
370                stream_config.ep_size,
371                1,
372            )?;
373            let alt_setting = DEFAULT_ALTERNATE_SETTING;
374            ac.input = Some(AudioStream {
375                stream_config,
376                interface,
377                endpoint,
378                alt_setting,
379            })
380        }
381
382        if let Some(stream_config) = self.output {
383            let interface = alloc.interface();
384            let endpoint = alloc.alloc(
385                None,
386                EndpointType::Isochronous {
387                    synchronization: IsochronousSynchronizationType::Adaptive,
388                    usage: IsochronousUsageType::Data,
389                },
390                stream_config.ep_size,
391                1,
392            )?;
393            let alt_setting = DEFAULT_ALTERNATE_SETTING;
394            ac.output = Some(AudioStream {
395                stream_config,
396                interface,
397                endpoint,
398                alt_setting,
399            })
400        }
401
402        Ok(ac)
403    }
404}
405
406/// USB device class for audio devices.
407///
408/// This device class based on the "Universal Serial Bus Device Class Definition
409/// for Audio Devices", Release 1.0. It supports one input stream and/or one
410/// output stream.
411pub struct AudioClass<'a, B: UsbBus> {
412    control_iface: InterfaceNumber,
413    input: Option<AudioStream<'a, B, In>>,
414    output: Option<AudioStream<'a, B, Out>>,
415}
416
417impl<B: UsbBus> AudioClass<'_, B> {
418    /// Read audio frames as output by the host. Returns an Error if no output
419    /// stream has been configured.
420    pub fn read(&self, data: &mut [u8]) -> Result<usize> {
421        if let Some(ref info) = self.output {
422            info.endpoint.read(data).map_err(Error::UsbError)
423        } else {
424            Err(Error::StreamNotInitialized)
425        }
426    }
427
428    /// Write audio frames to be input by the host. Returns an Error when no
429    /// input stream has been configured.
430    pub fn write(&self, data: &[u8]) -> Result<usize> {
431        if let Some(ref info) = self.input {
432            info.endpoint.write(data).map_err(Error::UsbError)
433        } else {
434            Err(Error::StreamNotInitialized)
435        }
436    }
437
438    /// Get current Alternate Setting of the input stream. Returns an error if
439    /// the stream is not configured.
440    pub fn input_alt_setting(&self) -> Result<u8> {
441        self.input
442            .as_ref()
443            .ok_or(Error::StreamNotInitialized)
444            .map(|si| si.alt_setting)
445    }
446
447    /// Get current Alternate Setting of the output stream. Returns an error if
448    /// the stream is not configured.
449    pub fn output_alt_setting(&self) -> Result<u8> {
450        self.output
451            .as_ref()
452            .ok_or(Error::StreamNotInitialized)
453            .map(|si| si.alt_setting)
454    }
455}
456
457impl<B: UsbBus> UsbClass<B> for AudioClass<'_, B> {
458    fn get_configuration_descriptors(
459        &self,
460        writer: &mut DescriptorWriter,
461    ) -> usb_device::Result<()> {
462        let mut in_collection = 0u8;
463        if self.input.is_some() {
464            in_collection += 1;
465        }
466        if self.output.is_some() {
467            in_collection += 1;
468        }
469
470        writer.iad(
471            self.control_iface,
472            in_collection + 1, // Number of interfaces: control + streaming
473            AUDIO,             // bFunctionClass
474            AUDIOCONTROL,
475            0x00, // bFunctionProtocol
476            None, // iFunction
477        )?;
478
479        // write Class-specific Audio Control (AC) Interface Descriptors
480        writer.interface(self.control_iface, AUDIO, AUDIOCONTROL, 0x00)?;
481
482        let total_length = 8u16 + (1 + 21) * in_collection as u16;
483
484        let mut ac_header = [
485            HEADER, // bDescriptorSubtype
486            0x00,
487            0x01, // bcdADC
488            total_length as u8,
489            (total_length >> 8) as u8, // wTotalLength
490            in_collection,             // number of AS interfaces
491            0x00,
492            0x00, // placeholders for baInterfaceNr
493        ];
494        let mut ndx = 6;
495        if let Some(ref input) = self.input {
496            ac_header[ndx] = input.interface.into();
497            ndx += 1;
498        }
499        if let Some(ref output) = self.output {
500            ac_header[ndx] = output.interface.into();
501            ndx += 1;
502        }
503        writer.write(CS_INTERFACE, &ac_header[..ndx])?;
504        if let Some(ref a) = self.input {
505            a.write_ac_descriptors(writer)?;
506        }
507        if let Some(ref a) = self.output {
508            a.write_ac_descriptors(writer)?;
509        }
510
511        // write Audio Streaming (AS) and endpoint (EP) descriptors
512        if let Some(ref a) = self.input {
513            a.write_as_and_ep_descriptors(writer)?;
514        }
515        if let Some(ref a) = self.output {
516            a.write_as_and_ep_descriptors(writer)?;
517        }
518        Ok(())
519    }
520
521    fn control_in(&mut self, xfer: ControlIn<B>) {
522        let req = xfer.request();
523        if req.request_type == RequestType::Standard
524            && req.recipient == Recipient::Interface
525            && req.request == Request::GET_INTERFACE
526            && req.length == 1
527        {
528            let iface = req.index as u8;
529            if let Some(info) = self.input.as_ref() {
530                if iface == info.interface.into() {
531                    xfer.accept_with(&[info.alt_setting]).ok();
532                    return;
533                }
534            }
535            if let Some(info) = self.output.as_ref() {
536                if iface == info.interface.into() {
537                    xfer.accept_with(&[info.alt_setting]).ok();
538                }
539            }
540        }
541    }
542
543    fn control_out(&mut self, xfer: ControlOut<B>) {
544        let req = xfer.request();
545        if req.request_type == RequestType::Standard
546            && req.recipient == Recipient::Interface
547            && req.request == Request::SET_INTERFACE
548        {
549            let iface = req.index as u8;
550            let alt_setting = req.value;
551
552            if let Some(info) = self.input.as_mut() {
553                if iface == info.interface.into() {
554                    info.alt_setting = alt_setting as u8;
555                    xfer.accept().ok();
556                    return;
557                }
558            }
559            if let Some(info) = self.output.as_mut() {
560                if iface == info.interface.into() {
561                    info.alt_setting = alt_setting as u8;
562                    xfer.accept().ok();
563                }
564            }
565        }
566    }
567}