gled-core 2.31.2

The engine of gled without a user interface: inputs, timing, rendering, Art-Net/DMX output and storage
Documentation
//! The audio input device a project uses, kept as cpal's device id in its text
//! form. The model stores the text so it does not depend on cpal; only the
//! machine that opens the device parses it.

use std::str::FromStr;

use cpal::DeviceId;

pub(crate) use gled_model::sound::AudioDeviceId;

/// The stored form of a cpal device id.
pub(crate) fn audio_device_id(id: &DeviceId) -> AudioDeviceId {
    AudioDeviceId(id.to_string())
}

/// The cpal device id, or `None` when the text is not one this cpal knows,
/// for example a project saved on another operating system.
pub(crate) fn cpal_device_id(id: &AudioDeviceId) -> Option<DeviceId> {
    DeviceId::from_str(&id.0)
        .map_err(|err| tracing::warn!("Unknown audio device id {:?}: {err}", id.0))
        .ok()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn keeps_the_json_of_older_projects() {
        let id: Option<AudioDeviceId> =
            serde_json::from_str("\"ALSA://device/1\"").expect("a string");
        assert_eq!(
            serde_json::to_string(&id).expect("serializes"),
            "\"ALSA://device/1\""
        );
        let none: Option<AudioDeviceId> = serde_json::from_str("null").expect("null");
        assert_eq!(none, None);
        let parsed = cpal_device_id(&AudioDeviceId("ALSA://device/1".to_string()))
            .expect("parses as a cpal id");
        // cpal writes the host in lower case; what matters is the same device.
        assert_eq!(cpal_device_id(&audio_device_id(&parsed)), Some(parsed));
    }
}