Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Add `Display` and `FromStr` implementations for `HostId`.
- Add support for custom `Host`s, `Device`s, and `Stream`s.
- Add `Sample::bits_per_sample` method.
- Change `SampleRate` from struct to `u32` type alias.
- Update `audio_thread_priority` to 0.34.
- AAudio: Configure buffer to ensure consistent callback buffer sizes.
- AAudio: Make `Stream` implement `Send` and `Sync`.
Expand All @@ -17,7 +18,7 @@
- ALSA: Fix format selection to probe hardware endianness instead of assuming native byte order.
- ALSA: Add support for 12, 24, 352.8, 384, 705.6, and 768 kHz sample rates.
- ALSA: Update `alsa` to 0.10.
- ALSA(process_output): Pass `silent=true` to `PCM.try_recover`, so it doesn't write to stderr.
- ALSA: Pass `silent=true` to `PCM.try_recover`, so it doesn't write to stderr.
- ASIO: Fix linker flags for MinGW cross-compilation.
- ASIO: Add packed(4) to representation of ASIO time structs in bindings.
- CI: Added native ARM64 Linux support in GitHub Actions.
Expand Down
8 changes: 4 additions & 4 deletions asio-sys/src/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ pub enum AsioMessageSelectors {
kAsioSupportsTimeInfo, // if host returns true here, it will expect the
// callback bufferSwitchTimeInfo to be called instead
// of bufferSwitch
kAsioSupportsTimeCode, //
kAsioSupportsTimeCode, //
kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands
kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this
kAsioSupportsInputGain, // unused and undefined
Expand Down Expand Up @@ -786,7 +786,7 @@ impl DriverState {
}

impl DriverInner {
fn lock_state(&self) -> MutexGuard<DriverState> {
fn lock_state(&self) -> MutexGuard<'_, DriverState> {
self.state.lock().expect("failed to lock `DriverState`")
}

Expand Down Expand Up @@ -890,14 +890,14 @@ fn stream_data_type(is_input: bool) -> Result<AsioSampleType, AsioError> {
/// ASIO uses null terminated c strings for driver names.
///
/// This converts to utf8.
fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<str> {
fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<'_, str> {
unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() }
}

/// ASIO uses null terminated c strings for channel names.
///
/// This converts to utf8.
fn _channel_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<str> {
fn _channel_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<'_, str> {
unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() }
}

Expand Down
3 changes: 0 additions & 3 deletions asio-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
extern crate num_derive;
extern crate num_traits;

#[cfg(asio)]
pub mod bindings;
#[cfg(asio)]
pub use bindings::errors::{AsioError, LoadDriverError};
#[cfg(asio)]
pub use bindings::*;
2 changes: 1 addition & 1 deletion examples/android/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh
where
T: SizedSample + FromSample<f32>,
{
let sample_rate = config.sample_rate.0 as f32;
let sample_rate = config.sample_rate as f32;
let channels = config.channels as usize;

// Produce a sinusoid of maximum amplitude.
Expand Down
2 changes: 1 addition & 1 deletion examples/audioworklet-beep/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Stream
where
T: cpal::Sample + cpal::SizedSample + cpal::FromSample<f32>,
{
let sample_rate = config.sample_rate.0 as f32;
let sample_rate = config.sample_rate as f32;
let channels = config.channels as usize;

// Produce a sinusoid of maximum amplitude.
Expand Down
2 changes: 1 addition & 1 deletion examples/beep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(),
where
T: SizedSample + FromSample<f32>,
{
let sample_rate = config.sample_rate.0 as f32;
let sample_rate = config.sample_rate as f32;
let channels = config.channels as usize;

// Produce a sinusoid of maximum amplitude.
Expand Down
8 changes: 4 additions & 4 deletions examples/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ impl DeviceTrait for MyDevice {
) -> Result<Self::SupportedOutputConfigs, cpal::SupportedStreamConfigsError> {
Ok(std::iter::once(cpal::SupportedStreamConfigRange::new(
2,
cpal::SampleRate(44100),
cpal::SampleRate(44100),
44100,
44100,
cpal::SupportedBufferSize::Unknown,
cpal::SampleFormat::F32,
)))
Expand All @@ -96,7 +96,7 @@ impl DeviceTrait for MyDevice {
) -> Result<cpal::SupportedStreamConfig, cpal::DefaultStreamConfigError> {
Ok(cpal::SupportedStreamConfig::new(
2,
cpal::SampleRate(44100),
44100,
cpal::SupportedBufferSize::Unknown,
cpal::SampleFormat::I16,
))
Expand Down Expand Up @@ -302,7 +302,7 @@ pub fn make_stream(
let num_channels = config.channels as usize;
let mut oscillator = Oscillator {
waveform: Waveform::Sine,
sample_rate: config.sample_rate.0 as f32,
sample_rate: config.sample_rate as f32,
current_sample_index: 0.0,
frequency_hz: 440.0,
};
Expand Down
2 changes: 1 addition & 1 deletion examples/feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fn main() -> anyhow::Result<()> {
let config: cpal::StreamConfig = input_device.default_input_config()?.into();

// Create a delay in case the input and output devices aren't synced.
let latency_frames = (opt.latency / 1_000.0) * config.sample_rate.0 as f32;
let latency_frames = (opt.latency / 1_000.0) * config.sample_rate as f32;
let latency_samples = latency_frames as usize * config.channels as usize;

// The buffer to share samples
Expand Down
7 changes: 5 additions & 2 deletions examples/ios-feedback/src/feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ extern crate cpal;
extern crate ringbuf;

use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use ringbuf::{HeapRb, traits::{Split, Producer, Consumer}};
use ringbuf::{
traits::{Consumer, Producer, Split},
HeapRb,
};

const LATENCY_MS: f32 = 1000.0;

Expand All @@ -32,7 +35,7 @@ pub fn run_example() -> Result<(), anyhow::Error> {
let config: cpal::StreamConfig = input_device.default_input_config()?.into();

// Create a delay in case the input and output devices aren't synced.
let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate.0 as f32;
let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate as f32;
let latency_samples = latency_frames as usize * config.channels as usize;

// The buffer to share samples
Expand Down
2 changes: 1 addition & 1 deletion examples/record_wav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat {
fn wav_spec_from_config(config: &cpal::SupportedStreamConfig) -> hound::WavSpec {
hound::WavSpec {
channels: config.channels() as _,
sample_rate: config.sample_rate().0 as _,
sample_rate: config.sample_rate() as _,
bits_per_sample: (config.sample_format().sample_size() * 8) as _,
sample_format: sample_format(config.sample_format()),
}
Expand Down
2 changes: 1 addition & 1 deletion examples/synth_tones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ where
let num_channels = config.channels as usize;
let mut oscillator = Oscillator {
waveform: Waveform::Sine,
sample_rate: config.sample_rate.0 as f32,
sample_rate: config.sample_rate as f32,
current_sample_index: 0.0,
frequency_hz: 440.0,
};
Expand Down
2 changes: 1 addition & 1 deletion examples/wasm-beep/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Stream
where
T: cpal::Sample + cpal::SizedSample + cpal::FromSample<f32>,
{
let sample_rate = config.sample_rate.0 as f32;
let sample_rate = config.sample_rate as f32;
let channels = config.channels as usize;

// Produce a sinusoid of maximum amplitude.
Expand Down
14 changes: 7 additions & 7 deletions src/host/aaudio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::{
DeviceDescription, DeviceDescriptionBuilder, DeviceDirection, DeviceId, DeviceIdError,
DeviceNameError, DeviceType, DevicesError, InputCallbackInfo, InputStreamTimestamp,
InterfaceType, OutputCallbackInfo, OutputStreamTimestamp, PauseStreamError, PlayStreamError,
SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSize,
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
SampleFormat, StreamConfig, StreamError, SupportedBufferSize, SupportedStreamConfig,
SupportedStreamConfigRange, SupportedStreamConfigsError,
};

mod convert;
Expand Down Expand Up @@ -203,8 +203,8 @@ fn default_supported_configs() -> VecIntoIter<SupportedStreamConfigRange> {
for sample_rate in &SAMPLE_RATES {
output.push(SupportedStreamConfigRange {
channels: *channel_count,
min_sample_rate: SampleRate(*sample_rate as u32),
max_sample_rate: SampleRate(*sample_rate as u32),
min_sample_rate: *sample_rate as u32,
max_sample_rate: *sample_rate as u32,
buffer_size,
sample_format: *sample_format,
});
Expand Down Expand Up @@ -249,8 +249,8 @@ fn device_supported_configs(device: &AudioDeviceInfo) -> VecIntoIter<SupportedSt
for format in formats {
output.push(SupportedStreamConfigRange {
channels: cmp::min(*channel_count as u16, 2u16),
min_sample_rate: SampleRate(*sample_rate as u32),
max_sample_rate: SampleRate(*sample_rate as u32),
min_sample_rate: *sample_rate as u32,
max_sample_rate: *sample_rate as u32,
buffer_size,
sample_format: *format,
});
Expand All @@ -271,7 +271,7 @@ fn configure_for_device(
} else {
builder
};
builder = builder.sample_rate(config.sample_rate.0.try_into().unwrap());
builder = builder.sample_rate(config.sample_rate.try_into().unwrap());

// Note: Buffer size validation is not needed - the native AAudio API validates buffer sizes
// when `open_stream()` is called.
Expand Down
16 changes: 8 additions & 8 deletions src/host/alsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,8 +515,8 @@ impl Device {
} else {
let mut rates = Vec::new();
for &sample_rate in crate::COMMON_SAMPLE_RATES.iter() {
if hw_params.test_rate(sample_rate.0).is_ok() {
rates.push((sample_rate.0, sample_rate.0));
if hw_params.test_rate(sample_rate).is_ok() {
rates.push((sample_rate, sample_rate));
}
}

Expand Down Expand Up @@ -555,8 +555,8 @@ impl Device {
for &(min_rate, max_rate) in sample_rates.iter() {
output.push(SupportedStreamConfigRange {
channels,
min_sample_rate: SampleRate(min_rate),
max_sample_rate: SampleRate(max_rate),
min_sample_rate: min_rate,
max_sample_rate: max_rate,
buffer_size: buffer_size_range,
sample_format,
});
Expand Down Expand Up @@ -609,7 +609,7 @@ impl Device {
let min_r = f.min_sample_rate;
let max_r = f.max_sample_rate;
let mut format = f.with_max_sample_rate();
const HZ_44100: SampleRate = SampleRate(44_100);
const HZ_44100: SampleRate = 44_100;
if min_r <= HZ_44100 && HZ_44100 <= max_r {
format.sample_rate = HZ_44100;
}
Expand Down Expand Up @@ -860,7 +860,7 @@ fn boost_current_thread_priority(buffer_size: BufferSize, sample_rate: SampleRat
0
};

if let Err(err) = promote_current_thread_to_real_time(buffer_size, sample_rate.0) {
if let Err(err) = promote_current_thread_to_real_time(buffer_size, sample_rate) {
eprintln!("Failed to promote audio thread to real-time priority: {err}");
}
}
Expand Down Expand Up @@ -1101,7 +1101,7 @@ fn timespec_diff_nanos(a: libc::timespec, b: libc::timespec) -> i64 {
// Convert the given duration in frames at the given sample rate to a `std::time::Duration`.
#[inline]
fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration {
let secsf = frames as f64 / rate.0 as f64;
let secsf = frames as f64 / rate as f64;
let secs = secsf as u64;
let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32;
std::time::Duration::new(secs, nanos)
Expand Down Expand Up @@ -1273,7 +1273,7 @@ fn init_hw_params<'a>(
let alsa_format = sample_format_to_alsa_format(&hw_params, sample_format)?;
hw_params.set_format(alsa_format)?;

hw_params.set_rate(config.sample_rate.0, alsa::ValueOr::Nearest)?;
hw_params.set_rate(config.sample_rate, alsa::ValueOr::Nearest)?;
hw_params.set_channels(config.channels as u32)?;
Ok(hw_params)
}
Expand Down
9 changes: 4 additions & 5 deletions src/host/asio/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::DeviceIdError;
use crate::DeviceNameError;
use crate::DevicesError;
use crate::SampleFormat;
use crate::SampleRate;
use crate::SupportedBufferSize;
use crate::SupportedStreamConfig;
use crate::SupportedStreamConfigRange;
Expand Down Expand Up @@ -94,7 +93,7 @@ impl Device {
for &rate in crate::COMMON_SAMPLE_RATES {
if !self
.driver
.can_sample_rate(rate.0.into())
.can_sample_rate(rate.into())
.ok()
.unwrap_or(false)
{
Expand Down Expand Up @@ -131,7 +130,7 @@ impl Device {
for &rate in crate::COMMON_SAMPLE_RATES {
if !self
.driver
.can_sample_rate(rate.0.into())
.can_sample_rate(rate.into())
.ok()
.unwrap_or(false)
{
Expand All @@ -153,7 +152,7 @@ impl Device {
/// Returns the default input config
pub fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
let channels = self.driver.channels().map_err(default_config_err)?.ins as u16;
let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_config_err)? as _);
let sample_rate = self.driver.sample_rate().map_err(default_config_err)? as u32;
let (min, max) = self.driver.buffersize_range().map_err(default_config_err)?;
let buffer_size = SupportedBufferSize::Range {
min: min as u32,
Expand All @@ -174,7 +173,7 @@ impl Device {
/// Returns the default output config
pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
let channels = self.driver.channels().map_err(default_config_err)?.outs as u16;
let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_config_err)? as _);
let sample_rate = self.driver.sample_rate().map_err(default_config_err)? as u32;
let (min, max) = self.driver.buffersize_range().map_err(default_config_err)?;
let buffer_size = SupportedBufferSize::Range {
min: min as u32,
Expand Down
7 changes: 4 additions & 3 deletions src/host/asio/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,9 +656,10 @@ fn system_time_to_stream_instant(
crate::StreamInstant::new(secs, nanos)
}

/// Convert the given duration in frames at the given sample rate to a `std::time::Duration`.
// Convert the given duration in frames at the given sample rate to a `std::time::Duration`.
#[inline]
fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration {
let secsf = frames as f64 / rate.0 as f64;
let secsf = frames as f64 / rate as f64;
let secs = secsf as u64;
let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32;
std::time::Duration::new(secs, nanos)
Expand Down Expand Up @@ -692,7 +693,7 @@ fn check_config(
}

// Try and set the sample rate to what the user selected.
let sample_rate = sample_rate.0.into();
let sample_rate = (*sample_rate).into();
if sample_rate != driver.sample_rate().map_err(build_stream_err)? {
if driver
.can_sample_rate(sample_rate)
Expand Down
13 changes: 6 additions & 7 deletions src/host/audioworklet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs};

const MIN_CHANNELS: ChannelCount = 1;
const MAX_CHANNELS: ChannelCount = 32;
const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000);
const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000);
const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100);
const MIN_SAMPLE_RATE: SampleRate = 8_000;
const MAX_SAMPLE_RATE: SampleRate = 96_000;
const DEFAULT_SAMPLE_RATE: SampleRate = 44_100;
const SUPPORTED_SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;

impl Host {
Expand Down Expand Up @@ -191,7 +191,7 @@ impl DeviceTrait for Device {
let config = config.clone();

let stream_opts = web_sys::AudioContextOptions::new();
stream_opts.set_sample_rate(config.sample_rate.0 as f32);
stream_opts.set_sample_rate(config.sample_rate as f32);

let audio_context = web_sys::AudioContext::new_with_context_options(&stream_opts).map_err(
|err| -> BuildStreamError {
Expand Down Expand Up @@ -237,8 +237,7 @@ impl DeviceTrait for Device {

let callback = crate::StreamInstant::from_secs_f64(now);

let buffer_duration =
frames_to_duration(frame_size as _, SampleRate(sample_rate));
let buffer_duration = frames_to_duration(frame_size as _, sample_rate);
let playback = callback.add(buffer_duration).expect(
"`playback` occurs beyond representation supported by `StreamInstant`",
);
Expand Down Expand Up @@ -336,7 +335,7 @@ fn valid_config(conf: &StreamConfig, sample_format: SampleFormat) -> bool {

// Convert the given duration in frames at the given sample rate to a `std::time::Duration`.
fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration {
let secsf = frames as f64 / rate.0 as f64;
let secsf = frames as f64 / rate as f64;
let secs = secsf as u64;
let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32;
std::time::Duration::new(secs, nanos)
Expand Down
Loading