devices/virtio/snd/
file_backend.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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(&params.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            // Capture is not supported yet
71            Box::new(NoopStreamSourceGenerator::new())
72        };
73
74        generators.push(generator);
75    }
76    Ok(generators)
77}