Skip to content
Open
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
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ 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.
pulseaudio = ["dep:pulseaudio", "dep:futures"] # Only available on some Unix platforms.

# Deprecated, the `oboe` backend has been removed
oboe-shared-stdcxx = []
Expand Down Expand Up @@ -53,6 +51,8 @@ alsa = "0.10"
libc = "0.2"
audio_thread_priority = { version = "0.34.0", optional = true }
jack = { version = "0.13.0", optional = true }
pulseaudio = { version = "0.3", optional = true }
futures = { version = "0.3", optional = true }

[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
mach2 = "0.5" # For access to mach_timebase type.
Expand Down
77 changes: 38 additions & 39 deletions examples/beep.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::Parser;
use cpal::{
traits::{DeviceTrait, HostTrait, StreamTrait},
FromSample, Sample, SizedSample, I24,
FromSample, HostUnavailable, Sample, SizedSample, I24,
};

#[derive(Parser, Debug)]
Expand All @@ -11,58 +11,57 @@ struct Opt {
#[arg(short, long, default_value_t = String::from("default"))]
device: String,

/// Use the JACK host
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
),
feature = "jack"
))]
#[arg(short, long)]
#[allow(dead_code)]
/// Use the JACK host. Requires `--features jack`.
#[arg(long, default_value_t = false)]
jack: bool,

/// Use the PulseAudio host. Requires `--features pulseaudio`.
#[arg(long, default_value_t = false)]
pulseaudio: bool,
}

fn main() -> anyhow::Result<()> {
let opt = Opt::parse();

// Conditionally compile with jack if the feature is specified.
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
),
feature = "jack"
// Jack/PulseAudio support must be enabled at compile time, and is
// only available on some platforms.
#[allow(unused_mut, unused_assignments)]
let mut jack_host_id = Err(HostUnavailable);
#[allow(unused_mut, unused_assignments)]
let mut pulseaudio_host_id = Err(HostUnavailable);

#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
))]
{
#[cfg(feature = "jack")]
{
jack_host_id = Ok(cpal::HostId::Jack);
}

#[cfg(feature = "pulseaudio")]
{
pulseaudio_host_id = Ok(cpal::HostId::PulseAudio);
}
}

// Manually check for flags. Can be passed through cargo with -- e.g.
// cargo run --release --example beep --features jack -- --jack
let host = if opt.jack {
cpal::host_from_id(cpal::available_hosts()
.into_iter()
.find(|id| *id == cpal::HostId::Jack)
.expect(
"make sure --features jack is specified. only works on OSes where jack is available",
)).expect("jack host unavailable")
jack_host_id
.and_then(cpal::host_from_id)
.expect("make sure `--features jack` is specified, and the platform is supported")
} else if opt.pulseaudio {
pulseaudio_host_id
.and_then(cpal::host_from_id)
.expect("make sure `--features pulseaudio` is specified, and the platform is supported")
} else {
cpal::default_host()
};

#[cfg(any(
not(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
)),
not(feature = "jack")
))]
let host = cpal::default_host();

let device = if opt.device == "default" {
host.default_output_device()
} else {
Expand Down
86 changes: 44 additions & 42 deletions examples/feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
//! precisely synchronised.

use clap::Parser;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{
traits::{DeviceTrait, HostTrait, StreamTrait},
HostUnavailable,
};
use ringbuf::{
traits::{Consumer, Producer, Split},
HeapRb,
Expand All @@ -28,58 +31,57 @@ struct Opt {
#[arg(short, long, value_name = "DELAY_MS", default_value_t = 150.0)]
latency: f32,

/// Use the JACK host
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
),
feature = "jack"
))]
#[arg(short, long)]
#[allow(dead_code)]
/// Use the JACK host. Requires `--features jack`.
#[arg(long, default_value_t = false)]
jack: bool,

/// Use the PulseAudio host. Requires `--features pulseaudio`.
#[arg(long, default_value_t = false)]
pulseaudio: bool,
}

fn main() -> anyhow::Result<()> {
let opt = Opt::parse();

// Conditionally compile with jack if the feature is specified.
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
),
feature = "jack"
// Jack/PulseAudio support must be enabled at compile time, and is
// only available on some platforms.
#[allow(unused_mut, unused_assignments)]
let mut jack_host_id = Err(HostUnavailable);
#[allow(unused_mut, unused_assignments)]
let mut pulseaudio_host_id = Err(HostUnavailable);

#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
))]
{
#[cfg(feature = "jack")]
{
jack_host_id = Ok(cpal::HostId::Jack);
}

#[cfg(feature = "pulseaudio")]
{
pulseaudio_host_id = Ok(cpal::HostId::PulseAudio);
}
}

// Manually check for flags. Can be passed through cargo with -- e.g.
// cargo run --release --example beep --features jack -- --jack
let host = if opt.jack {
cpal::host_from_id(cpal::available_hosts()
.into_iter()
.find(|id| *id == cpal::HostId::Jack)
.expect(
"make sure --features jack is specified. only works on OSes where jack is available",
)).expect("jack host unavailable")
jack_host_id
.and_then(cpal::host_from_id)
.expect("make sure `--features jack` is specified, and the platform is supported")
} else if opt.pulseaudio {
pulseaudio_host_id
.and_then(cpal::host_from_id)
.expect("make sure `--features pulseaudio` is specified, and the platform is supported")
} else {
cpal::default_host()
};

#[cfg(any(
not(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
)),
not(feature = "jack")
))]
let host = cpal::default_host();

// Find devices.
let input_device = if opt.input_device == "default" {
host.default_input_device()
Expand Down Expand Up @@ -160,9 +162,9 @@ fn main() -> anyhow::Result<()> {
input_stream.play()?;
output_stream.play()?;

// Run for 3 seconds before closing.
println!("Playing for 3 seconds... ");
std::thread::sleep(std::time::Duration::from_secs(3));
// Run for 10 seconds before closing.
println!("Playing for 10 seconds... ");
std::thread::sleep(std::time::Duration::from_secs(10));
drop(input_stream);
drop(output_stream);
println!("Done!");
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,15 @@ impl From<BackendSpecificError> for DevicesError {
pub enum DeviceNameError {
/// See the [`BackendSpecificError`] docs for more information about this error variant.
BackendSpecific { err: BackendSpecificError },
/// The name is not valid UTF-8.
InvalidUtf8,
}

impl Display for DeviceNameError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::BackendSpecific { err } => err.fmt(f),
Self::InvalidUtf8 => write!(f, "The name is not valid UTF-8"),
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ pub(crate) mod emscripten;
))]
pub(crate) mod jack;
pub(crate) mod null;
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd"
),
feature = "pulseaudio"
))]
pub(crate) mod pulseaudio;
#[cfg(windows)]
pub(crate) mod wasapi;
#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
Expand Down
Loading
Loading