devices/virtio/snd/
file_backend.rs1use std::fs::File;
6use std::fs::OpenOptions;
7use std::io::Error as IOError;
8use std::io::Seek;
9use std::io::SeekFrom;
10use std::io::Write;
11use std::path::Path;
12
13use audio_streams::NoopStreamSourceGenerator;
14use audio_util::FileStreamSourceGenerator;
15use base::error;
16use base::open_file_or_duplicate;
17use base::AsRawDescriptor;
18use base::RawDescriptor;
19use thiserror::Error as ThisError;
20
21use crate::virtio::snd::common_backend::SndData;
22use crate::virtio::snd::constants::VIRTIO_SND_D_OUTPUT;
23use crate::virtio::snd::parameters::Parameters;
24use crate::virtio::snd::sys::SysAudioStreamSourceGenerator;
25
26#[derive(ThisError, Debug)]
27pub enum Error {
28 #[error("Failed to allocate space: {0}")]
29 AllocateSpace(IOError),
30 #[error("Failed to open file: {0}")]
31 OpenFile(base::Error),
32}
33
34fn allocate_space(mut file: &File, size: usize) -> Result<(), Error> {
35 file.seek(SeekFrom::Start(size as u64))
36 .map_err(Error::AllocateSpace)?;
37 file.write_all(&[0]).map_err(Error::AllocateSpace)?;
38 file.seek(SeekFrom::Start(0))
39 .map_err(Error::AllocateSpace)?;
40 Ok(())
41}
42
43fn open_playback_file(dir_path: &String, stream_id: usize) -> Result<File, Error> {
44 let file_name = format!("stream-{stream_id}.out");
45 let file_path = Path::new(dir_path).join(file_name);
46 let file = open_file_or_duplicate(
47 file_path,
48 OpenOptions::new().read(true).create(true).write(true),
49 )
50 .map_err(Error::OpenFile)?;
51 Ok(file)
52}
53
54pub(crate) fn create_file_stream_source_generators(
55 params: &Parameters,
56 snd_data: &SndData,
57 keep_rds: &mut Vec<RawDescriptor>,
58) -> Result<Vec<SysAudioStreamSourceGenerator>, Error> {
59 let mut generators = Vec::new();
60
61 for (stream, pcm_info) in snd_data.pcm_info.iter().enumerate() {
62 let generator: SysAudioStreamSourceGenerator = if pcm_info.direction == VIRTIO_SND_D_OUTPUT
63 {
64 let file = open_playback_file(¶ms.playback_path, stream)?;
65 allocate_space(&file, params.playback_size)?;
66 keep_rds.push(file.as_raw_descriptor());
67
68 Box::new(FileStreamSourceGenerator::new(file, params.playback_size))
69 } else {
70 Box::new(NoopStreamSourceGenerator::new())
72 };
73
74 generators.push(generator);
75 }
76 Ok(generators)
77}