sound: add unit tests to alsa backend
Test whatever we can without actually playing/recording everything; this would require integration tests, not unit tests. Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This commit is contained in:
parent
d523e85efa
commit
a46d8d8bab
3 changed files with 639 additions and 0 deletions
|
|
@ -724,3 +724,512 @@ impl AudioBackend for AlsaBackend {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Utilities for temporarily setting a test-specific alsa config.
|
||||
pub mod test_utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{test_utils::setup_alsa_conf, *};
|
||||
use crate::{stream::PcmParams, virtio_sound::*};
|
||||
|
||||
const RATES: [u8; _VIRTIO_SND_PCM_RATE_MAX as usize] = [
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_5512,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_8000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_11025,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_16000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_22050,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_32000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_44100,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_48000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_64000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_88200,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_96000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_176400,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_192000,
|
||||
virtio_sound::VIRTIO_SND_PCM_RATE_384000,
|
||||
];
|
||||
|
||||
const FORMATS: [u8; _VIRTIO_SND_PCM_FMT_MAX as usize] = [
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_IMA_ADPCM,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_MU_LAW,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_A_LAW,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S8,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U8,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S16,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U16,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S18_3,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U18_3,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S20_3,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U20_3,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S24_3,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U24_3,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S20,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U20,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S24,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U24,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_S32,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_U32,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_FLOAT,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_FLOAT64,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_DSD_U8,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_DSD_U16,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_DSD_U32,
|
||||
virtio_sound::VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME,
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn test_alsa_trait_impls() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let _: alsa::Direction = Direction::Output.into();
|
||||
let _: alsa::Direction = Direction::Input.into();
|
||||
|
||||
let backend = AlsaBackend::new(Default::default());
|
||||
#[allow(clippy::redundant_clone)]
|
||||
let _ = backend.clone();
|
||||
|
||||
_ = format!("{:?}", backend);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alsa_ops() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![
|
||||
Stream::default(),
|
||||
Stream {
|
||||
id: 1,
|
||||
direction: Direction::Input,
|
||||
..Stream::default()
|
||||
},
|
||||
]));
|
||||
let backend = AlsaBackend::new(streams);
|
||||
let request = VirtioSndPcmSetParams {
|
||||
hdr: VirtioSoundPcmHeader {
|
||||
stream_id: 0.into(),
|
||||
hdr: VirtioSoundHeader { code: 0.into() },
|
||||
},
|
||||
format: VIRTIO_SND_PCM_FMT_S16,
|
||||
rate: VIRTIO_SND_PCM_RATE_44100,
|
||||
channels: 2,
|
||||
features: 0.into(),
|
||||
buffer_bytes: 8192.into(),
|
||||
period_bytes: 4096.into(),
|
||||
padding: 0,
|
||||
};
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
backend.prepare(0).unwrap();
|
||||
backend.start(0).unwrap();
|
||||
backend.write(0).unwrap();
|
||||
backend.read(0).unwrap();
|
||||
backend.stop(0).unwrap();
|
||||
backend.release(0).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alsa_invalid_stream_id() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![
|
||||
Stream::default(),
|
||||
Stream {
|
||||
id: 1,
|
||||
direction: Direction::Input,
|
||||
..Stream::default()
|
||||
},
|
||||
]));
|
||||
let backend = AlsaBackend::new(streams);
|
||||
let request = VirtioSndPcmSetParams {
|
||||
hdr: VirtioSoundPcmHeader {
|
||||
stream_id: 3.into(),
|
||||
hdr: VirtioSoundHeader { code: 0.into() },
|
||||
},
|
||||
format: VIRTIO_SND_PCM_FMT_S16,
|
||||
rate: VIRTIO_SND_PCM_RATE_44100,
|
||||
channels: 2,
|
||||
features: 0.into(),
|
||||
buffer_bytes: 8192.into(),
|
||||
period_bytes: 4096.into(),
|
||||
padding: 0,
|
||||
};
|
||||
backend.set_parameters(3, request).unwrap_err();
|
||||
backend.prepare(3).unwrap_err();
|
||||
backend.start(3).unwrap_err();
|
||||
backend.write(3).unwrap_err();
|
||||
backend.read(3).unwrap_err();
|
||||
backend.stop(3).unwrap_err();
|
||||
backend.release(3).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alsa_invalid_state_transitions() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![
|
||||
Stream::default(),
|
||||
Stream {
|
||||
id: 1,
|
||||
direction: Direction::Input,
|
||||
..Stream::default()
|
||||
},
|
||||
]));
|
||||
let request = VirtioSndPcmSetParams {
|
||||
hdr: VirtioSoundPcmHeader {
|
||||
stream_id: 3.into(),
|
||||
hdr: VirtioSoundHeader { code: 0.into() },
|
||||
},
|
||||
format: VIRTIO_SND_PCM_FMT_S16,
|
||||
rate: VIRTIO_SND_PCM_RATE_44100,
|
||||
channels: 2,
|
||||
features: 0.into(),
|
||||
buffer_bytes: 8192.into(),
|
||||
period_bytes: 4096.into(),
|
||||
padding: 0,
|
||||
};
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
|
||||
// Invalid, but we allow it.
|
||||
backend.stop(0).unwrap();
|
||||
// Invalid, but we don't allow it.
|
||||
backend.release(0).unwrap_err();
|
||||
backend.start(0).unwrap_err();
|
||||
backend.release(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
|
||||
// set_parameters -> set_parameters | VALID
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
|
||||
// set_parameters -> prepare | VALID
|
||||
backend.prepare(0).unwrap();
|
||||
|
||||
// Invalid, but we allow it.
|
||||
// prepare -> stop | INVALID
|
||||
backend.stop(0).unwrap();
|
||||
// prepare -> release | VALID
|
||||
backend.release(0).unwrap();
|
||||
|
||||
// release -> start | INVALID
|
||||
backend.start(0).unwrap_err();
|
||||
// release -> stop | VALID
|
||||
backend.stop(0).unwrap();
|
||||
// release -> prepare | VALID
|
||||
backend.prepare(0).unwrap();
|
||||
|
||||
// prepare -> start | VALID
|
||||
backend.start(0).unwrap();
|
||||
|
||||
// start -> start | INVALID
|
||||
backend.start(0).unwrap_err();
|
||||
// start -> set_parameters | INVALID
|
||||
backend.set_parameters(0, request).unwrap_err();
|
||||
// start -> prepare | INVALID
|
||||
backend.prepare(0).unwrap_err();
|
||||
// start -> release | INVALID
|
||||
backend.release(0).unwrap_err();
|
||||
// start -> stop | VALID
|
||||
backend.stop(0).unwrap();
|
||||
// stop -> start | VALID
|
||||
backend.start(0).unwrap();
|
||||
// start -> stop | VALID
|
||||
backend.stop(0).unwrap();
|
||||
// stop -> prepare | INVALID
|
||||
backend.prepare(0).unwrap_err();
|
||||
// stop -> set_parameters | INVALID
|
||||
backend.set_parameters(0, request).unwrap_err();
|
||||
// stop -> release | VALID
|
||||
backend.release(0).unwrap();
|
||||
}
|
||||
|
||||
// Redundant checks? Oh well.
|
||||
//
|
||||
// Generated with:
|
||||
//
|
||||
// ```python
|
||||
// import itertools
|
||||
// states = ["SetParameters", "Prepare", "Release", "Start", "Stop"]
|
||||
// combs = set(itertools.product(states, repeat=2))
|
||||
// ```
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
backend.prepare(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.prepare(0).unwrap();
|
||||
backend.stop(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.start(0).unwrap();
|
||||
backend.start(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.prepare(0).unwrap_err();
|
||||
backend.start(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.stop(0).unwrap();
|
||||
backend.release(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.stop(0).unwrap();
|
||||
backend.prepare(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.release(0).unwrap();
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.start(0).unwrap_err();
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.prepare(0).unwrap();
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.release(0).unwrap_err();
|
||||
backend.read(0).unwrap_err();
|
||||
backend.write(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
backend.stop(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.release(0).unwrap_err();
|
||||
backend.prepare(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
backend.start(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.start(0).unwrap_err();
|
||||
backend.release(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.prepare(0).unwrap();
|
||||
backend.release(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.start(0).unwrap_err();
|
||||
backend.prepare(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.stop(0).unwrap();
|
||||
backend.stop(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.prepare(0).unwrap();
|
||||
backend.prepare(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.stop(0).unwrap();
|
||||
backend.start(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap_err();
|
||||
backend.release(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.release(0).unwrap_err();
|
||||
backend.stop(0).unwrap();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.stop(0).unwrap();
|
||||
backend.set_parameters(0, request).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.release(0).unwrap();
|
||||
backend.start(0).unwrap_err();
|
||||
}
|
||||
{
|
||||
let backend = AlsaBackend::new(streams);
|
||||
backend.start(0).unwrap_err();
|
||||
backend.stop(0).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alsa_worker() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![
|
||||
Stream::default(),
|
||||
Stream {
|
||||
id: 1,
|
||||
direction: Direction::Input,
|
||||
..Stream::default()
|
||||
},
|
||||
]));
|
||||
let (sender, receiver) = channel();
|
||||
let pcm = Arc::new(Mutex::new(
|
||||
PCM::new("null", Direction::Output.into(), false).unwrap(),
|
||||
));
|
||||
|
||||
let mtx = Arc::clone(&pcm);
|
||||
let streams = Arc::clone(&streams);
|
||||
let _handle =
|
||||
thread::spawn(move || alsa_worker(mtx.clone(), streams.clone(), &receiver, 0));
|
||||
sender.send(false).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alsa_valid_parameters() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![
|
||||
Stream::default(),
|
||||
Stream {
|
||||
id: 1,
|
||||
direction: Direction::Input,
|
||||
..Stream::default()
|
||||
},
|
||||
]));
|
||||
let mut request = VirtioSndPcmSetParams {
|
||||
hdr: VirtioSoundPcmHeader {
|
||||
stream_id: 0.into(),
|
||||
hdr: VirtioSoundHeader { code: 0.into() },
|
||||
},
|
||||
format: VIRTIO_SND_PCM_FMT_S16,
|
||||
rate: VIRTIO_SND_PCM_RATE_44100,
|
||||
channels: 2,
|
||||
features: 0.into(),
|
||||
buffer_bytes: 8192.into(),
|
||||
period_bytes: 4096.into(),
|
||||
padding: 0,
|
||||
};
|
||||
|
||||
for rate in RATES
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|rt| ((1 << *rt) & crate::SUPPORTED_RATES) > 0)
|
||||
{
|
||||
request.rate = rate;
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
}
|
||||
|
||||
for rate in RATES
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|rt| ((1 << *rt) & crate::SUPPORTED_RATES) == 0)
|
||||
{
|
||||
request.rate = rate;
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap_err();
|
||||
}
|
||||
request.rate = VIRTIO_SND_PCM_RATE_44100;
|
||||
|
||||
for format in FORMATS
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|fmt| ((1 << *fmt) & crate::SUPPORTED_FORMATS) > 0)
|
||||
{
|
||||
request.format = format;
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap();
|
||||
}
|
||||
|
||||
for format in FORMATS
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|fmt| ((1 << *fmt) & crate::SUPPORTED_FORMATS) == 0)
|
||||
{
|
||||
request.format = format;
|
||||
let backend = AlsaBackend::new(streams.clone());
|
||||
backend.set_parameters(0, request).unwrap_err();
|
||||
}
|
||||
|
||||
{
|
||||
for format in FORMATS
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|fmt| ((1 << *fmt) & crate::SUPPORTED_FORMATS) > 0)
|
||||
{
|
||||
let streams = Arc::new(RwLock::new(vec![Stream {
|
||||
params: PcmParams {
|
||||
format,
|
||||
..PcmParams::default()
|
||||
},
|
||||
..Stream::default()
|
||||
}]));
|
||||
let pcm = Arc::new(Mutex::new(
|
||||
PCM::new("null", Direction::Output.into(), false).unwrap(),
|
||||
));
|
||||
update_pcm(&pcm, 0, &streams).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "unreachable")]
|
||||
fn test_alsa_invalid_rate() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![Stream {
|
||||
params: PcmParams {
|
||||
rate: _VIRTIO_SND_PCM_RATE_MAX,
|
||||
..PcmParams::default()
|
||||
},
|
||||
..Stream::default()
|
||||
}]));
|
||||
let pcm = Arc::new(Mutex::new(
|
||||
PCM::new("null", Direction::Output.into(), false).unwrap(),
|
||||
));
|
||||
update_pcm(&pcm, 0, &streams).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "unreachable")]
|
||||
fn test_alsa_invalid_fmt() {
|
||||
crate::init_logger();
|
||||
let _harness = setup_alsa_conf();
|
||||
|
||||
let streams = Arc::new(RwLock::new(vec![Stream {
|
||||
params: PcmParams {
|
||||
format: _VIRTIO_SND_PCM_FMT_MAX,
|
||||
..PcmParams::default()
|
||||
},
|
||||
..Stream::default()
|
||||
}]));
|
||||
let pcm = Arc::new(Mutex::new(
|
||||
PCM::new("null", Direction::Output.into(), false).unwrap(),
|
||||
));
|
||||
update_pcm(&pcm, 0, &streams).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
128
staging/vhost-device-sound/src/audio_backends/alsa/test_utils.rs
Normal file
128
staging/vhost-device-sound/src/audio_backends/alsa/test_utils.rs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
|
||||
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::{
|
||||
atomic::{AtomicU8, Ordering},
|
||||
Arc, Mutex, Once,
|
||||
},
|
||||
};
|
||||
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
static mut TEST_HARNESS: Option<AlsaTestHarness> = None;
|
||||
static INIT_ALSA_CONF: Once = Once::new();
|
||||
|
||||
#[must_use]
|
||||
pub fn setup_alsa_conf() -> AlsaTestHarnessRef<'static> {
|
||||
INIT_ALSA_CONF.call_once(||
|
||||
// SAFETY:
|
||||
// This is only called once, because of.. `Once`, so it's safe to
|
||||
// access the static value mutably.
|
||||
unsafe {
|
||||
TEST_HARNESS = Some(AlsaTestHarness::new());
|
||||
});
|
||||
let retval = AlsaTestHarnessRef(
|
||||
// SAFETY:
|
||||
// The unsafe { } block is needed because TEST_HARNESS is a mutable static. The inner
|
||||
// operations are protected by atomics.
|
||||
unsafe { TEST_HARNESS.as_ref().unwrap() },
|
||||
);
|
||||
retval.0.inc_ref();
|
||||
retval
|
||||
}
|
||||
|
||||
/// The alsa test harness. It must only be constructed via
|
||||
/// `AlsaTestHarness::new()`.
|
||||
#[non_exhaustive]
|
||||
pub struct AlsaTestHarness {
|
||||
pub tempdir: Arc<Mutex<Option<TempDir>>>,
|
||||
pub conf_path: PathBuf,
|
||||
pub ref_count: AtomicU8,
|
||||
}
|
||||
|
||||
/// Ref counted alsa test harness ref.
|
||||
#[repr(transparent)]
|
||||
#[non_exhaustive]
|
||||
pub struct AlsaTestHarnessRef<'a>(&'a AlsaTestHarness);
|
||||
|
||||
impl<'a> Drop for AlsaTestHarnessRef<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.0.dec_ref();
|
||||
}
|
||||
}
|
||||
|
||||
impl AlsaTestHarness {
|
||||
pub fn new() -> Self {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let conf_path = tempdir.path().join("alsa.conf");
|
||||
|
||||
std::fs::write(
|
||||
&conf_path,
|
||||
b"pcm.!default {\n type null \n }\n\nctl.!default {\n type null\n }\n\npcm.null {\n type null \n }\n\nctl.null {\n type null\n }\n",
|
||||
).unwrap();
|
||||
|
||||
std::env::set_var("ALSA_CONFIG_PATH", &conf_path);
|
||||
println!(
|
||||
"INFO: setting ALSA_CONFIG_PATH={} in PID {} and TID {:?}",
|
||||
conf_path.display(),
|
||||
std::process::id(),
|
||||
std::thread::current().id()
|
||||
);
|
||||
|
||||
Self {
|
||||
tempdir: Arc::new(Mutex::new(Some(tempdir))),
|
||||
conf_path,
|
||||
ref_count: 0.into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inc_ref(&self) {
|
||||
let old_val = self.ref_count.fetch_add(1, Ordering::SeqCst);
|
||||
assert!(
|
||||
old_val != u8::MAX,
|
||||
"ref_count overflowed on 8bits when increasing by 1"
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dec_ref(&self) {
|
||||
let old_val = self.ref_count.fetch_sub(1, Ordering::SeqCst);
|
||||
if old_val == 1 {
|
||||
let mut lck = self.tempdir.lock().unwrap();
|
||||
println!(
|
||||
"INFO: unsetting ALSA_CONFIG_PATH={} in PID {} and TID {:?}",
|
||||
self.conf_path.display(),
|
||||
std::process::id(),
|
||||
std::thread::current().id()
|
||||
);
|
||||
std::env::remove_var("ALSA_CONFIG_PATH");
|
||||
_ = lck.take();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AlsaTestHarness {
|
||||
fn drop(&mut self) {
|
||||
let ref_count = self.ref_count.load(Ordering::SeqCst);
|
||||
if ref_count != 0 {
|
||||
println!(
|
||||
"ERROR: ref_count is {ref_count} when dropping {}",
|
||||
stringify!(AlsaTestHarness)
|
||||
);
|
||||
}
|
||||
if self
|
||||
.tempdir
|
||||
.lock()
|
||||
.map(|mut l| l.take().is_some())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
println!(
|
||||
"ERROR: tempdir held a value when dropping {}",
|
||||
stringify!(AlsaTestHarness)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -89,6 +89,7 @@ pub const VIRTIO_SND_PCM_FMT_DSD_U8: u8 = 21;
|
|||
pub const VIRTIO_SND_PCM_FMT_DSD_U16: u8 = 22;
|
||||
pub const VIRTIO_SND_PCM_FMT_DSD_U32: u8 = 23;
|
||||
pub const VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME: u8 = 24;
|
||||
pub(crate) const _VIRTIO_SND_PCM_FMT_MAX: u8 = 25;
|
||||
|
||||
// supported PCM frame rates
|
||||
|
||||
|
|
@ -106,6 +107,7 @@ pub const VIRTIO_SND_PCM_RATE_96000: u8 = 10;
|
|||
pub const VIRTIO_SND_PCM_RATE_176400: u8 = 11;
|
||||
pub const VIRTIO_SND_PCM_RATE_192000: u8 = 12;
|
||||
pub const VIRTIO_SND_PCM_RATE_384000: u8 = 13;
|
||||
pub(crate) const _VIRTIO_SND_PCM_RATE_MAX: u8 = 14;
|
||||
|
||||
// standard channel position definition
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue