Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/snd/sys/windows.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
// TODO(b/275406212): Deleted resampler code to make upstream easier. The resample
6
// will be in win_audio now
7
use std::io;
8
use std::io::Read;
9
use std::rc::Rc;
10
use std::slice;
11
use std::sync::Arc;
12
13
use async_trait::async_trait;
14
use audio_streams::capture::AsyncCaptureBuffer;
15
use audio_streams::capture::AsyncCaptureBufferStream;
16
use audio_streams::AsyncPlaybackBuffer;
17
use audio_streams::AsyncPlaybackBufferStream;
18
use audio_streams::BoxError;
19
use base::error;
20
pub(crate) use base::set_audio_thread_priority;
21
use base::warn;
22
use cros_async::sync::RwLock as AsyncRwLock;
23
use cros_async::Executor;
24
use data_model::Le32;
25
use futures::channel::mpsc::UnboundedReceiver;
26
use futures::channel::mpsc::UnboundedSender;
27
use futures::SinkExt;
28
use serde::Deserialize;
29
use serde::Serialize;
30
use sync::Mutex;
31
use vm_memory::GuestMemory;
32
use win_audio::async_stream::WinAudioStreamSourceGenerator;
33
use win_audio::AudioSharedFormat;
34
use win_audio::WinAudioServer;
35
use win_audio::WinStreamSourceGenerator;
36
use win_audio::ANDROID_CAPTURE_FRAME_SIZE_BYTES;
37
use win_audio::BYTES_PER_32FLOAT;
38
39
use crate::virtio::snd::common_backend::async_funcs::CaptureBufferReader;
40
use crate::virtio::snd::common_backend::async_funcs::PlaybackBufferWriter;
41
use crate::virtio::snd::common_backend::stream_info::StreamInfo;
42
use crate::virtio::snd::common_backend::DirectionalStream;
43
use crate::virtio::snd::common_backend::Error;
44
use crate::virtio::snd::common_backend::PcmResponse;
45
use crate::virtio::snd::common_backend::SndData;
46
use crate::virtio::snd::constants::StatusCode;
47
use crate::virtio::snd::layout::virtio_snd_pcm_status;
48
use crate::virtio::snd::parameters::Error as ParametersError;
49
use crate::virtio::snd::parameters::Parameters;
50
use crate::virtio::DescriptorChain;
51
use crate::virtio::Reader;
52
53
pub(crate) type SysAudioStreamSourceGenerator = Box<dyn WinStreamSourceGenerator>;
54
pub(crate) type SysAudioStreamSource = Box<dyn WinAudioServer>;
55
pub(crate) type SysBufferReader = WinBufferReader;
56
57
pub struct SysDirectionOutput {
58
pub async_playback_buffer_stream:
59
Arc<AsyncRwLock<Box<dyn audio_streams::AsyncPlaybackBufferStream>>>,
60
pub buffer_writer: Rc<AsyncRwLock<Box<dyn PlaybackBufferWriter>>>,
61
}
62
63
pub(crate) struct SysAsyncStreamObjects {
64
pub(crate) stream: DirectionalStream,
65
pub(crate) pcm_sender: UnboundedSender<PcmResponse>,
66
}
67
68
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
69
pub enum StreamSourceBackend {
70
WINAUDIO,
71
}
72
73
// Implemented to make backend serialization possible, since we deserialize from str.
74
impl From<StreamSourceBackend> for String {
75
fn from(backend: StreamSourceBackend) -> Self {
76
match backend {
77
StreamSourceBackend::WINAUDIO => "winaudio".to_owned(),
78
}
79
}
80
}
81
82
impl TryFrom<&str> for StreamSourceBackend {
83
type Error = ParametersError;
84
85
fn try_from(s: &str) -> Result<Self, Self::Error> {
86
match s {
87
"winaudio" => Ok(StreamSourceBackend::WINAUDIO),
88
_ => Err(ParametersError::InvalidBackend),
89
}
90
}
91
}
92
93
pub(crate) fn create_stream_source_generators(
94
_backend: StreamSourceBackend,
95
_params: &Parameters,
96
_snd_data: &SndData,
97
) -> Vec<SysAudioStreamSourceGenerator> {
98
vec![
99
Box::new(WinAudioStreamSourceGenerator {}),
100
Box::new(WinAudioStreamSourceGenerator {}),
101
]
102
}
103
104
impl StreamInfo {
105
async fn set_up_async_playback_stream(
106
&mut self,
107
frame_size: usize,
108
audio_client_guid: Option<String>,
109
ex: &Executor,
110
) -> Result<Box<dyn AsyncPlaybackBufferStream>, Error> {
111
let (async_playback_buffer_stream, _) = self
112
.stream_source
113
.as_mut()
114
.ok_or(Error::EmptyStreamSource)?
115
.new_async_playback_stream_and_get_shared_format(
116
self.channels as usize,
117
self.format,
118
self.frame_rate as usize,
119
// `buffer_size` in `audio_streams` API indicates the buffer size in bytes that the
120
// stream consumes (or transmits) each time
121
// (next_playback/capture_buffer). `period_bytes` in virtio-snd
122
// device (or ALSA) indicates the device transmits (or
123
// consumes) for each PCM message.
124
// Therefore, `buffer_size` in `audio_streams` == `period_bytes` in virtio-snd.
125
self.period_bytes / frame_size,
126
ex,
127
audio_client_guid,
128
)
129
.map_err(Error::CreateStream)?;
130
Ok(async_playback_buffer_stream)
131
}
132
133
pub(crate) async fn set_up_async_capture_stream(
134
&mut self,
135
frame_size: usize,
136
ex: &Executor,
137
) -> Result<SysBufferReader, Error> {
138
let (async_capture_buffer_stream, audio_shared_format) = self
139
.stream_source
140
.as_mut()
141
.ok_or(Error::EmptyStreamSource)?
142
.new_async_capture_stream_and_get_shared_format(
143
self.channels as usize,
144
self.format,
145
self.frame_rate,
146
self.period_bytes / frame_size,
147
ex,
148
)
149
.map_err(Error::CreateStream)?;
150
let mut buffer_reader = WinBufferReader::new(async_capture_buffer_stream);
151
Ok(buffer_reader)
152
}
153
154
pub(crate) async fn create_directionstream_output(
155
&mut self,
156
frame_size: usize,
157
audio_client_guid: Option<String>,
158
ex: &Executor,
159
) -> Result<DirectionalStream, Error> {
160
if self.playback_stream_cache.is_none() {
161
let async_playback_buffer_stream = self
162
.set_up_async_playback_stream(frame_size, audio_client_guid, ex)
163
.await?;
164
165
let buffer_writer = WinBufferWriter::new(self.period_bytes);
166
167
self.playback_stream_cache = Some((
168
Arc::new(AsyncRwLock::new(async_playback_buffer_stream)),
169
Rc::new(AsyncRwLock::new(Box::new(buffer_writer))),
170
));
171
}
172
let playback_stream_cache = self
173
.playback_stream_cache
174
.as_ref()
175
.expect("playback stream cache is None. This shouldn't be possible");
176
177
Ok(DirectionalStream::Output(SysDirectionOutput {
178
async_playback_buffer_stream: playback_stream_cache.0.clone(),
179
buffer_writer: playback_stream_cache.1.clone(),
180
}))
181
}
182
}
183
184
pub(crate) struct WinBufferReader {
185
async_stream: Box<dyn AsyncCaptureBufferStream>,
186
}
187
188
impl WinBufferReader {
189
fn new(async_stream: Box<dyn AsyncCaptureBufferStream>) -> Self {
190
WinBufferReader { async_stream }
191
}
192
}
193
194
#[async_trait(?Send)]
195
impl CaptureBufferReader for WinBufferReader {
196
async fn get_next_capture_period(
197
&mut self,
198
ex: &Executor,
199
) -> Result<AsyncCaptureBuffer, BoxError> {
200
self.async_stream.next_capture_buffer(ex).await
201
}
202
}
203
204
pub(crate) struct WinBufferWriter {
205
guest_period_bytes: usize,
206
}
207
208
#[async_trait(?Send)]
209
impl PlaybackBufferWriter for WinBufferWriter {
210
fn new(guest_period_bytes: usize) -> Self {
211
WinBufferWriter { guest_period_bytes }
212
}
213
214
fn endpoint_period_bytes(&self) -> usize {
215
self.guest_period_bytes
216
}
217
218
// This method implementation may diverge downstream due to vendor specific requirements.
219
fn copy_to_buffer(
220
&mut self,
221
dst_buf: &mut AsyncPlaybackBuffer<'_>,
222
reader: &mut Reader,
223
) -> Result<usize, Error> {
224
dst_buf.copy_from(reader).map_err(Error::Io)
225
}
226
}
227
228