Skip to content

Commit 831a175

Browse files
committed
feat: duplex support PR feedback updates.
1 parent 01b01be commit 831a175

6 files changed

Lines changed: 104 additions & 134 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ This library currently supports the following:
3030
- Enumerate known supported input and output stream formats for a device.
3131
- Get the current default input and output stream formats for a device.
3232
- Build and run input and output PCM streams on a chosen device with a given stream format.
33-
- Build and run duplex (simultaneous input/output) streams with hardware clock synchronization (macOS only, more platforms coming soon).
33+
- Build and run duplex (simultaneous input/output) streams with hardware clock synchronization.
3434

3535
Currently, supported platforms include:
3636

examples/duplex_feedback.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod imp {
1111
use clap::Parser;
1212
use cpal::duplex::DuplexStreamConfig;
1313
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
14-
use cpal::BufferSize;
14+
use cpal::{BufferSize, ChannelCount, FrameCount, Sample, SampleRate};
1515

1616
#[derive(Parser, Debug)]
1717
#[command(version, about = "CPAL duplex feedback example", long_about = None)]
@@ -22,33 +22,35 @@ mod imp {
2222

2323
/// Number of input channels
2424
#[arg(long, value_name = "CHANNELS", default_value_t = 2)]
25-
input_channels: u16,
25+
input_channels: ChannelCount,
2626

2727
/// Number of output channels
2828
#[arg(long, value_name = "CHANNELS", default_value_t = 2)]
29-
output_channels: u16,
29+
output_channels: ChannelCount,
3030

3131
/// Sample rate in Hz
3232
#[arg(short, long, value_name = "RATE", default_value_t = 48000)]
33-
sample_rate: u32,
33+
sample_rate: SampleRate,
3434

35-
/// Buffer size in frames
36-
#[arg(short, long, value_name = "FRAMES", default_value_t = 512)]
37-
buffer_size: u32,
35+
/// Buffer size in frames (omit for device default)
36+
#[arg(short, long, value_name = "FRAMES")]
37+
buffer_size: Option<FrameCount>,
3838
}
3939

4040
pub fn run() -> anyhow::Result<()> {
4141
let opt = Opt::parse();
4242
let host = cpal::default_host();
4343

4444
// Find the device by device ID or use default
45-
let device = if let Some(device_id_str) = opt.device {
46-
let device_id = device_id_str.parse().expect("failed to parse device id");
47-
host.device_by_id(&device_id)
48-
.unwrap_or_else(|| panic!("failed to find device with id: {}", device_id_str))
49-
} else {
50-
host.default_output_device()
51-
.expect("no default output device")
45+
let device = match opt.device {
46+
Some(device_id_str) => {
47+
let device_id = device_id_str.parse().expect("failed to parse device id");
48+
host.device_by_id(&device_id)
49+
.expect(&format!("failed to find device with id: {}", device_id_str))
50+
}
51+
None => host
52+
.default_output_device()
53+
.expect("no default output device"),
5254
};
5355

5456
println!("Using device: \"{}\"", device.description()?.name());
@@ -58,15 +60,18 @@ mod imp {
5860
input_channels: opt.input_channels,
5961
output_channels: opt.output_channels,
6062
sample_rate: opt.sample_rate,
61-
buffer_size: BufferSize::Fixed(opt.buffer_size),
63+
buffer_size: opt
64+
.buffer_size
65+
.map(|s| BufferSize::Fixed(s))
66+
.unwrap_or(BufferSize::Default),
6267
};
6368

6469
println!("Building duplex stream with config: {config:?}");
6570

6671
let stream = device.build_duplex_stream::<f32, _, _>(
6772
&config,
6873
move |input, output, _info| {
69-
output.fill(0.0);
74+
output.fill(Sample::EQUILIBRIUM);
7075
let copy_len = input.len().min(output.len());
7176
output[..copy_len].copy_from_slice(&input[..copy_len]);
7277
},
@@ -76,7 +81,7 @@ mod imp {
7681

7782
println!("Successfully built duplex stream.");
7883
println!(
79-
"Input: {} channels, Output: {} channels, Sample rate: {} Hz, Buffer size: {} frames",
84+
"Input: {} channels, Output: {} channels, Sample rate: {} Hz, Buffer size: {:?} frames",
8085
opt.input_channels, opt.output_channels, opt.sample_rate, opt.buffer_size
8186
);
8287

@@ -86,7 +91,6 @@ mod imp {
8691
println!("Playing for 10 seconds... (speak into your microphone)");
8792
std::thread::sleep(std::time::Duration::from_secs(10));
8893

89-
drop(stream);
9094
println!("Done!");
9195
Ok(())
9296
}
@@ -98,7 +102,6 @@ fn main() {
98102

99103
#[cfg(not(target_os = "macos"))]
100104
{
101-
eprintln!("Duplex streams are currently only supported on macOS.");
102-
eprintln!("Windows (WASAPI) and Linux (ALSA) support is planned.");
105+
eprintln!("Duplex streams are not supported on this platform.");
103106
}
104107
}

src/duplex.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,9 @@
33
//! This module provides types for building duplex (simultaneous input/output) audio streams
44
//! with hardware clock synchronization.
55
//!
6-
//! # Overview
7-
//!
8-
//! Unlike separate input and output streams which may have independent clocks, a duplex stream
9-
//! uses a single device context for both input and output, ensuring they share the same
10-
//! hardware clock. This is essential for applications like:
11-
//!
12-
//! - DAWs (Digital Audio Workstations)
13-
//! - Real-time audio effects processing
14-
//! - Audio measurement and analysis
15-
//! - Any application requiring sample-accurate I/O synchronization
16-
//!
176
//! See `examples/duplex_feedback.rs` for a working example.
187
19-
use crate::{InputStreamTimestamp, OutputStreamTimestamp, SampleRate};
8+
use crate::{ChannelCount, InputStreamTimestamp, OutputStreamTimestamp, SampleRate};
209

2110
/// Information passed to duplex callbacks.
2211
///
@@ -66,10 +55,10 @@ impl DuplexCallbackInfo {
6655
#[derive(Clone, Debug, Eq, PartialEq)]
6756
pub struct DuplexStreamConfig {
6857
/// Number of input channels.
69-
pub input_channels: u16,
58+
pub input_channels: ChannelCount,
7059

7160
/// Number of output channels.
72-
pub output_channels: u16,
61+
pub output_channels: ChannelCount,
7362

7463
/// Sample rate in Hz.
7564
pub sample_rate: SampleRate,

0 commit comments

Comments
 (0)