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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
.DS_Store
recorded.wav
rls*.log
/.direnv
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- CoreAudio: Change `Device::supported_configs` to return a single element containing the available sample rate range when all elements have the same `mMinimum` and `mMaximum` values.
- CoreAudio: Change default audio device detection to be lazy when building a stream, instead of during device enumeration.
- CoreAudio: Add `i8`, `i32` and `I24` sample format support (24-bit samples stored in 4 bytes).
- CoreAudio: Add support for loopback recording (recording system audio output) on macOS.
- iOS: Fix example by properly activating audio session.
- WASAPI: Expose `IMMDevice` from WASAPI host Device.
- WASAPI: Add `I24` and `U24` sample format support (24-bit samples stored in 4 bytes).
Expand Down
41 changes: 35 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ edition = "2021"
rust-version = "1.70"

[features]
asio = ["asio-sys", "num-traits"] # Only available on Windows. See README for setup instructions.
asio = [
"asio-sys",
"num-traits",
] # Only available on Windows. See README for setup instructions.

# Deprecated, the `oboe` backend has been removed
oboe-shared-stdcxx = []
Expand All @@ -36,8 +39,8 @@ windows = { version = "0.54.0", features = [
"Win32_System_SystemServices",
"Win32_System_Variant",
"Win32_Media_Multimedia",
"Win32_UI_Shell_PropertiesSystem"
]}
"Win32_UI_Shell_PropertiesSystem",
] }
audio_thread_priority = { version = "0.33.0", optional = true }
asio-sys = { version = "0.2", path = "asio-sys", optional = true }
num-traits = { version = "0.2.6", optional = true }
Expand All @@ -60,6 +63,8 @@ objc2-core-audio = { version = "0.3.1", default-features = false, features = [
"std",
"AudioHardware",
"AudioHardwareDeprecated",
"objc2",
"objc2-foundation",
] }
objc2-audio-toolbox = { version = "0.3.1", default-features = false, features = [
"std",
Expand All @@ -70,20 +75,44 @@ objc2-core-audio-types = { version = "0.3.1", default-features = false, features
"std",
"CoreAudioBaseTypes",
] }
objc2-core-foundation = { version = "0.3.1" }
objc2-foundation = { version = "0.3.1" }
objc2 = { version = "0.6.2" }

[target.'cfg(target_os = "emscripten")'.dependencies]
wasm-bindgen = { version = "0.2.89" }
wasm-bindgen-futures = "0.4.33"
js-sys = { version = "0.3.35" }
web-sys = { version = "0.3.35", features = [ "AudioContext", "AudioContextOptions", "AudioBuffer", "AudioBufferSourceNode", "AudioNode", "AudioDestinationNode", "Window", "AudioContextState"] }
web-sys = { version = "0.3.35", features = [
"AudioContext",
"AudioContextOptions",
"AudioBuffer",
"AudioBufferSourceNode",
"AudioNode",
"AudioDestinationNode",
"Window",
"AudioContextState",
] }

[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
wasm-bindgen = { version = "0.2.58", optional = true }
js-sys = { version = "0.3.35" }
web-sys = { version = "0.3.35", features = [ "AudioContext", "AudioContextOptions", "AudioBuffer", "AudioBufferSourceNode", "AudioNode", "AudioDestinationNode", "Window", "AudioContextState"] }
web-sys = { version = "0.3.35", features = [
"AudioContext",
"AudioContextOptions",
"AudioBuffer",
"AudioBufferSourceNode",
"AudioNode",
"AudioDestinationNode",
"Window",
"AudioContextState",
] }

[target.'cfg(target_os = "android")'.dependencies]
ndk = { version = "0.9", default-features = false, features = ["audio", "api-level-26"]}
ndk = { version = "0.9", default-features = false, features = [
"audio",
"api-level-26",
] }
ndk-context = "0.1"
jni = "0.21"
num-derive = "0.4"
Expand Down
32 changes: 21 additions & 11 deletions examples/record_wav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ use std::sync::{Arc, Mutex};
#[derive(Parser, Debug)]
#[command(version, about = "CPAL record_wav example", long_about = None)]
struct Opt {
/// The audio device to use
/// The audio device to use.
/// For the default microphone, use "default".
/// For recording system output, use "default-output".
#[arg(short, long, default_value_t = String::from("default"))]
device: String,

/// How long to record, in seconds
#[arg(long, default_value_t = 3)]
duration: u64,

/// Use the JACK host
#[cfg(all(
any(
Expand Down Expand Up @@ -69,20 +75,24 @@ fn main() -> Result<(), anyhow::Error> {
let host = cpal::default_host();

// Set up the input device and stream with the default input config.
let device = if opt.device == "default" {
host.default_input_device()
} else {
host.input_devices()?
.find(|x| x.name().map(|y| y == opt.device).unwrap_or(false))
let device = match opt.device.as_str() {
"default" => host.default_input_device(),
"default-output" => host.default_output_device(),
name => host
.input_devices()?
.find(|x| x.name().map(|y| y == name).unwrap_or(false)),
}
.expect("failed to find input device");

println!("Input device: {}", device.name()?);

let config = device
.default_input_config()
.expect("Failed to get default input config");
println!("Default input config: {config:?}");
let config = if device.supports_input() {
device.default_input_config()
} else {
device.default_output_config()
}
.expect("Failed to get default input/output config");
println!("Default input/output config: {config:?}");

// The WAV file we're recording to.
const PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/recorded.wav");
Expand Down Expand Up @@ -135,7 +145,7 @@ fn main() -> Result<(), anyhow::Error> {
stream.play()?;

// Let recording go for roughly three seconds.
std::thread::sleep(std::time::Duration::from_secs(3));
std::thread::sleep(std::time::Duration::from_secs(opt.duration));
drop(stream);
writer.lock().unwrap().take().unwrap().finalize()?;
println!("Recording {PATH} complete!");
Expand Down
Loading
Loading