devices/virtio/snd/sys/
linux.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
5#[cfg(feature = "audio_aaudio")]
6use android_audio::AndroidAudioStreamSourceGenerator;
7use async_trait::async_trait;
8use audio_streams::capture::AsyncCaptureBuffer;
9use audio_streams::capture::AsyncCaptureBufferStream;
10use audio_streams::AsyncPlaybackBufferStream;
11use audio_streams::BoxError;
12use audio_streams::StreamSource;
13use audio_streams::StreamSourceGenerator;
14#[cfg(feature = "audio_cras")]
15use base::error;
16use base::set_rt_prio_limit;
17use base::set_rt_round_robin;
18use cros_async::Executor;
19use futures::channel::mpsc::UnboundedSender;
20#[cfg(feature = "audio_cras")]
21use libcras::CrasStreamSourceGenerator;
22#[cfg(feature = "audio_cras")]
23use libcras::CrasStreamType;
24use serde::Deserialize;
25use serde::Serialize;
26
27use crate::virtio::snd::common_backend::async_funcs::CaptureBufferReader;
28use crate::virtio::snd::common_backend::async_funcs::PlaybackBufferWriter;
29use crate::virtio::snd::common_backend::stream_info::StreamInfo;
30use crate::virtio::snd::common_backend::DirectionalStream;
31use crate::virtio::snd::common_backend::Error;
32use crate::virtio::snd::common_backend::PcmResponse;
33use crate::virtio::snd::common_backend::SndData;
34use crate::virtio::snd::parameters::Error as ParametersError;
35use crate::virtio::snd::parameters::Parameters;
36
37const AUDIO_THREAD_RTPRIO: u16 = 10; // Matches other cros audio clients.
38
39pub(crate) type SysAudioStreamSourceGenerator = Box<dyn StreamSourceGenerator>;
40pub(crate) type SysAudioStreamSource = Box<dyn StreamSource>;
41pub(crate) type SysBufferReader = UnixBufferReader;
42
43pub struct SysDirectionOutput {
44    pub async_playback_buffer_stream: Box<dyn audio_streams::AsyncPlaybackBufferStream>,
45    pub buffer_writer: Box<dyn PlaybackBufferWriter>,
46}
47
48pub(crate) struct SysAsyncStreamObjects {
49    pub(crate) stream: DirectionalStream,
50    pub(crate) pcm_sender: UnboundedSender<PcmResponse>,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
54pub enum StreamSourceBackend {
55    #[cfg(feature = "audio_aaudio")]
56    AAUDIO,
57    #[cfg(feature = "audio_cras")]
58    CRAS,
59}
60
61// Implemented to make backend serialization possible, since we deserialize from str.
62impl From<StreamSourceBackend> for String {
63    fn from(backend: StreamSourceBackend) -> Self {
64        match backend {
65            #[cfg(feature = "audio_aaudio")]
66            StreamSourceBackend::AAUDIO => "aaudio".to_owned(),
67            #[cfg(feature = "audio_cras")]
68            StreamSourceBackend::CRAS => "cras".to_owned(),
69        }
70    }
71}
72
73impl TryFrom<&str> for StreamSourceBackend {
74    type Error = ParametersError;
75
76    fn try_from(s: &str) -> Result<Self, Self::Error> {
77        match s {
78            #[cfg(feature = "audio_aaudio")]
79            "aaudio" => Ok(StreamSourceBackend::AAUDIO),
80            #[cfg(feature = "audio_cras")]
81            "cras" => Ok(StreamSourceBackend::CRAS),
82            _ => Err(ParametersError::InvalidBackend),
83        }
84    }
85}
86
87#[cfg(feature = "audio_aaudio")]
88pub(crate) fn create_aaudio_stream_source_generators(
89    snd_data: &SndData,
90) -> Vec<SysAudioStreamSourceGenerator> {
91    let mut generators: Vec<Box<dyn StreamSourceGenerator>> =
92        Vec::with_capacity(snd_data.pcm_info_len());
93    for pcm_info in snd_data.pcm_info_iter() {
94        assert_eq!(pcm_info.features, 0); // Should be 0. Android audio backend does not support any features.
95        generators.push(Box::new(AndroidAudioStreamSourceGenerator::new()));
96    }
97    generators
98}
99
100#[cfg(feature = "audio_cras")]
101pub(crate) fn create_cras_stream_source_generators(
102    params: &Parameters,
103    snd_data: &SndData,
104) -> Vec<Box<dyn StreamSourceGenerator>> {
105    let mut generators: Vec<Box<dyn StreamSourceGenerator>> =
106        Vec::with_capacity(snd_data.pcm_info_len());
107    for pcm_info in snd_data.pcm_info_iter() {
108        let device_params = params.get_device_params(pcm_info).unwrap_or_else(|err| {
109            error!("Create cras stream source generator error: {}", err);
110            Default::default()
111        });
112        generators.push(Box::new(CrasStreamSourceGenerator::with_stream_type(
113            params.capture,
114            device_params.client_type.unwrap_or(params.client_type),
115            params.socket_type,
116            device_params
117                .stream_type
118                .unwrap_or(CrasStreamType::CRAS_STREAM_TYPE_DEFAULT),
119        )));
120    }
121    generators
122}
123
124#[allow(unused_variables)]
125pub(crate) fn create_stream_source_generators(
126    backend: StreamSourceBackend,
127    params: &Parameters,
128    snd_data: &SndData,
129) -> Vec<Box<dyn StreamSourceGenerator>> {
130    match backend {
131        #[cfg(feature = "audio_aaudio")]
132        StreamSourceBackend::AAUDIO => create_aaudio_stream_source_generators(snd_data),
133        #[cfg(feature = "audio_cras")]
134        StreamSourceBackend::CRAS => create_cras_stream_source_generators(params, snd_data),
135    }
136}
137
138pub(crate) fn set_audio_thread_priority() -> Result<(), base::Error> {
139    set_rt_prio_limit(u64::from(AUDIO_THREAD_RTPRIO))
140        .and_then(|_| set_rt_round_robin(i32::from(AUDIO_THREAD_RTPRIO)))
141}
142
143impl StreamInfo {
144    /// (*)
145    /// `buffer_size` in `audio_streams` API indicates the buffer size in bytes that the stream
146    /// consumes (or transmits) each time (next_playback/capture_buffer).
147    /// `period_bytes` in virtio-snd device (or ALSA) indicates the device transmits (or
148    /// consumes) for each PCM message.
149    /// Therefore, `buffer_size` in `audio_streams` == `period_bytes` in virtio-snd.
150    async fn set_up_async_playback_stream(
151        &mut self,
152        frame_size: usize,
153        ex: &Executor,
154    ) -> Result<Box<dyn AsyncPlaybackBufferStream>, Error> {
155        Ok(self
156            .stream_source
157            .as_mut()
158            .ok_or(Error::EmptyStreamSource)?
159            .async_new_async_playback_stream(
160                self.channels as usize,
161                self.format,
162                self.frame_rate,
163                // See (*)
164                self.period_bytes / frame_size,
165                ex,
166            )
167            .await
168            .map_err(Error::CreateStream)?
169            .1)
170    }
171
172    pub(crate) async fn set_up_async_capture_stream(
173        &mut self,
174        frame_size: usize,
175        ex: &Executor,
176    ) -> Result<SysBufferReader, Error> {
177        let async_capture_buffer_stream = self
178            .stream_source
179            .as_mut()
180            .ok_or(Error::EmptyStreamSource)?
181            .async_new_async_capture_stream(
182                self.channels as usize,
183                self.format,
184                self.frame_rate,
185                self.period_bytes / frame_size,
186                &self.effects,
187                ex,
188            )
189            .await
190            .map_err(Error::CreateStream)?
191            .1;
192        Ok(SysBufferReader::new(async_capture_buffer_stream))
193    }
194
195    pub(crate) async fn create_directionstream_output(
196        &mut self,
197        frame_size: usize,
198        ex: &Executor,
199    ) -> Result<DirectionalStream, Error> {
200        let async_playback_buffer_stream =
201            self.set_up_async_playback_stream(frame_size, ex).await?;
202
203        let buffer_writer = UnixBufferWriter::new(self.period_bytes);
204
205        Ok(DirectionalStream::Output(SysDirectionOutput {
206            async_playback_buffer_stream,
207            buffer_writer: Box::new(buffer_writer),
208        }))
209    }
210}
211
212pub(crate) struct UnixBufferReader {
213    async_stream: Box<dyn AsyncCaptureBufferStream>,
214}
215
216impl UnixBufferReader {
217    fn new(async_stream: Box<dyn AsyncCaptureBufferStream>) -> Self
218    where
219        Self: Sized,
220    {
221        UnixBufferReader { async_stream }
222    }
223}
224#[async_trait(?Send)]
225impl CaptureBufferReader for UnixBufferReader {
226    async fn get_next_capture_period(
227        &mut self,
228        ex: &Executor,
229    ) -> Result<AsyncCaptureBuffer, BoxError> {
230        Ok(self
231            .async_stream
232            .next_capture_buffer(ex)
233            .await
234            .map_err(Error::FetchBuffer)?)
235    }
236}
237
238pub(crate) struct UnixBufferWriter {
239    guest_period_bytes: usize,
240}
241
242#[async_trait(?Send)]
243impl PlaybackBufferWriter for UnixBufferWriter {
244    fn new(guest_period_bytes: usize) -> Self {
245        UnixBufferWriter { guest_period_bytes }
246    }
247    fn endpoint_period_bytes(&self) -> usize {
248        self.guest_period_bytes
249    }
250}