refactoring and allow &mut calls of AudioClass

This commit is contained in:
2026-05-07 01:29:41 -07:00
parent 648b4344a8
commit 3d862e3b46
+76 -39
View File
@@ -6,18 +6,16 @@ mod cursor;
pub mod descriptors; pub mod descriptors;
mod log; mod log;
use core::cell::OnceCell;
use core::cmp::Ordering; use core::cmp::Ordering;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::AtomicUsize; use core::sync::atomic::AtomicUsize;
use byteorder_embedded_io::{LittleEndian, WriteBytesExt}; use byteorder_embedded_io::{LittleEndian, ReadBytesExt, WriteBytesExt};
use constants::*; use constants::*;
use descriptors::*; use descriptors::*;
use log::*; use log::*;
use modular_bitfield::prelude::*; use num_traits::ConstZero;
use num_traits::{ConstZero, Zero};
use usb_device::control::{Recipient, Request, RequestType}; use usb_device::control::{Recipient, Request, RequestType};
use usb_device::device::DEFAULT_ALTERNATE_SETTING; use usb_device::device::DEFAULT_ALTERNATE_SETTING;
use usb_device::endpoint::{self, Endpoint, EndpointDirection, In, Out}; use usb_device::endpoint::{self, Endpoint, EndpointDirection, In, Out};
@@ -163,7 +161,7 @@ impl UsbIsochronousFeedback {
pub trait UsbAudioClass<'a, B: UsbBus> { pub trait UsbAudioClass<'a, B: UsbBus> {
/// Called when audio data is received from the host. `ep` is ready for /// Called when audio data is received from the host. `ep` is ready for
/// `ep.read()`. /// `ep.read()`.
fn audio_data_rx(&self, ep: &Endpoint<'a, B, endpoint::Out>) {} fn audio_data_rx(&mut self, ep: &Endpoint<'a, B, endpoint::Out>) {}
/// Called when it's time to send an isochronous feedback update. Should /// Called when it's time to send an isochronous feedback update. Should
/// return the correct feedback payload. Should not be considered a great /// return the correct feedback payload. Should not be considered a great
@@ -172,20 +170,14 @@ pub trait UsbAudioClass<'a, B: UsbBus> {
/// ///
/// Required for isochronous asynchronous mode to work properly. If None is /// Required for isochronous asynchronous mode to work properly. If None is
/// returned, no IN packet will be emitted at feedback time. /// returned, no IN packet will be emitted at feedback time.
fn feedback(&self) -> Option<UsbIsochronousFeedback> { fn feedback(&mut self) -> Option<UsbIsochronousFeedback> {
None None
} }
/// Called when the alternate setting of `terminal`'s interface is changed, /// Called when the alternate setting of `terminal`'s interface is changed,
/// before the `AudioStream` is updated. Currently not very useful since we /// before the `AudioStream` is updated. Currently not very useful since we
/// don't implement alternate settings. /// don't implement alternate settings.
fn alternate_setting_changed<CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>( fn alternate_setting_changed(&mut self, terminal: UsbDirection, alt_setting: u8) {}
&self,
ac: &mut AudioClass<'a, B, CS, AU>,
terminal: UsbDirection,
alt_setting: u8,
) {
}
} }
/// A trait for implementing Sampling Frequency Control for USB Audio Clock Sources /// A trait for implementing Sampling Frequency Control for USB Audio Clock Sources
@@ -201,8 +193,8 @@ pub trait UsbAudioClockImpl {
const SOF_SYNC: bool; const SOF_SYNC: bool;
/// Called when the host requests the current sample rate. Returns the sample rate in Hz. /// Called when the host requests the current sample rate. Returns the sample rate in Hz.
fn get_sample_rate(&self) -> core::result::Result<u32, UsbAudioClassError>; fn get_sample_rate(&self) -> core::result::Result<u32, UsbAudioClassError>;
/// Called when the host requests to set the sample rate. Should reconfigure the clock source /// Called when the host requests to set the sample rate. Not necessarily called at all startups,
/// if necessary. /// so alt_setting should start/stop the clock. Not required for 'fixed' clocks.
fn set_sample_rate( fn set_sample_rate(
&mut self, &mut self,
sample_rate: u32, sample_rate: u32,
@@ -238,6 +230,13 @@ pub trait UsbAudioClockImpl {
/// ref: USB Audio Class Specification 2.0 5.2.1 & 5.2.3.3 /// ref: USB Audio Class Specification 2.0 5.2.1 & 5.2.3.3
fn get_rates(&self) -> core::result::Result<&[RangeEntry<u32>], UsbAudioClassError>; fn get_rates(&self) -> core::result::Result<&[RangeEntry<u32>], UsbAudioClassError>;
/// Called when the audio device's AltSetting is changed. Usually 0 signals shutdown of the
/// streaming audio and 1 signals start of streaming. This should be used to start the clock
/// (and stop it if desired). If unimplemented, does nothing - keep the clock running at all times.
fn alt_setting(&mut self, alt_setting: u8) -> core::result::Result<(), UsbAudioClassError> {
Ok(())
}
/// Build the ClockSource descriptor. It is not intended to override this method. /// Build the ClockSource descriptor. It is not intended to override this method.
/// ///
/// Assumes access control based on clock type. Internal fixed/variable are read only, /// Assumes access control based on clock type. Internal fixed/variable are read only,
@@ -320,7 +319,7 @@ impl<D: EndpointDirection> TerminalConfig<D> {
self.format.bytes_per_sample as u32 * self.num_channels as u32 self.format.bytes_per_sample as u32 * self.num_channels as u32
} }
} }
impl<'a> TerminalConfigurationDescriptors for TerminalConfig<In> { impl<'a> TerminalConfigurationDescriptors for TerminalConfig<Out> {
fn get_configuration_descriptors(&self) -> (InputTerminal, OutputTerminal) { fn get_configuration_descriptors(&self) -> (InputTerminal, OutputTerminal) {
let input_terminal = InputTerminal { let input_terminal = InputTerminal {
id: self.base_id, id: self.base_id,
@@ -357,7 +356,7 @@ impl<'a> TerminalConfigurationDescriptors for TerminalConfig<In> {
// fn get_interface_descriptor(&self, id: InterfaceIndex) ) // fn get_interface_descriptor(&self, id: InterfaceIndex) )
} }
impl<'a> TerminalConfigurationDescriptors for TerminalConfig<Out> { impl<'a> TerminalConfigurationDescriptors for TerminalConfig<In> {
fn get_configuration_descriptors(&self) -> (InputTerminal, OutputTerminal) { fn get_configuration_descriptors(&self) -> (InputTerminal, OutputTerminal) {
let output_terminal = OutputTerminal { let output_terminal = OutputTerminal {
id: self.base_id, id: self.base_id,
@@ -422,10 +421,10 @@ pub enum UsbSpeed {
pub struct AudioClassConfig<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> { pub struct AudioClassConfig<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> {
pub speed: UsbSpeed, pub speed: UsbSpeed,
pub device_category: FunctionCode, pub device_category: FunctionCode,
pub clock_impl: &'a CS, pub clock_impl: &'a mut CS,
pub audio_impl: &'a AU, pub audio_impl: &'a mut AU,
pub input_config: Option<TerminalConfig<Out>>, pub input_config: Option<TerminalConfig<In>>,
pub output_config: Option<TerminalConfig<In>>, pub output_config: Option<TerminalConfig<Out>>,
pub additional_descriptors: Option<&'a [AudioClassDescriptor]>, pub additional_descriptors: Option<&'a [AudioClassDescriptor]>,
_bus: PhantomData<B>, _bus: PhantomData<B>,
} }
@@ -436,8 +435,8 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
pub fn new( pub fn new(
speed: UsbSpeed, speed: UsbSpeed,
device_category: FunctionCode, device_category: FunctionCode,
clock_impl: &'a CS, clock_impl: &'a mut CS,
audio_impl: &'a AU, audio_impl: &'a mut AU,
) -> Self { ) -> Self {
Self { Self {
speed, speed,
@@ -450,11 +449,11 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
_bus: PhantomData, _bus: PhantomData,
} }
} }
pub fn with_input_config(mut self, input_config: TerminalConfig<Out>) -> Self { pub fn with_input_config(mut self, input_config: TerminalConfig<In>) -> Self {
self.input_config = Some(input_config); self.input_config = Some(input_config);
self self
} }
pub fn with_output_config(mut self, output_config: TerminalConfig<In>) -> Self { pub fn with_output_config(mut self, output_config: TerminalConfig<Out>) -> Self {
self.output_config = Some(output_config); self.output_config = Some(output_config);
self self
} }
@@ -516,10 +515,10 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
interval, interval,
); );
let alt_setting = DEFAULT_ALTERNATE_SETTING; let alt_setting = DEFAULT_ALTERNATE_SETTING;
ac.in_iface = interface.into(); ac.out_iface = interface.into();
ac.in_ep = endpoint.address().index(); ac.out_ep = endpoint.address().index();
ac.fb_ep = feedback_ep.address().index(); ac.fb_ep = feedback_ep.address().index();
ac.input = Some(AudioStream { ac.output = Some(AudioStream {
config, config,
interface, interface,
endpoint, endpoint,
@@ -537,9 +536,10 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
interval, interval,
); );
let alt_setting = DEFAULT_ALTERNATE_SETTING; let alt_setting = DEFAULT_ALTERNATE_SETTING;
ac.out_iface = interface.into(); ac.in_iface = interface.into();
ac.out_ep = endpoint.address().index(); ac.in_ep = endpoint.address().index();
ac.output = Some(AudioStream {
ac.input = Some(AudioStream {
config, config,
interface, interface,
endpoint, endpoint,
@@ -651,8 +651,8 @@ impl<'a, B: UsbBus, D: EndpointDirection> AudioStream<'a, B, D> {
pub struct AudioClass<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> { pub struct AudioClass<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> {
control_iface: InterfaceNumber, control_iface: InterfaceNumber,
clock_impl: &'a CS, clock_impl: &'a mut CS,
audio_impl: &'a AU, audio_impl: &'a mut AU,
output: Option<AudioStream<'a, B, Out>>, output: Option<AudioStream<'a, B, Out>>,
input: Option<AudioStream<'a, B, In>>, input: Option<AudioStream<'a, B, In>>,
feedback: Option<Endpoint<'a, B, In>>, feedback: Option<Endpoint<'a, B, In>>,
@@ -675,7 +675,7 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> UsbClass<B>
) -> usb_device::Result<()> { ) -> usb_device::Result<()> {
info!(" AudioClass::get_configuration_descriptors"); info!(" AudioClass::get_configuration_descriptors");
// Control + 0-2 streaming // Control + 0-2 streaming
let n_interfaces = 1 + (self.input.is_some() as u8) + (self.input.is_some() as u8); let n_interfaces = 1 + (self.input.is_some() as u8) + (self.output.is_some() as u8);
debug!("writer.iad()"); debug!("writer.iad()");
// UAC2 4.6 Interface Association Descriptor // UAC2 4.6 Interface Association Descriptor
@@ -835,12 +835,15 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> UsbClass<B>
fn poll(&mut self) { fn poll(&mut self) {
debug!("poll"); debug!("poll");
// no streaming in alt 0 // no streaming in alt 0
if self.output.as_ref().unwrap().alt_setting != 1 { if self.output.as_ref().is_none_or(|o| o.alt_setting != 0)
|| self.input.as_ref().is_none_or(|i| i.alt_setting != 0)
{
return; return;
} }
loop { loop {
if let Some(o) = self.output.as_ref() {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
match self.output.as_ref().unwrap().endpoint.read(&mut buf) { match o.endpoint.read(&mut buf) {
Ok(len) if len > 0 => { Ok(len) if len > 0 => {
debug!("EP OUT data {:?}", len); debug!("EP OUT data {:?}", len);
} }
@@ -856,6 +859,7 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> UsbClass<B>
} }
} }
} }
}
impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<'a, B, CS, AU> { impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<'a, B, CS, AU> {
fn standard_request_out(&mut self, xfer: ControlOut<B>) { fn standard_request_out(&mut self, xfer: ControlOut<B>) {
@@ -917,16 +921,18 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<
if self.input.is_some() && iface == self.in_iface { if self.input.is_some() && iface == self.in_iface {
let old_alt = self.input.as_ref().unwrap().alt_setting; let old_alt = self.input.as_ref().unwrap().alt_setting;
if old_alt != alt_setting { if old_alt != alt_setting {
self.clock_impl.alt_setting(alt_setting).ok();
self.audio_impl self.audio_impl
.alternate_setting_changed(self, UsbDirection::In, alt_setting); .alternate_setting_changed(UsbDirection::In, alt_setting);
self.input.as_mut().unwrap().alt_setting = alt_setting; self.input.as_mut().unwrap().alt_setting = alt_setting;
xfer.accept().ok(); xfer.accept().ok();
} }
} else if self.output.is_some() && iface == self.out_iface { } else if self.output.is_some() && iface == self.out_iface {
let old_alt = self.output.as_ref().unwrap().alt_setting; let old_alt = self.output.as_ref().unwrap().alt_setting;
if old_alt != alt_setting { if old_alt != alt_setting {
self.clock_impl.alt_setting(alt_setting).ok();
self.audio_impl self.audio_impl
.alternate_setting_changed(self, UsbDirection::Out, alt_setting); .alternate_setting_changed(UsbDirection::Out, alt_setting);
self.output.as_mut().unwrap().alt_setting = alt_setting; self.output.as_mut().unwrap().alt_setting = alt_setting;
xfer.accept().ok(); xfer.accept().ok();
} }
@@ -1023,6 +1029,10 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<
channel: u8, channel: u8,
control: u8, control: u8,
) { ) {
match entity {
1 => return self.set_clock_cur(xfer, channel, control),
_ => {}
}
debug!(" Unimplemented."); debug!(" Unimplemented.");
} }
@@ -1131,7 +1141,8 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<
Ok(valid) => { Ok(valid) => {
debug!(" {}", valid); debug!(" {}", valid);
buf.write_u8(valid as u8) buf.write_u8(valid as u8)
.map_err(|_e| UsbError::BufferOverflow)?; .map_err(|_e| UsbError::BufferOverflow)
.ok();
Ok(1) Ok(1)
} }
Err(_e) => Err(UsbError::InvalidState), Err(_e) => Err(UsbError::InvalidState),
@@ -1143,6 +1154,32 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<
} }
} }
} }
fn set_clock_cur(&mut self, xfer: ControlOut<B>, channel: u8, control: u8) {
match control.try_into() {
Ok(ClockSourceControlSelector::SamFreqControl) => {
debug!(" SamplingFreqControl");
if channel != 0 {
error!(
" Invalid channel {} for SamplingFreqControl GET CUR. Ignoring.",
channel
);
}
match xfer.data().read_u32::<LittleEndian>() {
Ok(rate) => {
debug!(" SET SamplingFreqControl CUR {}", rate);
self.clock_impl.set_sample_rate(rate).ok();
xfer.accept().ok();
}
Err(e) => {
error!(" SET SamplingFreqControl CUR ERROR BAD DATA");
}
}
}
_ => {
debug!(" Unimplemented.");
}
}
}
fn get_clock_range(&mut self, xfer: ControlIn<B>, channel: u8, control: u8) { fn get_clock_range(&mut self, xfer: ControlIn<B>, channel: u8, control: u8) {
match control.try_into() { match control.try_into() {
Ok(ClockSourceControlSelector::SamFreqControl) => { Ok(ClockSourceControlSelector::SamFreqControl) => {