use super::*;
impl Maolan {
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn apply_hw_selected(&self, hw: &AudioDeviceOption) {
let mut state = self.state.blocking_write();
let selected = Self::selected_output_device_for_platform(&mut state, hw);
state.selected_hw = Some(selected);
}
#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")))]
pub(super) fn apply_hw_selected(&self, hw: &String) {
self.state.blocking_write().selected_hw = Some(hw.to_string());
}
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn apply_hw_input_selected(&self, hw: &AudioDeviceOption) {
let mut state = self.state.blocking_write();
let selected = Self::select_refreshed_device(
&mut state.available_hw,
hw,
crate::state::discover_output_audio_devices,
);
state.selected_input_hw = Some(selected.clone());
Self::update_bits_from_selected_device(&mut state, &selected);
}
#[cfg(target_os = "linux")]
pub(super) fn apply_hw_input_selected(&self, hw: &AudioDeviceOption) {
let mut state = self.state.blocking_write();
let selected = Self::select_refreshed_device(
&mut state.available_input_hw,
hw,
crate::state::discover_alsa_input_devices,
);
state.selected_input_hw = Some(selected);
Self::update_bits_from_selected_device(&mut state, hw);
}
#[cfg(target_os = "windows")]
pub(super) fn apply_hw_input_selected(&self, hw: &String) {
self.state.blocking_write().selected_input_hw = Some(hw.to_string());
}
pub(super) fn apply_hw_backend_selected(&self, backend: &crate::state::AudioBackendOption) {
let mut state = self.state.blocking_write();
state.selected_backend = backend.clone();
state.selected_hw = None;
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "openbsd",
target_os = "windows"
))]
{
state.selected_input_hw = None;
state.oss_bits = 32;
Self::apply_backend_device_defaults(&mut state, backend);
}
}
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn select_refreshed_device(
available_devices: &mut Vec<AudioDeviceOption>,
current: &AudioDeviceOption,
discover: fn() -> Vec<AudioDeviceOption>,
) -> AudioDeviceOption {
let refreshed = discover();
let selected = refreshed
.iter()
.find(|candidate| candidate.id == current.id)
.cloned()
.unwrap_or_else(|| current.clone());
if !refreshed.is_empty() {
*available_devices = refreshed;
}
selected
}
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn selected_output_device_for_platform(
state: &mut crate::state::StateData,
hw: &AudioDeviceOption,
) -> AudioDeviceOption {
let selected = Self::select_refreshed_device(
&mut state.available_hw,
hw,
crate::state::discover_output_audio_devices,
);
Self::update_bits_from_selected_device(state, &selected);
selected
}
#[cfg(target_os = "linux")]
pub(super) fn selected_output_device_for_platform(
state: &mut crate::state::StateData,
hw: &AudioDeviceOption,
) -> AudioDeviceOption {
Self::update_bits_from_selected_device(state, hw);
hw.clone()
}
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn update_bits_from_selected_device(
state: &mut crate::state::StateData,
selected: &AudioDeviceOption,
) {
if let Some(bits) = selected.preferred_bits() {
state.oss_bits = bits;
}
}
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn select_first_backend_output_device(
state: &mut crate::state::StateData,
discover: fn() -> Vec<AudioDeviceOption>,
) -> Option<AudioDeviceOption> {
let refreshed = discover();
let selected = refreshed.first().cloned();
if !refreshed.is_empty() {
state.available_hw = refreshed;
}
if let Some(selected_ref) = selected.as_ref() {
Self::update_bits_from_selected_device(state, selected_ref);
}
selected
}
#[cfg(target_os = "linux")]
pub(super) fn select_first_backend_input_device(
state: &mut crate::state::StateData,
discover: fn() -> Vec<AudioDeviceOption>,
) -> Option<AudioDeviceOption> {
let refreshed = discover();
let selected = refreshed.first().cloned();
if !refreshed.is_empty() {
state.available_input_hw = refreshed;
}
if let Some(selected_ref) = selected.as_ref() {
Self::update_bits_from_selected_device(state, selected_ref);
}
selected
}
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub(super) fn apply_backend_device_defaults(
state: &mut crate::state::StateData,
backend: &crate::state::AudioBackendOption,
) {
#[cfg(target_os = "freebsd")]
if !matches!(backend, crate::state::AudioBackendOption::Oss) {
return;
}
#[cfg(target_os = "openbsd")]
if !matches!(backend, crate::state::AudioBackendOption::Sndio) {
return;
}
state.selected_hw = Self::select_first_backend_output_device(
state,
crate::state::discover_output_audio_devices,
);
state.selected_input_hw = state.selected_hw.clone();
}
#[cfg(target_os = "linux")]
pub(super) fn apply_backend_device_defaults(
state: &mut crate::state::StateData,
backend: &crate::state::AudioBackendOption,
) {
if !matches!(backend, crate::state::AudioBackendOption::Alsa) {
return;
}
state.selected_hw = Self::select_first_backend_output_device(
state,
crate::state::discover_alsa_output_devices,
);
state.selected_input_hw = Self::select_first_backend_input_device(
state,
crate::state::discover_alsa_input_devices,
);
}
#[cfg(target_os = "windows")]
pub(super) fn apply_backend_device_defaults(
state: &mut crate::state::StateData,
backend: &crate::state::AudioBackendOption,
) {
if !matches!(backend, crate::state::AudioBackendOption::Wasapi) {
return;
}
state.available_hw = crate::state::discover_windows_audio_devices();
state.available_input_hw = crate::state::discover_windows_input_devices();
state.selected_hw = state.available_hw.first().cloned();
state.selected_input_hw = state.available_input_hw.first().cloned();
if let Some(selected) = state.selected_hw.as_ref() {
state.oss_bits = crate::state::discover_windows_output_bit_depths(selected)
.first()
.copied()
.unwrap_or(32);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(target_os = "linux")]
fn apply_hw_backend_selected_updates_state() {
let app = Maolan::default();
let backend = crate::state::AudioBackendOption::Alsa;
app.apply_hw_backend_selected(&backend);
let state = app.state.blocking_read();
assert!(matches!(
state.selected_backend,
crate::state::AudioBackendOption::Alsa
));
assert!(state.selected_hw.is_none());
}
#[test]
#[cfg(unix)]
fn apply_hw_backend_selected_jack_updates_state() {
let app = Maolan::default();
let backend = crate::state::AudioBackendOption::Jack;
app.apply_hw_backend_selected(&backend);
let state = app.state.blocking_read();
assert!(matches!(
state.selected_backend,
crate::state::AudioBackendOption::Jack
));
assert!(state.selected_hw.is_none());
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
fn select_refreshed_device_returns_clone_when_not_found() {
let current = AudioDeviceOption::with_supported_caps(
"hw:0".to_string(),
"Test Device".to_string(),
vec![16, 24, 32],
vec![44100, 48000],
);
let mut available = Vec::new();
let selected = Maolan::select_refreshed_device(&mut available, ¤t, Vec::new);
assert_eq!(selected.id, current.id);
}
#[test]
fn update_bits_from_selected_device_sets_oss_bits() {
let mut state = crate::state::StateData::default();
let device = AudioDeviceOption::with_supported_caps(
"hw:0".to_string(),
"Test".to_string(),
vec![16, 24],
vec![48000],
);
Maolan::update_bits_from_selected_device(&mut state, &device);
assert_eq!(state.oss_bits, 24);
}
}