Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/snd/sys/linux.rs
5394 views
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 {
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
73
impl 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")]
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")]
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)]
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
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.
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
212
pub(crate) struct UnixBufferReader {
213
async_stream: Box<dyn AsyncCaptureBufferStream>,
214
}
215
216
impl 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)]
225
impl 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
238
pub(crate) struct UnixBufferWriter {
239
guest_period_bytes: usize,
240
}
241
242
#[async_trait(?Send)]
243
impl 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
}
251
252