Compare commits
2 Commits
e2edb1d468
...
a82120169f
| Author | SHA1 | Date | |
|---|---|---|---|
|
a82120169f
|
|||
|
066c5dbf96
|
+45
-28
@@ -15,7 +15,7 @@ use constants::*;
|
|||||||
use descriptors::*;
|
use descriptors::*;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use num_traits::ConstZero;
|
use num_traits::{ConstZero, ToPrimitive};
|
||||||
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};
|
||||||
@@ -115,6 +115,10 @@ impl UsbIsochronousFeedback {
|
|||||||
pub fn new_frac(int: u16, frac: u16) -> Self {
|
pub fn new_frac(int: u16, frac: u16) -> Self {
|
||||||
Self { int, frac }
|
Self { int, frac }
|
||||||
}
|
}
|
||||||
|
pub fn new_float(rate: f32) -> Self {
|
||||||
|
let fb = (rate * 65536.0 + 0.5) as u32;
|
||||||
|
Self::new(fb)
|
||||||
|
}
|
||||||
/// Assumed 16.16, not either of the USB formats
|
/// Assumed 16.16, not either of the USB formats
|
||||||
pub fn new(value: u32) -> Self {
|
pub fn new(value: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -487,6 +491,10 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
|
|||||||
.max;
|
.max;
|
||||||
let control_iface = alloc.interface();
|
let control_iface = alloc.interface();
|
||||||
|
|
||||||
|
let nominal_fb = UsbIsochronousFeedback::new_float(
|
||||||
|
self.clock_impl.get_sample_rate().to_f32().unwrap() / audio_rate.to_f32().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
let mut ac = AudioClass {
|
let mut ac = AudioClass {
|
||||||
control_iface,
|
control_iface,
|
||||||
clock_impl: self.clock_impl,
|
clock_impl: self.clock_impl,
|
||||||
@@ -502,6 +510,7 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
|
|||||||
out_ep: 0,
|
out_ep: 0,
|
||||||
fb_ep: 0,
|
fb_ep: 0,
|
||||||
speed,
|
speed,
|
||||||
|
nominal_fb,
|
||||||
audio_rate,
|
audio_rate,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -510,7 +519,7 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
|
|||||||
let endpoint = alloc.isochronous(
|
let endpoint = alloc.isochronous(
|
||||||
config.sync_type,
|
config.sync_type,
|
||||||
IsochronousUsageType::Data,
|
IsochronousUsageType::Data,
|
||||||
(max_rate.div_ceil(audio_rate) * config.bytes_per_frame()) as u16,
|
((max_rate.div_ceil(audio_rate) + 1) * config.bytes_per_frame()) as u16, // headroom of 1 sample for rate control
|
||||||
interval,
|
interval,
|
||||||
);
|
);
|
||||||
let feedback_ep = alloc.isochronous(
|
let feedback_ep = alloc.isochronous(
|
||||||
@@ -537,7 +546,7 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>>
|
|||||||
let endpoint = alloc.isochronous(
|
let endpoint = alloc.isochronous(
|
||||||
config.sync_type,
|
config.sync_type,
|
||||||
IsochronousUsageType::Data,
|
IsochronousUsageType::Data,
|
||||||
(max_rate.div_ceil(audio_rate) * config.bytes_per_frame()) as u16,
|
((max_rate.div_ceil(audio_rate) + 1) * config.bytes_per_frame()) as u16, // headroom of 1 sample for rate control
|
||||||
interval,
|
interval,
|
||||||
);
|
);
|
||||||
let alt_setting = DEFAULT_ALTERNATE_SETTING;
|
let alt_setting = DEFAULT_ALTERNATE_SETTING;
|
||||||
@@ -669,6 +678,7 @@ pub struct AudioClass<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a
|
|||||||
out_ep: usize,
|
out_ep: usize,
|
||||||
fb_ep: usize,
|
fb_ep: usize,
|
||||||
speed: UsbSpeed,
|
speed: UsbSpeed,
|
||||||
|
nominal_fb: UsbIsochronousFeedback,
|
||||||
audio_rate: u32, // audio packet rate in hz
|
audio_rate: u32, // audio packet rate in hz
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,39 +821,25 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> UsbClass<B>
|
|||||||
}
|
}
|
||||||
fn endpoint_out(&mut self, addr: EndpointAddress) {
|
fn endpoint_out(&mut self, addr: EndpointAddress) {
|
||||||
debug!("EP {} out data", addr);
|
debug!("EP {} out data", addr);
|
||||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
if addr.index() == self.out_ep {
|
if addr.index() == self.out_ep {
|
||||||
self.audio_impl
|
self.audio_impl
|
||||||
.audio_data_rx(&self.output.as_ref().unwrap().endpoint);
|
.audio_data_rx(&self.output.as_ref().unwrap().endpoint);
|
||||||
let new_count = COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
if let Some(fb_ep) = self.feedback.as_ref() {
|
|
||||||
if new_count.is_multiple_of(1 << (fb_ep.interval() - 1) as usize) {
|
|
||||||
let cur_rate = self.clock_impl.get_sample_rate();
|
|
||||||
let numerator = (cur_rate as u64) << 16;
|
|
||||||
let raw = (numerator + self.audio_rate as u64 / 2) / (self.audio_rate as u64);
|
|
||||||
let nominal_rate = UsbIsochronousFeedback {
|
|
||||||
int: (raw >> 16) as u16,
|
|
||||||
frac: (raw & 0xffff) as u16,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(fb) = self.audio_impl.feedback(nominal_rate) {
|
|
||||||
debug!(" emitting feedback IN {:08x}", fb.to_u32_12_13());
|
|
||||||
let r = match self.speed {
|
|
||||||
UsbSpeed::Low | UsbSpeed::Full => fb_ep.write(&fb.to_bytes_10_14()),
|
|
||||||
UsbSpeed::High | UsbSpeed::Super => fb_ep.write(&fb.to_bytes_12_13()),
|
|
||||||
};
|
|
||||||
if let Err(e) = r {
|
|
||||||
warn!(" feedback IN failed {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
debug!(" unexpected OUT on {}", addr);
|
debug!(" unexpected OUT on {}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
|
||||||
|
debug!("EP {} IN complete", addr);
|
||||||
|
if let Some(fb_ep) = self.feedback.as_ref()
|
||||||
|
&& addr.index() == self.fb_ep
|
||||||
|
{
|
||||||
|
self.emit_feedback();
|
||||||
|
} else {
|
||||||
|
debug!(" unexpected IN on {}", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn poll(&mut self) {
|
fn poll(&mut self) {
|
||||||
debug!("poll");
|
debug!("poll");
|
||||||
// no streaming in alt 0
|
// no streaming in alt 0
|
||||||
@@ -874,6 +870,22 @@ 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 emit_feedback(&mut self) {
|
||||||
|
if let Some(fb_ep) = self.feedback.as_ref() {
|
||||||
|
if let Some(fb) = self.audio_impl.feedback(self.nominal_fb) {
|
||||||
|
debug!(" emitting feedback IN {:08x}", fb.to_u32_12_13());
|
||||||
|
let r = match self.speed {
|
||||||
|
UsbSpeed::Low | UsbSpeed::Full => fb_ep.write(&fb.to_bytes_10_14()),
|
||||||
|
UsbSpeed::High | UsbSpeed::Super => fb_ep.write(&fb.to_bytes_12_13()),
|
||||||
|
};
|
||||||
|
if let Err(e) = r {
|
||||||
|
warn!(" feedback IN failed {:?}", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug!(" feedback callback returned None")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fn standard_request_out(&mut self, xfer: ControlOut<B>) {
|
fn standard_request_out(&mut self, xfer: ControlOut<B>) {
|
||||||
let req = xfer.request();
|
let req = xfer.request();
|
||||||
match (req.recipient, req.request) {
|
match (req.recipient, req.request) {
|
||||||
@@ -945,6 +957,8 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<
|
|||||||
self.clock_impl.alt_setting(alt_setting).ok();
|
self.clock_impl.alt_setting(alt_setting).ok();
|
||||||
self.audio_impl
|
self.audio_impl
|
||||||
.alternate_setting_changed(UsbDirection::Out, alt_setting);
|
.alternate_setting_changed(UsbDirection::Out, alt_setting);
|
||||||
|
// Start the IN cycle running
|
||||||
|
self.emit_feedback();
|
||||||
self.output.as_mut().unwrap().alt_setting = alt_setting;
|
self.output.as_mut().unwrap().alt_setting = alt_setting;
|
||||||
xfer.accept().ok();
|
xfer.accept().ok();
|
||||||
}
|
}
|
||||||
@@ -1179,6 +1193,9 @@ impl<'a, B: UsbBus, CS: UsbAudioClockImpl, AU: UsbAudioClass<'a, B>> AudioClass<
|
|||||||
Ok(rate) => {
|
Ok(rate) => {
|
||||||
debug!(" SET SamplingFreqControl CUR {}", rate);
|
debug!(" SET SamplingFreqControl CUR {}", rate);
|
||||||
self.clock_impl.set_sample_rate(rate).ok();
|
self.clock_impl.set_sample_rate(rate).ok();
|
||||||
|
self.nominal_fb = UsbIsochronousFeedback::new_float(
|
||||||
|
rate.to_f32().unwrap() / self.audio_rate.to_f32().unwrap(),
|
||||||
|
);
|
||||||
xfer.accept().ok();
|
xfer.accept().ok();
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user