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 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.
- Add `Copy` impl to `InputCallbackInfo` and `OutputCallbackInfo`.
- Change `SampleRate` from struct to `u32` type alias.
- Update `audio_thread_priority` to 0.34.
- AAudio: Configure buffer to ensure consistent callback buffer sizes.
Expand Down
50 changes: 45 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,35 @@ edition = "2021"
rust-version = "1.70"

[features]
# ASIO backend for Windows
# Provides low-latency audio I/O by bypassing the Windows audio stack
# Requires: ASIO drivers and LLVM/Clang for build-time bindings
# See README for detailed setup instructions
asio = [
"asio-sys",
"num-traits",
] # Only available on Windows. See README for setup instructions.
"dep:asio-sys",
"dep:num-traits",
]

# Only available on web when atomics are enabled. See README for what it does.
# JACK Audio Connection Kit backend for Linux/BSD
# Provides low-latency connections between applications and audio hardware
# Requires: JACK server and client libraries installed on the system
# Platform: Linux, DragonFly BSD, FreeBSD, NetBSD only
# Note: While JACK exists on Windows/macOS, CPAL's JACK backend is only implemented for Linux/BSD
jack = ["dep:jack"]

# WebAssembly backend using wasm-bindgen
# Enables the Web Audio API backend for browser-based audio
# Required for any WebAssembly audio support
# Platform: WebAssembly (wasm32-unknown-unknown)
# Note: This is typically enabled automatically when targeting wasm32
wasm-bindgen = ["dep:wasm-bindgen", "dep:wasm-bindgen-futures"]

# Audio Worklet backend for WebAssembly
# Provides lower-latency web audio processing compared to default Web Audio API
# Requires: Build with atomics support and Cross-Origin headers for SharedArrayBuffer
# Platform: WebAssembly (wasm32-unknown-unknown)
audioworklet = [
"dep:wasm-bindgen-futures",
"wasm-bindgen",
"web-sys/Blob",
"web-sys/BlobPropertyBag",
"web-sys/Url",
Expand All @@ -27,7 +48,9 @@ audioworklet = [
]

# Support for user-defined custom hosts, devices, and streams
# Allows integration with audio systems not natively supported by CPAL
# See examples/custom.rs for usage
# Platform: All platforms
custom = []

[dependencies]
Expand Down Expand Up @@ -152,3 +175,20 @@ name = "record_wav"

[[example]]
name = "synth_tones"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
targets = [
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
"x86_64-apple-darwin",
"aarch64-apple-darwin",
"aarch64-apple-ios",
"wasm32-unknown-unknown",
"wasm32-unknown-emscripten",
"aarch64-linux-android",
"x86_64-unknown-freebsd",
"x86_64-unknown-netbsd",
"x86_64-unknown-dragonfly",
]
178 changes: 113 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,75 @@ Note that on Linux, the ALSA development files are required. These are provided
as part of the `libasound2-dev` package on Debian and Ubuntu distributions and
`alsa-lib-devel` on Fedora.

## Compiling for Web Assembly
## Compiling for WebAssembly

If you are interested in using CPAL with WASM, please see [this guide](https://github.com/RustAudio/cpal/wiki/Setting-up-a-new-CPAL-WASM-project) in our Wiki which walks through setting up a new project from scratch.
If you are interested in using CPAL with WebAssembly, please see [this guide](https://github.com/RustAudio/cpal/wiki/Setting-up-a-new-CPAL-WASM-project) in our Wiki which walks through setting up a new project from scratch. Some of the examples in this repository also provide working configurations that you can use as reference.

## Feature flags for audio backends
## Optional Features

Some audio backends are optional and will only be compiled with a [feature flag](https://doc.rust-lang.org/cargo/reference/features.html).
CPAL provides the following optional features:

- JACK (on Linux): `jack`
- ASIO (on Windows): `asio`
- AudioWorklet (on Web): `audioworklet`
### `asio`

For AudioWorklet backend usage see the README for the `audioworklet-beep` example.
**Platform:** Windows

## ASIO on Windows
Enables the ASIO (Audio Stream Input/Output) backend. ASIO provides low-latency audio I/O by bypassing the Windows audio stack.

**Requirements:**
- ASIO drivers for your audio device
- LLVM/Clang for build-time bindings generation

**Setup:** See the [ASIO setup guide](#asio-on-windows) below for detailed installation instructions.

### `jack`

**Platform:** Linux, DragonFly BSD, FreeBSD, NetBSD

Enables the JACK (JACK Audio Connection Kit) backend. JACK is an audio server providing low-latency connections between applications and audio hardware.

**Requirements:**
- JACK server and client libraries must be installed on the system

**Usage:** See the [beep example](examples/beep.rs) for selecting the JACK host at runtime.

**Note:** While JACK is available on Windows and macOS, CPAL's JACK backend is currently only implemented for Linux and BSD systems. On other platforms, use the native backends (WASAPI/ASIO for Windows, CoreAudio for macOS).

### `wasm-bindgen`

**Platform:** WebAssembly (wasm32-unknown-unknown)

Enables the Web Audio API backend for browser-based audio. This is the base feature required for any WebAssembly audio support.

**Requirements:**
- Target `wasm32-unknown-unknown`
- Web browser with Web Audio API support

**Usage:** See the `wasm-beep` example for basic WebAssembly audio setup.

### `audioworklet`

**Platform:** WebAssembly (wasm32-unknown-unknown)

Enables the Audio Worklet backend for lower-latency web audio processing compared to the default Web Audio API backend.

**Requirements:**
- The `wasm-bindgen` feature (automatically enabled)
- Build with atomics support: `RUSTFLAGS="-C target-feature=+atomics,+bulk-memory,+mutable-globals"`
- Web server must send Cross-Origin headers for SharedArrayBuffer support

**Setup:** See the `audioworklet-beep` example README for complete setup instructions.

**Note:** Audio Worklet provides better performance than the default Web Audio API by running audio processing on a separate thread.

### `custom`

**Platform:** All platforms

[ASIO](https://en.wikipedia.org/wiki/Audio_Stream_Input/Output) is an audio
driver protocol by Steinberg. While it is available on multiple operating
systems, it is most commonly used on Windows to work around limitations of
WASAPI including access to large numbers of channels and lower-latency audio
processing.
Enables support for user-defined custom host implementations, allowing integration with audio systems not natively supported by CPAL.

CPAL allows for using the ASIO SDK as the audio host on Windows instead of
WASAPI.
**Usage:** See `examples/custom.rs` for implementation details.

## ASIO on Windows

### Locating the ASIO SDK

Expand All @@ -64,78 +109,81 @@ The build script will try to find the ASIO SDK by following these steps in order

In an ideal situation you don't need to worry about this step.

### Preparing the build environment
### Preparing the Build Environment

1. **Install LLVM/Clang**: `bindgen`, the library used to generate bindings to the C++ SDK, requires clang. Download and install LLVM from <http://releases.llvm.org/download.html> under the "Pre-Built Binaries" section.

1. `bindgen`, the library used to generate bindings to the C++ SDK, requires
clang. **Download and install LLVM** from
[here](http://releases.llvm.org/download.html) under the "Pre-Built Binaries"
section. The version as of writing this is 17.0.1.
2. Add the LLVM `bin` directory to a `LIBCLANG_PATH` environment variable. If
you installed LLVM to the default directory, this should work in the command
prompt:
2. **Set LIBCLANG_PATH**: Add the LLVM `bin` directory to a `LIBCLANG_PATH` environment variable. If you installed LLVM to the default directory, this should work in the command prompt:
```
setx LIBCLANG_PATH "C:\Program Files\LLVM\bin"
```
3. If you don't have any ASIO devices or drivers available, you can [**download
and install ASIO4ALL**](http://www.asio4all.org/). Be sure to enable the
"offline" feature during installation despite what the installer says about
it being useless.
4. Our build script assumes that Microsoft Visual Studio is installed if the host OS for compilation is Windows. The script will try to find `vcvarsall.bat`
and execute it with the right host and target machine architecture regardless of the Microsoft Visual Studio version.
If there are any errors encountered in this process which is unlikely,
you may find the `vcvarsall.bat` manually and execute it with your machine architecture as an argument.
The script will detect this and skip the step.

A manually executed command example for 64 bit machines:

3. **Install ASIO Drivers** (optional for testing): If you don't have any ASIO devices or drivers available, you can download and install ASIO4ALL from <http://www.asio4all.org/>. Be sure to enable the "offline" feature during installation.

4. **Visual Studio**: The build script assumes Microsoft Visual Studio is installed. It will try to find `vcvarsall.bat` and execute it with the right host and target architecture. If needed, you can manually execute it:
```
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
```
For more information see the [vcvarsall.bat documentation](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line).

For more information please refer to the documentation of [`vcvarsall.bat``](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160#vcvarsall-syntax).
### Using ASIO in Your Application

5. Select the ASIO host at the start of our program with the following code:
1. **Enable the feature** in your `Cargo.toml`:
```toml
cpal = { version = "*", features = ["asio"] }
```

2. **Select the ASIO host** in your code:
```rust
let host;
#[cfg(target_os = "windows")]
{
host = cpal::host_from_id(cpal::HostId::Asio).expect("failed to initialise ASIO host");
}
let host = cpal::host_from_id(cpal::HostId::Asio)
.expect("failed to initialise ASIO host");
```

If you run into compilations errors produced by `asio-sys` or `bindgen`, make
sure that `CPAL_ASIO_DIR` is set correctly and try `cargo clean`.
### Troubleshooting

6. Make sure to enable the `asio` feature when building CPAL:
If you encounter compilation errors from `asio-sys` or `bindgen`:
- Verify `CPAL_ASIO_DIR` is set correctly
- Try running `cargo clean`
- Ensure LLVM/Clang is properly installed and `LIBCLANG_PATH` is set

```
cargo build --features "asio"
```
### Cross-Compilation

or if you are using CPAL as a dependency in a downstream project, enable the
feature like this:
When Windows is the host and target OS, the build script supports all cross-compilation targets supported by the MSVC compiler.

```toml
cpal = { version = "*", features = ["asio"] }
```
It is also possible to compile Windows applications with ASIO support on Linux and macOS using the MinGW-w64 toolchain.

_Updated as of ASIO version 2.3.3._
**Requirements:**
- Include the MinGW-w64 include directory in your `CPLUS_INCLUDE_PATH` environment variable
- Include the LLVM include directory in your `CPLUS_INCLUDE_PATH` environment variable

### Cross compilation
**Example for macOS** (targeting `x86_64-pc-windows-gnu` with `mingw-w64` installed via brew):
```
export CPLUS_INCLUDE_PATH="$CPLUS_INCLUDE_PATH:/opt/homebrew/Cellar/mingw-w64/11.0.1/toolchain-x86_64/x86_64-w64-mingw32/include"
```

When Windows is the host and the target OS, the build script of `asio-sys` supports all cross compilation targets
which are supported by the MSVC compiler. An exhaustive list of combinations could be found [here](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160#vcvarsall-syntax) with the addition of undocumented `arm64`, `arm64_x86`, `arm64_amd64` and `arm64_arm` targets. (5.11.2023)
## Troubleshooting

It is also possible to compile Windows applications with ASIO support on Linux and macOS.
### No Default Device Available

For both platforms the common way to do this is to use the [MinGW-w64](https://www.mingw-w64.org/) toolchain.
If you receive errors about no default input or output device:

Make sure that you have included the `MinGW-w64` include directory in your `CPLUS_INCLUDE_PATH` environment variable.
Make sure that LLVM is installed and include directory is also included in your `CPLUS_INCLUDE_PATH` environment variable.
- **Linux/ALSA:** Ensure your user is in the `audio` group and that ALSA is properly configured
- **Linux/PulseAudio:** Check that PulseAudio is running: `pulseaudio --check`
- **Windows:** Verify your audio device is enabled in Sound Settings
- **macOS:** Check System Preferences > Sound for available devices
- **Mobile (iOS/Android):** Ensure your app has microphone/audio permissions

Example for macOS for the target of `x86_64-pc-windows-gnu` where `mingw-w64` is installed via brew:
### Buffer Size Issues

```
export CPLUS_INCLUDE_PATH="$CPLUS_INCLUDE_PATH:/opt/homebrew/Cellar/mingw-w64/11.0.1/toolchain-x86_64/x86_64-w64-mingw32/include"
```
If you experience audio glitches or dropouts:

- Try `BufferSize::Default` first before requesting specific sizes
- When using `BufferSize::Fixed`, query `SupportedBufferSize` to find valid ranges
- Smaller buffers reduce latency but increase CPU load and risk dropouts
- Ensure your audio callback completes quickly and avoids blocking operations

### Build Errors

- **ASIO on Windows:** Verify `LIBCLANG_PATH` is set and LLVM is installed
- **ALSA on Linux:** Install development packages: `libasound2-dev` (Debian/Ubuntu) or `alsa-lib-devel` (Fedora)
- **JACK:** Install JACK development libraries before enabling the `jack` feature
13 changes: 13 additions & 0 deletions examples/beep.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
//! Plays a simple 440 Hz sine wave (beep) tone.
//!
//! This example demonstrates:
//! - Selecting audio hosts (with optional JACK support on Linux)
//! - Selecting devices by ID or using the default output device
//! - Querying the default output configuration
//! - Building and running an output stream with typed samples
//! - Generating audio data in the stream callback
//!
//! Run with: `cargo run --example beep`
//! With JACK (Linux): `cargo run --example beep --features jack -- --jack`
//! With specific device: `cargo run --example beep -- --device "wasapi:device_id"`

use clap::Parser;
use cpal::{
traits::{DeviceTrait, HostTrait, StreamTrait},
Expand Down
11 changes: 11 additions & 0 deletions examples/enumerate.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
//! Enumerates all available audio hosts, devices, and their supported configurations.
//!
//! This example demonstrates:
//! - Querying available audio hosts on the system
//! - Enumerating all audio devices for each host
//! - Retrieving device IDs for persistent identification
//! - Getting device descriptions with metadata
//! - Listing supported input and output stream configurations
//!
//! Run with: `cargo run --example enumerate`
extern crate anyhow;
extern crate cpal;

Expand Down
8 changes: 7 additions & 1 deletion src/device_description.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
//! Device metadata and description types.
//!
//! This module provides structured information about audio devices including manufacturer,
//! device type, interface type, and connection details. Not all backends provide complete
//! information - availability depends on platform capabilities.
use std::fmt;

use crate::ChannelCount;
Expand Down Expand Up @@ -29,7 +35,7 @@ pub struct DeviceDescription {
/// Physical address or connection identifier
address: Option<String>,

/// Additional description lines with non-structured, detailed information
/// Additional description lines with non-structured, detailed information.
extended: Vec<String>,
}

Expand Down
9 changes: 5 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ impl Error for HostUnavailable {}
/// `panic!` caused by some unforeseen or unknown reason.
///
/// **Note:** If you notice a `BackendSpecificError` that you believe could be better handled in a
/// cross-platform manner, please create an issue or submit a pull request with a patch that adds
/// the necessary error variant to the appropriate error enum.
/// cross-platform manner, please create an issue at <https://github.com/RustAudio/cpal/issues>
/// with details about your use case, the backend you're using, and the error message. Or submit
/// a pull request with a patch that adds the necessary error variant to the appropriate error enum.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct BackendSpecificError {
pub description: String,
Expand Down Expand Up @@ -65,7 +66,7 @@ impl From<BackendSpecificError> for DevicesError {
}
}

/// An error that may occur while attempting to retrieve a device id.
/// An error that may occur while attempting to retrieve a device ID.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DeviceIdError {
/// See the [`BackendSpecificError`] docs for more information about this error variant.
Expand All @@ -79,7 +80,7 @@ impl Display for DeviceIdError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::BackendSpecific { err } => err.fmt(f),
Self::UnsupportedPlatform => f.write_str("Device ids are unsupported for this OS"),
Self::UnsupportedPlatform => f.write_str("Device IDs are unsupported for this OS"),
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/host/aaudio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! AAudio backend implementation.
//!
//! Default backend on Android.

use std::cmp;
use std::convert::TryInto;
use std::sync::{Arc, Mutex};
Expand Down
4 changes: 4 additions & 0 deletions src/host/alsa/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! ALSA backend implementation.
//!
//! Default backend on Linux and BSD systems.

extern crate alsa;
extern crate libc;

Expand Down
Loading