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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `DeviceBusy` error variant for retriable device access errors (EBUSY, EAGAIN).
- **ALSA**: `Debug` implementations for `Host`, `Device`, `Stream`, and internal types.
- **ALSA**: Example demonstrating ALSA error suppression during enumeration.
- **ASIO**: Extension trait for ASIO devices, which allows opening the control panel.
- **WASAPI**: Allow non-native sample rates to be used via as-necessary resampling in the WASAPI server process.

### Changed
Expand Down
2 changes: 2 additions & 0 deletions asio-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ fn main() {
// Print out links to needed libraries
println!("cargo:rustc-link-lib=dylib=ole32");
println!("cargo:rustc-link-lib=dylib=user32");
println!("cargo:rustc-link-lib=dylib=Advapi32");
println!("cargo:rustc-link-search={}", out_dir.display());
println!("cargo:rustc-link-lib=static=asio");
println!("cargo:rustc-cfg=asio");
Expand Down Expand Up @@ -237,6 +238,7 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
.allowlist_function("ASIOStart")
.allowlist_function("ASIOStop")
.allowlist_function("ASIODisposeBuffers")
.allowlist_function("ASIOControlPanel")
.allowlist_function("ASIOExit")
.allowlist_function("load_asio_driver")
.allowlist_function("remove_current_driver")
Expand Down
5 changes: 5 additions & 0 deletions asio-sys/src/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,11 @@ impl Driver {
let mut mcb = MESSAGE_CALLBACKS.lock().unwrap();
mcb.retain(|&(id, _)| id != rem_id);
}

/// Opens the ASIO driver's control panel window.
pub fn open_control_panel(&self) -> Result<(), AsioError> {
unsafe { asio_result!(ai::ASIOControlPanel()) }
}
}

impl DriverState {
Expand Down
67 changes: 67 additions & 0 deletions src/platform/asio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Implementations for ASIO-specific device functionality.

use crate::BackendSpecificError;
use crate::Device;

/// Extension trait for ASIO-specific device functionality.
pub trait AsioDeviceExt {
/// Returns `true` if this device is an ASIO device.
fn is_asio_device(&self) -> bool;

/// Opens the ASIO driver's control panel window.
///
/// This provides access to device-specific settings like buffer size,
/// sample rate, input/output routing, and hardware-specific features.
///
/// # Blocking Behavior
///
/// **WARNING**: This call may block until the user closes the control panel.
/// Consider spawning a thread to avoid blocking the main thread.
///
/// # Errors
///
/// Returns an error if this device is not an ASIO device.
fn asio_open_control_panel(&self) -> Result<(), BackendSpecificError>;
}

#[cfg(all(target_os = "windows", feature = "asio"))]
impl AsioDeviceExt for Device {
fn is_asio_device(&self) -> bool {
matches!(self.as_inner(), crate::platform::DeviceInner::Asio(_))
}

fn asio_open_control_panel(&self) -> Result<(), BackendSpecificError> {
use crate::platform::DeviceInner;

if let DeviceInner::Asio(ref asio_device) = self.as_inner() {
asio_device
.driver
.open_control_panel()
.map_err(|e| BackendSpecificError {
description: format!("Failed to open control panel: {:?}", e),
})
} else {
Err(BackendSpecificError {
description: "Not an ASIO device".to_string(),
})
}
}
}

#[cfg(not(all(target_os = "windows", feature = "asio")))]
impl AsioDeviceExt for Device {
fn is_asio_device(&self) -> bool {
false
}

fn asio_open_control_panel(&self) -> Result<(), BackendSpecificError> {
Err(not_available())
}
}

#[cfg(not(all(target_os = "windows", feature = "asio")))]
fn not_available() -> BackendSpecificError {
BackendSpecificError {
description: "ASIO is not available on this platform".to_string(),
}
}
2 changes: 2 additions & 0 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub use self::platform_impl::*;
#[cfg(feature = "custom")]
pub use crate::host::custom::{Device as CustomDevice, Host as CustomHost, Stream as CustomStream};

pub mod asio;

/// A macro to assist with implementing a platform's dynamically dispatched [`Host`] type.
///
/// These dynamically dispatched types are necessary to allow for users to switch between hosts at
Expand Down