Skip to main content

usb_gadget/function/
audio.rs

1//! USB Audio Class 1 (UAC1) and 2 (UAC2) functions.
2//!
3//! The Linux kernel configuration option `CONFIG_USB_CONFIGFS_F_UAC1` must be enabled for UAC1
4//! and `CONFIG_USB_CONFIGFS_F_UAC2` must be enabled for UAC2.
5//!
6//! # UAC1 Example
7//!
8//! ```no_run
9//! use usb_gadget::{
10//!     default_udc,
11//!     function::audio::{Channel, Uac1},
12//!     Class, Config, Gadget, Id, Strings,
13//! };
14//!
15//! // capture: stereo, 48000 Hz, 16 bit, playback: stereo, 48000 Hz, 16 bit
16//! let (audio, func) = Uac1::new(Channel::new(0b11, 48000, 2), Channel::new(0b11, 48000, 2));
17//!
18//! let udc = default_udc().expect("cannot get UDC");
19//! let reg = Gadget::new(
20//!     Class::INTERFACE_SPECIFIC,
21//!     Id::LINUX_FOUNDATION_COMPOSITE,
22//!     Strings::new("Clippy Manufacturer", "Rust UAC1", "RUST0123456"),
23//! )
24//! .with_config(Config::new("Audio Config 1").with_function(func))
25//! .bind(&udc)
26//! .expect("cannot bind to UDC");
27//!
28//! println!(
29//!     "UAC1 audio {} at {} to {} status {:?}",
30//!     reg.name().to_string_lossy(),
31//!     reg.path().display(),
32//!     udc.name().to_string_lossy(),
33//!     audio.status()
34//! );
35//! ```
36//!
37//! # UAC2 Example
38//!
39//! ```no_run
40//! use usb_gadget::{
41//!     default_udc,
42//!     function::audio::{Channel, Uac2},
43//!     Class, Config, Gadget, Id, Strings,
44//! };
45//!
46//! // capture: 8 ch, 48000 Hz, 24 bit, playback: 2 ch, 48000 Hz, 16 bit
47//! let (audio, func) =
48//!     Uac2::new(Channel::new(0b1111_1111, 48000, 24 / 8), Channel::new(0b11, 48000, 16 / 8));
49//!
50//! let udc = default_udc().expect("cannot get UDC");
51//! let reg = Gadget::new(
52//!     Class::INTERFACE_SPECIFIC,
53//!     Id::LINUX_FOUNDATION_COMPOSITE,
54//!     Strings::new("Clippy Manufacturer", "Rust UAC2", "RUST0123456"),
55//! )
56//! .with_config(Config::new("Audio Config 1").with_function(func))
57//! .bind(&udc)
58//! .expect("cannot bind to UDC");
59//!
60//! println!(
61//!     "UAC2 audio {} at {} to {} status {:?}",
62//!     reg.name().to_string_lossy(),
63//!     reg.path().display(),
64//!     udc.name().to_string_lossy(),
65//!     audio.status()
66//! );
67//! ```
68
69use std::{ffi::OsString, io::Result};
70
71use super::{
72    util::{FunctionDir, Status},
73    Function, Handle,
74};
75
76/// Audio channel configuration.
77#[derive(Debug, Clone, Default)]
78pub struct Channel {
79    /// Audio channel mask. Set to 0 to disable the audio endpoint.
80    ///
81    /// The audio channel mask is a bit mask of the audio channels. The mask is a 32-bit integer
82    /// with each bit representing a channel. The least significant bit is channel 1. The mask is
83    /// used to specify the audio channels that are present in the audio stream. For example, a
84    /// stereo stream would have a mask of 0x3 (channel 1 and channel 2).
85    pub channel_mask: Option<u32>,
86    /// Audio sample rate (Hz)
87    pub sample_rate: Option<u32>,
88    /// Audio sample size (bytes) so 2 bytes per sample (16 bit) would be 2.
89    pub sample_size: Option<u32>,
90}
91
92impl Channel {
93    /// Creates a new audio channel with the specified channel mask, sample rate (Hz), and sample
94    /// size (bytes).
95    pub fn new(channel_mask: u32, sample_rate: u32, sample_size: u32) -> Self {
96        Self { channel_mask: Some(channel_mask), sample_rate: Some(sample_rate), sample_size: Some(sample_size) }
97    }
98}
99
100/// Audio device configuration.
101///
102/// Fields are optional and will be set to f_uac2 default values if not specified, see
103/// drivers/usb/gadget/function/u_uac2.h. Not all fields are supported by all kernels; permission
104/// denied errors may occur if unsupported fields are set.
105#[derive(Debug, Clone, Default)]
106#[non_exhaustive]
107pub struct Uac2Config {
108    /// Audio channel configuration.
109    pub channel: Channel,
110    /// Audio sync type (capture only)
111    pub sync_type: Option<u32>,
112    /// Capture bInterval for HS/SS (1-4: fixed, 0: auto)
113    pub hs_interval: Option<u8>,
114    /// If channel has mute
115    pub mute_present: Option<bool>,
116    /// Terminal type
117    pub terminal_type: Option<u8>,
118    /// If channel has volume
119    pub volume_present: Option<bool>,
120    /// Minimum volume (in 1/256 dB)
121    pub volume_min: Option<i16>,
122    /// Maximum volume (in 1/256 dB)
123    pub volume_max: Option<i16>,
124    /// Resolution of volume control (in 1/256 dB)
125    pub volume_resolution: Option<i16>,
126    /// Name of the volume control function
127    pub volume_name: Option<String>,
128    /// Name of the input terminal
129    pub input_terminal_name: Option<String>,
130    /// Name of the input terminal channel
131    pub input_terminal_channel_name: Option<String>,
132    /// Name of the output terminal
133    pub output_terminal_name: Option<String>,
134}
135
136/// Builder for USB audio class 2 (UAC2) function.
137///
138/// Set capture or playback channel_mask to 0 to disable the audio endpoint.
139#[derive(Debug, Clone, Default)]
140#[non_exhaustive]
141pub struct Uac2Builder {
142    /// Audio capture configuration.
143    pub capture: Uac2Config,
144    /// Audio playback configuration.
145    pub playback: Uac2Config,
146    /// Maximum extra bandwidth in async mode
147    pub fb_max: Option<u32>,
148    /// The number of pre-allocated request for both capture and playback
149    pub request_number: Option<u32>,
150    /// The name of the interface
151    pub function_name: Option<String>,
152    /// Topology control name
153    pub control_name: Option<String>,
154    /// The name of the input clock source
155    pub clock_source_in_name: Option<String>,
156    /// The name of the output clock source
157    pub clock_source_out_name: Option<String>,
158}
159
160impl Uac2Builder {
161    /// Build the USB function.
162    ///
163    /// The returned handle must be added to a USB gadget configuration.
164    #[must_use]
165    pub fn build(self) -> (Uac2, Handle) {
166        let dir = FunctionDir::new();
167        (Uac2 { dir: dir.clone() }, Handle::new(Uac2Function { builder: self, dir }))
168    }
169
170    /// Set audio capture configuration.
171    #[must_use]
172    pub fn with_capture_config(mut self, capture: Uac2Config) -> Self {
173        self.capture = capture;
174        self
175    }
176
177    /// Set audio playback configuration.
178    #[must_use]
179    pub fn with_playback_config(mut self, playback: Uac2Config) -> Self {
180        self.playback = playback;
181        self
182    }
183}
184
185#[derive(Debug)]
186struct Uac2Function {
187    builder: Uac2Builder,
188    dir: FunctionDir,
189}
190
191impl Function for Uac2Function {
192    fn driver(&self) -> OsString {
193        "uac2".into()
194    }
195
196    fn dir(&self) -> FunctionDir {
197        self.dir.clone()
198    }
199
200    fn register(&self) -> Result<()> {
201        // capture
202        if let Some(channel_mask) = self.builder.capture.channel.channel_mask {
203            self.dir.write("c_chmask", channel_mask.to_string())?;
204        }
205        if let Some(sample_rate) = self.builder.capture.channel.sample_rate {
206            self.dir.write("c_srate", sample_rate.to_string())?;
207        }
208        if let Some(sample_size) = self.builder.capture.channel.sample_size {
209            self.dir.write("c_ssize", sample_size.to_string())?;
210        }
211        if let Some(sync_type) = self.builder.capture.sync_type {
212            self.dir.write("c_sync", sync_type.to_string())?;
213        }
214        if let Some(hs_interval) = self.builder.capture.hs_interval {
215            self.dir.write("c_hs_bint", hs_interval.to_string())?;
216        }
217        if let Some(mute_present) = self.builder.capture.mute_present {
218            self.dir.write("c_mute_present", (mute_present as u8).to_string())?;
219        }
220        if let Some(volume_present) = self.builder.capture.volume_present {
221            self.dir.write("c_volume_present", (volume_present as u8).to_string())?;
222        }
223        if let Some(volume_min) = self.builder.capture.volume_min {
224            self.dir.write("c_volume_min", volume_min.to_string())?;
225        }
226        if let Some(volume_max) = self.builder.capture.volume_max {
227            self.dir.write("c_volume_max", volume_max.to_string())?;
228        }
229        if let Some(volume_resolution) = self.builder.capture.volume_resolution {
230            self.dir.write("c_volume_res", volume_resolution.to_string())?;
231        }
232        if let Some(volume_name) = &self.builder.capture.volume_name {
233            self.dir.write("c_fu_vol_name", volume_name)?;
234        }
235        if let Some(terminal_type) = self.builder.capture.terminal_type {
236            self.dir.write("c_terminal_type", terminal_type.to_string())?;
237        }
238        if let Some(input_terminal_name) = &self.builder.capture.input_terminal_name {
239            self.dir.write("c_it_name", input_terminal_name)?;
240        }
241        if let Some(input_terminal_channel_name) = &self.builder.capture.input_terminal_channel_name {
242            self.dir.write("c_it_ch_name", input_terminal_channel_name)?;
243        }
244        if let Some(output_terminal_name) = &self.builder.capture.output_terminal_name {
245            self.dir.write("c_ot_name", output_terminal_name)?;
246        }
247
248        // playback
249        if let Some(channel_mask) = self.builder.playback.channel.channel_mask {
250            self.dir.write("p_chmask", channel_mask.to_string())?;
251        }
252        if let Some(sample_rate) = self.builder.playback.channel.sample_rate {
253            self.dir.write("p_srate", sample_rate.to_string())?;
254        }
255        if let Some(sample_size) = self.builder.playback.channel.sample_size {
256            self.dir.write("p_ssize", sample_size.to_string())?;
257        }
258        if let Some(hs_interval) = self.builder.playback.hs_interval {
259            self.dir.write("p_hs_bint", hs_interval.to_string())?;
260        }
261        if let Some(mute_present) = self.builder.playback.mute_present {
262            self.dir.write("p_mute_present", (mute_present as u8).to_string())?;
263        }
264        if let Some(volume_present) = self.builder.playback.volume_present {
265            self.dir.write("p_volume_present", (volume_present as u8).to_string())?;
266        }
267        if let Some(volume_min) = self.builder.playback.volume_min {
268            self.dir.write("p_volume_min", volume_min.to_string())?;
269        }
270        if let Some(volume_max) = self.builder.playback.volume_max {
271            self.dir.write("p_volume_max", volume_max.to_string())?;
272        }
273        if let Some(volume_resolution) = self.builder.playback.volume_resolution {
274            self.dir.write("p_volume_res", volume_resolution.to_string())?;
275        }
276        if let Some(volume_name) = &self.builder.playback.volume_name {
277            self.dir.write("p_fu_vol_name", volume_name)?;
278        }
279        if let Some(terminal_type) = self.builder.playback.terminal_type {
280            self.dir.write("p_terminal_type", terminal_type.to_string())?;
281        }
282        if let Some(input_terminal_name) = &self.builder.playback.input_terminal_name {
283            self.dir.write("p_it_name", input_terminal_name)?;
284        }
285        if let Some(input_terminal_channel_name) = &self.builder.playback.input_terminal_channel_name {
286            self.dir.write("p_it_ch_name", input_terminal_channel_name)?;
287        }
288        if let Some(output_terminal_name) = &self.builder.playback.output_terminal_name {
289            self.dir.write("p_ot_name", output_terminal_name)?;
290        }
291
292        // general
293        if let Some(fb_max) = self.builder.fb_max {
294            self.dir.write("fb_max", fb_max.to_string())?;
295        }
296        if let Some(request_number) = self.builder.request_number {
297            self.dir.write("req_number", request_number.to_string())?;
298        }
299        if let Some(function_name) = &self.builder.function_name {
300            self.dir.write("function_name", function_name)?;
301        }
302        if let Some(control_name) = &self.builder.control_name {
303            self.dir.write("if_ctrl_name", control_name)?;
304        }
305        if let Some(clock_source_in_name) = &self.builder.clock_source_in_name {
306            self.dir.write("clksrc_in_name", clock_source_in_name)?;
307        }
308        if let Some(clock_source_out_name) = &self.builder.clock_source_out_name {
309            self.dir.write("clksrc_out_name", clock_source_out_name)?;
310        }
311
312        Ok(())
313    }
314}
315
316/// USB Audio Class 2 (UAC2) function.
317#[derive(Debug)]
318pub struct Uac2 {
319    dir: FunctionDir,
320}
321
322impl Uac2 {
323    /// Creates a new USB Audio Class 2 (UAC2) builder with g_uac2 audio defaults.
324    pub fn builder() -> Uac2Builder {
325        Uac2Builder::default()
326    }
327
328    /// Creates a new USB Audio Class 2 (UAC2) function with the specified capture and playback
329    /// channels.
330    pub fn new(capture: Channel, playback: Channel) -> (Uac2, Handle) {
331        let mut builder = Uac2Builder::default();
332        builder.capture.channel = capture;
333        builder.playback.channel = playback;
334        builder.build()
335    }
336
337    /// Access to registration status.
338    pub fn status(&self) -> Status {
339        self.dir.status()
340    }
341}
342
343/// Audio device configuration for UAC1.
344///
345/// Fields are optional and will be set to f_uac1 default values if not specified, see
346/// `drivers/usb/gadget/function/u_uac1.h`. Not all fields are supported by all kernels; permission
347/// denied errors may occur if unsupported fields are set.
348#[derive(Debug, Clone, Default)]
349#[non_exhaustive]
350pub struct Uac1Config {
351    /// Audio channel configuration.
352    pub channel: Channel,
353    /// If channel has mute
354    pub mute_present: Option<bool>,
355    /// If channel has volume
356    pub volume_present: Option<bool>,
357    /// Minimum volume (in 1/256 dB)
358    pub volume_min: Option<i16>,
359    /// Maximum volume (in 1/256 dB)
360    pub volume_max: Option<i16>,
361    /// Resolution of volume control (in 1/256 dB)
362    pub volume_resolution: Option<i16>,
363    /// Name of the volume control function
364    pub volume_name: Option<String>,
365    /// Name of the input terminal
366    pub input_terminal_name: Option<String>,
367    /// Name of the input terminal channel
368    pub input_terminal_channel_name: Option<String>,
369    /// Name of the output terminal
370    pub output_terminal_name: Option<String>,
371}
372
373/// Builder for USB audio class 1 (UAC1) function.
374///
375/// Set capture or playback channel_mask to 0 to disable the audio endpoint.
376#[derive(Debug, Clone, Default)]
377#[non_exhaustive]
378pub struct Uac1Builder {
379    /// Audio capture configuration.
380    pub capture: Uac1Config,
381    /// Audio playback configuration.
382    pub playback: Uac1Config,
383    /// The number of pre-allocated requests for both capture and playback
384    pub request_number: Option<u32>,
385    /// The name of the interface
386    pub function_name: Option<String>,
387}
388
389impl Uac1Builder {
390    /// Build the USB function.
391    ///
392    /// The returned handle must be added to a USB gadget configuration.
393    #[must_use]
394    pub fn build(self) -> (Uac1, Handle) {
395        let dir = FunctionDir::new();
396        (Uac1 { dir: dir.clone() }, Handle::new(Uac1Function { builder: self, dir }))
397    }
398
399    /// Set audio capture configuration.
400    #[must_use]
401    pub fn with_capture_config(mut self, capture: Uac1Config) -> Self {
402        self.capture = capture;
403        self
404    }
405
406    /// Set audio playback configuration.
407    #[must_use]
408    pub fn with_playback_config(mut self, playback: Uac1Config) -> Self {
409        self.playback = playback;
410        self
411    }
412}
413
414#[derive(Debug)]
415struct Uac1Function {
416    builder: Uac1Builder,
417    dir: FunctionDir,
418}
419
420impl Function for Uac1Function {
421    fn driver(&self) -> OsString {
422        "uac1".into()
423    }
424
425    fn dir(&self) -> FunctionDir {
426        self.dir.clone()
427    }
428
429    fn register(&self) -> Result<()> {
430        // capture
431        if let Some(channel_mask) = self.builder.capture.channel.channel_mask {
432            self.dir.write("c_chmask", channel_mask.to_string())?;
433        }
434        if let Some(sample_rate) = self.builder.capture.channel.sample_rate {
435            self.dir.write("c_srate", sample_rate.to_string())?;
436        }
437        if let Some(sample_size) = self.builder.capture.channel.sample_size {
438            self.dir.write("c_ssize", sample_size.to_string())?;
439        }
440        if let Some(mute_present) = self.builder.capture.mute_present {
441            self.dir.write("c_mute_present", (mute_present as u8).to_string())?;
442        }
443        if let Some(volume_present) = self.builder.capture.volume_present {
444            self.dir.write("c_volume_present", (volume_present as u8).to_string())?;
445        }
446        if let Some(volume_min) = self.builder.capture.volume_min {
447            self.dir.write("c_volume_min", volume_min.to_string())?;
448        }
449        if let Some(volume_max) = self.builder.capture.volume_max {
450            self.dir.write("c_volume_max", volume_max.to_string())?;
451        }
452        if let Some(volume_resolution) = self.builder.capture.volume_resolution {
453            self.dir.write("c_volume_res", volume_resolution.to_string())?;
454        }
455        if let Some(volume_name) = &self.builder.capture.volume_name {
456            self.dir.write("c_fu_vol_name", volume_name)?;
457        }
458        if let Some(input_terminal_name) = &self.builder.capture.input_terminal_name {
459            self.dir.write("c_it_name", input_terminal_name)?;
460        }
461        if let Some(input_terminal_channel_name) = &self.builder.capture.input_terminal_channel_name {
462            self.dir.write("c_it_ch_name", input_terminal_channel_name)?;
463        }
464        if let Some(output_terminal_name) = &self.builder.capture.output_terminal_name {
465            self.dir.write("c_ot_name", output_terminal_name)?;
466        }
467
468        // playback
469        if let Some(channel_mask) = self.builder.playback.channel.channel_mask {
470            self.dir.write("p_chmask", channel_mask.to_string())?;
471        }
472        if let Some(sample_rate) = self.builder.playback.channel.sample_rate {
473            self.dir.write("p_srate", sample_rate.to_string())?;
474        }
475        if let Some(sample_size) = self.builder.playback.channel.sample_size {
476            self.dir.write("p_ssize", sample_size.to_string())?;
477        }
478        if let Some(mute_present) = self.builder.playback.mute_present {
479            self.dir.write("p_mute_present", (mute_present as u8).to_string())?;
480        }
481        if let Some(volume_present) = self.builder.playback.volume_present {
482            self.dir.write("p_volume_present", (volume_present as u8).to_string())?;
483        }
484        if let Some(volume_min) = self.builder.playback.volume_min {
485            self.dir.write("p_volume_min", volume_min.to_string())?;
486        }
487        if let Some(volume_max) = self.builder.playback.volume_max {
488            self.dir.write("p_volume_max", volume_max.to_string())?;
489        }
490        if let Some(volume_resolution) = self.builder.playback.volume_resolution {
491            self.dir.write("p_volume_res", volume_resolution.to_string())?;
492        }
493        if let Some(volume_name) = &self.builder.playback.volume_name {
494            self.dir.write("p_fu_vol_name", volume_name)?;
495        }
496        if let Some(input_terminal_name) = &self.builder.playback.input_terminal_name {
497            self.dir.write("p_it_name", input_terminal_name)?;
498        }
499        if let Some(input_terminal_channel_name) = &self.builder.playback.input_terminal_channel_name {
500            self.dir.write("p_it_ch_name", input_terminal_channel_name)?;
501        }
502        if let Some(output_terminal_name) = &self.builder.playback.output_terminal_name {
503            self.dir.write("p_ot_name", output_terminal_name)?;
504        }
505
506        // general
507        if let Some(request_number) = self.builder.request_number {
508            self.dir.write("req_number", request_number.to_string())?;
509        }
510        if let Some(function_name) = &self.builder.function_name {
511            self.dir.write("function_name", function_name)?;
512        }
513
514        Ok(())
515    }
516}
517
518/// USB Audio Class 1 (UAC1) function.
519///
520/// UAC1 is widely supported by hosts including car stereos, older Macs, game consoles, and
521/// embedded systems that may not support UAC2.
522#[derive(Debug)]
523pub struct Uac1 {
524    dir: FunctionDir,
525}
526
527impl Uac1 {
528    /// Creates a new USB Audio Class 1 (UAC1) builder with f_uac1 audio defaults.
529    pub fn builder() -> Uac1Builder {
530        Uac1Builder::default()
531    }
532
533    /// Creates a new USB Audio Class 1 (UAC1) function with the specified capture and playback
534    /// channels.
535    pub fn new(capture: Channel, playback: Channel) -> (Uac1, Handle) {
536        let mut builder = Uac1Builder::default();
537        builder.capture.channel = capture;
538        builder.playback.channel = playback;
539        builder.build()
540    }
541
542    /// Access to registration status.
543    pub fn status(&self) -> Status {
544        self.dir.status()
545    }
546}