Files
qbz/crates/qbz-audio/Cargo.toml
T
vicrodh a67e3c9217 Merge PR #391 (Vudgekek): macOS CoreAudio Exclusive Mode
Adds CoreAudio Hog Mode integration on macOS so Exclusive Mode actually
takes the device exclusively (previously the macOS path used the
Linux-shaped logic without any kernel-level lock). Pins the CoreAudio
device id through Hog Mode acquisition, sample-rate switching, and
stream creation so System Default doesn't drift mid-session. Linux
behaviour is unchanged.

Review asks (all four resolved by Vudgekek + afonsojramos):

- set_coreaudio_hardware_volume falls back to software volume on Err
  rather than reporting success, so knob-only DACs keep a working
  volume slider via engine.set_volume().
- CoreAudioExclusiveGuard snapshots the device's hardware volume on
  acquire and restores it before releasing Hog Mode, so leaving
  Exclusive Mode returns the DAC to the user's pre-Exclusive level.
  Guard is constructed before the FFI call so partial-acquire failures
  still trigger Drop and release.
- Linux unused-variable warnings on stream_opt and exclusive_guard
  cleaned up via cfg_attr(allow(unused_variables)) on the macOS-only
  guard plumbing. cargo check is clean.
- Silent shared-mode regression on macOS when backend init fails:
  init_device now sets_current_device(None) and returns None on
  exclusive_mode==true so the user sees an error instead of
  unknowingly playing in shared mode.

Bonus: 5f10b4ba adds real CoreAudio device-rate detection for macOS
Shared Mode, +90 lines in backend.rs.

Conflict resolution: single textual collision in
crates/qbz-audio/src/lib.rs (both branches added a pub use line).
Resolved by keeping both, alphabetical order — coreaudio_direct
re-export from pr-391, device_reservation re-export from pre-release.
All other auto-merges verified line-by-line: AlsaDirectStream's
DeviceReservation::acquire flow (alsa_direct.rs:60-97), the macOS
exclusive_mode guard (player/mod.rs:1077-1085 in qbz-player and the
mirror in src-tauri:1024), and CoreAudioExclusiveGuard's volume
snapshot/restore (coreaudio_direct.rs:351,369,373,388) all coexist
correctly because each branch touched different functions.

cargo check clean across all four crates. 9 device_reservation +
3 reserve_dac + 214 src-tauri unit tests pass.

cc
2026-05-07 19:09:37 -06:00

53 lines
1.4 KiB
TOML

[package]
name = "qbz-audio"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Audio backend system for QBZ - bit-perfect playback"
[dependencies]
qbz-models = { path = "../qbz-models" }
# Async
tokio = { workspace = true }
async-trait = { workspace = true }
# Logging
log = { workspace = true }
# Serialization
serde = { workspace = true }
serde_json = { workspace = true }
# Error handling
thiserror = { workspace = true }
# Audio playback (f32 pipeline is now upstream in rodio 0.22)
rodio = { version = "0.22", features = ["symphonia-all"] }
# Audio analysis
symphonia = { workspace = true }
ebur128 = "0.1"
rustfft = "6.4"
# Database for loudness cache
rusqlite = { version = "0.31", features = ["bundled"] }
# System directories
dirs = "6"
[target.'cfg(target_os = "linux")'.dependencies]
# ALSA for direct hardware access (bit-perfect)
alsa = "0.10"
# alsa-sys: direct FFI for snd_lib_error_set_handler (custom error routing)
alsa-sys = "0.3"
# zbus for org.freedesktop.ReserveDevice1 D-Bus client (device reservation).
# Pinned to v4 to share the transitive copy already pulled in by
# secret-service/souvlaki and avoid duplicate zbus compiles.
zbus = { version = "4", default-features = false, features = ["tokio"] }
[target.'cfg(target_os = "macos")'.dependencies]
# CoreAudio for device probing, sample rate switching, and (future) hog mode / exclusive mode
coreaudio-rs = "0.14.1"
objc2-core-audio = "0.3.2"