xref: /aosp_15_r20/external/crosvm/devices/src/virtio/snd/sys/linux.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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")]
6 use android_audio::AndroidAudioStreamSourceGenerator;
7 use async_trait::async_trait;
8 use audio_streams::capture::AsyncCaptureBuffer;
9 use audio_streams::capture::AsyncCaptureBufferStream;
10 use audio_streams::AsyncPlaybackBufferStream;
11 use audio_streams::BoxError;
12 use audio_streams::StreamSource;
13 use audio_streams::StreamSourceGenerator;
14 #[cfg(feature = "audio_cras")]
15 use base::error;
16 use base::set_rt_prio_limit;
17 use base::set_rt_round_robin;
18 use cros_async::Executor;
19 use futures::channel::mpsc::UnboundedSender;
20 #[cfg(feature = "audio_cras")]
21 use libcras::CrasStreamSourceGenerator;
22 #[cfg(feature = "audio_cras")]
23 use libcras::CrasStreamType;
24 use serde::Deserialize;
25 use serde::Serialize;
26 
27 use crate::virtio::snd::common_backend::async_funcs::CaptureBufferReader;
28 use crate::virtio::snd::common_backend::async_funcs::PlaybackBufferWriter;
29 use crate::virtio::snd::common_backend::stream_info::StreamInfo;
30 use crate::virtio::snd::common_backend::DirectionalStream;
31 use crate::virtio::snd::common_backend::Error;
32 use crate::virtio::snd::common_backend::PcmResponse;
33 use crate::virtio::snd::common_backend::SndData;
34 use crate::virtio::snd::parameters::Error as ParametersError;
35 use crate::virtio::snd::parameters::Parameters;
36 
37 const AUDIO_THREAD_RTPRIO: u16 = 10; // Matches other cros audio clients.
38 
39 pub(crate) type SysAudioStreamSourceGenerator = Box<dyn StreamSourceGenerator>;
40 pub(crate) type SysAudioStreamSource = Box<dyn StreamSource>;
41 pub(crate) type SysBufferReader = UnixBufferReader;
42 
43 pub struct SysDirectionOutput {
44     pub async_playback_buffer_stream: Box<dyn audio_streams::AsyncPlaybackBufferStream>,
45     pub buffer_writer: Box<dyn PlaybackBufferWriter>,
46 }
47 
48 pub(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)]
54 pub 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.
62 impl From<StreamSourceBackend> for String {
from(backend: StreamSourceBackend) -> Self63     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 
73 impl TryFrom<&str> for StreamSourceBackend {
74     type Error = ParametersError;
75 
try_from(s: &str) -> Result<Self, Self::Error>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")]
create_aaudio_stream_source_generators( snd_data: &SndData, ) -> Vec<SysAudioStreamSourceGenerator>88 pub(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")]
create_cras_stream_source_generators( params: &Parameters, snd_data: &SndData, ) -> Vec<Box<dyn StreamSourceGenerator>>101 pub(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)]
create_stream_source_generators( backend: StreamSourceBackend, params: &Parameters, snd_data: &SndData, ) -> Vec<Box<dyn StreamSourceGenerator>>125 pub(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 
set_audio_thread_priority() -> Result<(), base::Error>138 pub(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 
143 impl 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.
set_up_async_playback_stream( &mut self, frame_size: usize, ex: &Executor, ) -> Result<Box<dyn AsyncPlaybackBufferStream>, Error>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 
set_up_async_capture_stream( &mut self, frame_size: usize, ex: &Executor, ) -> Result<SysBufferReader, Error>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 
create_directionstream_output( &mut self, frame_size: usize, ex: &Executor, ) -> Result<DirectionalStream, Error>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 
212 pub(crate) struct UnixBufferReader {
213     async_stream: Box<dyn AsyncCaptureBufferStream>,
214 }
215 
216 impl UnixBufferReader {
new(async_stream: Box<dyn AsyncCaptureBufferStream>) -> Self where Self: Sized,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)]
225 impl CaptureBufferReader for UnixBufferReader {
get_next_capture_period( &mut self, ex: &Executor, ) -> Result<AsyncCaptureBuffer, BoxError>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 
238 pub(crate) struct UnixBufferWriter {
239     guest_period_bytes: usize,
240 }
241 
242 #[async_trait(?Send)]
243 impl PlaybackBufferWriter for UnixBufferWriter {
new(guest_period_bytes: usize) -> Self244     fn new(guest_period_bytes: usize) -> Self {
245         UnixBufferWriter { guest_period_bytes }
246     }
endpoint_period_bytes(&self) -> usize247     fn endpoint_period_bytes(&self) -> usize {
248         self.guest_period_bytes
249     }
250 }
251