Skip to content

Commit 73f4294

Browse files
committed
ASIO: Extension trait + open control panel
1 parent 6627959 commit 73f4294

5 files changed

Lines changed: 77 additions & 0 deletions

File tree

CHANGELOG.md

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

1718
### Changed

asio-sys/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ fn main() {
7272
// Print out links to needed libraries
7373
println!("cargo:rustc-link-lib=dylib=ole32");
7474
println!("cargo:rustc-link-lib=dylib=user32");
75+
println!("cargo:rustc-link-lib=dylib=Advapi32");
7576
println!("cargo:rustc-link-search={}", out_dir.display());
7677
println!("cargo:rustc-link-lib=static=asio");
7778
println!("cargo:rustc-cfg=asio");
@@ -237,6 +238,7 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
237238
.allowlist_function("ASIOStart")
238239
.allowlist_function("ASIOStop")
239240
.allowlist_function("ASIODisposeBuffers")
241+
.allowlist_function("ASIOControlPanel")
240242
.allowlist_function("ASIOExit")
241243
.allowlist_function("load_asio_driver")
242244
.allowlist_function("remove_current_driver")

asio-sys/src/bindings/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,11 @@ impl Driver {
788788
let mut mcb = MESSAGE_CALLBACKS.lock().unwrap();
789789
mcb.retain(|&(id, _)| id != rem_id);
790790
}
791+
792+
/// Opens the ASIO driver's control panel window.
793+
pub fn open_control_panel(&self) -> Result<(), AsioError> {
794+
unsafe { asio_result!(ai::ASIOControlPanel()) }
795+
}
791796
}
792797

793798
impl DriverState {

src/platform/asio.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! Implementations for ASIO-specific device functionality.
2+
3+
use crate::BackendSpecificError;
4+
use crate::Device;
5+
6+
/// Extension trait for ASIO-specific device functionality.
7+
pub trait AsioDeviceExt {
8+
/// Returns `true` if this device is an ASIO device.
9+
fn is_asio_device(&self) -> bool;
10+
11+
/// Opens the ASIO driver's control panel window.
12+
///
13+
/// This provides access to device-specific settings like buffer size,
14+
/// sample rate, input/output routing, and hardware-specific features.
15+
///
16+
/// # Blocking Behavior
17+
///
18+
/// **WARNING**: This call may block until the user closes the control panel.
19+
/// Consider spawning a thread to avoid blocking the main thread.
20+
///
21+
/// # Errors
22+
///
23+
/// Returns an error if this device is not an ASIO device.
24+
fn asio_open_control_panel(&self) -> Result<(), BackendSpecificError>;
25+
}
26+
27+
#[cfg(all(target_os = "windows", feature = "asio"))]
28+
impl AsioDeviceExt for Device {
29+
fn is_asio_device(&self) -> bool {
30+
matches!(self.as_inner(), crate::platform::DeviceInner::Asio(_))
31+
}
32+
33+
fn asio_open_control_panel(&self) -> Result<(), BackendSpecificError> {
34+
use crate::platform::DeviceInner;
35+
36+
if let DeviceInner::Asio(ref asio_device) = self.as_inner() {
37+
asio_device
38+
.driver
39+
.open_control_panel()
40+
.map_err(|e| BackendSpecificError {
41+
description: format!("Failed to open control panel: {:?}", e),
42+
})
43+
} else {
44+
Err(BackendSpecificError {
45+
description: "Not an ASIO device".to_string(),
46+
})
47+
}
48+
}
49+
}
50+
51+
#[cfg(not(all(target_os = "windows", feature = "asio")))]
52+
impl AsioDeviceExt for Device {
53+
fn is_asio_device(&self) -> bool {
54+
false
55+
}
56+
57+
fn asio_open_control_panel(&self) -> Result<(), BackendSpecificError> {
58+
Err(not_available())
59+
}
60+
}
61+
62+
#[cfg(not(all(target_os = "windows", feature = "asio")))]
63+
fn not_available() -> BackendSpecificError {
64+
BackendSpecificError {
65+
description: "ASIO is not available on this platform".to_string(),
66+
}
67+
}

src/platform/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub use self::platform_impl::*;
1010
#[cfg(feature = "custom")]
1111
pub use crate::host::custom::{Device as CustomDevice, Host as CustomHost, Stream as CustomStream};
1212

13+
pub mod asio;
14+
1315
/// A macro to assist with implementing a platform's dynamically dispatched [`Host`] type.
1416
///
1517
/// These dynamically dispatched types are necessary to allow for users to switch between hosts at

0 commit comments

Comments
 (0)