Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/snd/common_backend/stream_info.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
use std::fmt;
6
use std::rc::Rc;
7
use std::sync::atomic::AtomicBool;
8
use std::sync::atomic::Ordering;
9
use std::sync::Arc;
10
use std::time::Duration;
11
12
use audio_streams::SampleFormat;
13
use audio_streams::StreamEffect;
14
use base::error;
15
use base::warn;
16
use cros_async::sync::Condvar;
17
use cros_async::sync::RwLock as AsyncRwLock;
18
use cros_async::Executor;
19
use futures::channel::mpsc;
20
use futures::Future;
21
use futures::TryFutureExt;
22
use serde::Deserialize;
23
use serde::Serialize;
24
25
use super::Error;
26
use super::PcmResponse;
27
use super::WorkerStatus;
28
use crate::virtio::snd::common::*;
29
use crate::virtio::snd::common_backend::async_funcs::*;
30
use crate::virtio::snd::common_backend::DirectionalStream;
31
use crate::virtio::snd::common_backend::SysAsyncStreamObjects;
32
use crate::virtio::snd::constants::*;
33
use crate::virtio::snd::sys::SysAudioStreamSource;
34
use crate::virtio::snd::sys::SysAudioStreamSourceGenerator;
35
use crate::virtio::DescriptorChain;
36
37
/// Parameters for setting parameters in StreamInfo
38
#[derive(Copy, Clone, Debug)]
39
pub struct SetParams {
40
pub channels: u8,
41
pub format: SampleFormat,
42
pub frame_rate: u32,
43
pub buffer_bytes: usize,
44
pub period_bytes: usize,
45
pub dir: u8,
46
}
47
48
/// StreamInfoBuilder builds a [`StreamInfo`]. It is used when we want to store the parameters to
49
/// create a [`StreamInfo`] beforehand and actually create it later. (as is the case with VirtioSnd)
50
///
51
/// To create a new StreamInfoBuilder, see [`StreamInfo::builder()`].
52
#[derive(Clone)]
53
pub struct StreamInfoBuilder {
54
stream_source_generator: Arc<SysAudioStreamSourceGenerator>,
55
effects: Vec<StreamEffect>,
56
card_index: usize,
57
#[cfg(windows)]
58
audio_client_guid: Option<String>,
59
}
60
61
impl StreamInfoBuilder {
62
/// Creates a StreamInfoBuilder with minimal required fields:
63
///
64
/// * `stream_source_generator`: Generator which generates stream source in
65
/// [`StreamInfo::prepare()`].
66
/// * `card_index`: The ALSA card index.
67
pub fn new(
68
stream_source_generator: Arc<SysAudioStreamSourceGenerator>,
69
card_index: usize,
70
) -> Self {
71
StreamInfoBuilder {
72
stream_source_generator,
73
effects: vec![],
74
card_index,
75
#[cfg(windows)]
76
audio_client_guid: None,
77
}
78
}
79
80
/// Set the [`StreamEffect`]s to use when creating a stream from the stream source in
81
/// [`StreamInfo::prepare()`]. The default value is no effects.
82
pub fn effects(mut self, effects: Vec<StreamEffect>) -> Self {
83
self.effects = effects;
84
self
85
}
86
87
#[cfg(windows)]
88
pub fn audio_client_guid(mut self, audio_client_guid: Option<String>) -> Self {
89
self.audio_client_guid = audio_client_guid;
90
self
91
}
92
93
/// Builds a [`StreamInfo`].
94
pub fn build(self) -> StreamInfo {
95
self.into()
96
}
97
}
98
99
/// StreamInfo represents a virtio snd stream.
100
///
101
/// To create a StreamInfo, see [`StreamInfo::builder()`] and [`StreamInfoBuilder::build()`].
102
pub struct StreamInfo {
103
pub(crate) stream_source: Option<SysAudioStreamSource>,
104
stream_source_generator: Arc<SysAudioStreamSourceGenerator>,
105
pub(crate) muted: Rc<AtomicBool>,
106
pub(crate) channels: u8,
107
pub(crate) format: SampleFormat,
108
pub(crate) frame_rate: u32,
109
buffer_bytes: usize,
110
pub(crate) period_bytes: usize,
111
direction: u8, // VIRTIO_SND_D_*
112
pub state: u32, // VIRTIO_SND_R_PCM_SET_PARAMS -> VIRTIO_SND_R_PCM_STOP, or 0 (uninitialized)
113
// Stream effects to use when creating a new stream on [`prepare()`].
114
pub(crate) effects: Vec<StreamEffect>,
115
116
// just_reset set to true after reset. Make invalid state transition return Ok. Set to false
117
// after a valid state transition to SET_PARAMS or PREPARE.
118
pub just_reset: bool,
119
120
// Worker related
121
pub status_mutex: Rc<AsyncRwLock<WorkerStatus>>,
122
pub sender: Option<mpsc::UnboundedSender<DescriptorChain>>,
123
worker_future: Option<Box<dyn Future<Output = Result<(), Error>> + Unpin>>,
124
release_signal: Option<Rc<(AsyncRwLock<bool>, Condvar)>>, // Signal worker on release
125
card_index: usize,
126
ex: Option<Executor>, // Executor provided on `prepare()`. Used on `drop()`.
127
#[cfg(windows)]
128
pub(crate) playback_stream_cache: Option<(
129
Arc<AsyncRwLock<Box<dyn audio_streams::AsyncPlaybackBufferStream>>>,
130
Rc<AsyncRwLock<Box<dyn PlaybackBufferWriter>>>,
131
)>,
132
#[cfg(windows)]
133
pub(crate) audio_client_guid: Option<String>,
134
}
135
136
#[derive(Clone, Serialize, Deserialize)]
137
pub struct StreamInfoSnapshot {
138
pub(crate) channels: u8,
139
pub(crate) format: SampleFormat,
140
pub(crate) frame_rate: u32,
141
buffer_bytes: usize,
142
pub(crate) period_bytes: usize,
143
direction: u8, // VIRTIO_SND_D_*
144
pub state: u32, // VIRTIO_SND_R_PCM_SET_PARAMS -> VIRTIO_SND_R_PCM_STOP, or 0 (uninitialized)
145
effects: Vec<StreamEffect>,
146
pub just_reset: bool,
147
}
148
149
impl fmt::Debug for StreamInfo {
150
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151
f.debug_struct("StreamInfo")
152
.field("muted", &self.muted.load(Ordering::Relaxed))
153
.field("channels", &self.channels)
154
.field("format", &self.format)
155
.field("frame_rate", &self.frame_rate)
156
.field("buffer_bytes", &self.buffer_bytes)
157
.field("period_bytes", &self.period_bytes)
158
.field("direction", &get_virtio_direction_name(self.direction))
159
.field("state", &get_virtio_snd_r_pcm_cmd_name(self.state))
160
.field("effects", &self.effects)
161
.finish()
162
}
163
}
164
165
impl Drop for StreamInfo {
166
fn drop(&mut self) {
167
if let Some(ex) = self.ex.take() {
168
if self.state == VIRTIO_SND_R_PCM_START {
169
match ex.run_until(self.stop()) {
170
Err(e) => error!("Drop stream error on stop in executor: {}", e),
171
Ok(Err(e)) => error!("Drop stream error on stop: {}", e),
172
_ => {}
173
}
174
}
175
if self.state == VIRTIO_SND_R_PCM_PREPARE || self.state == VIRTIO_SND_R_PCM_STOP {
176
match ex.run_until(self.release()) {
177
Err(e) => error!("Drop stream error on release in executor: {}", e),
178
Ok(Err(e)) => error!("Drop stream error on release: {}", e),
179
_ => {}
180
}
181
}
182
}
183
}
184
}
185
186
impl From<StreamInfoBuilder> for StreamInfo {
187
fn from(builder: StreamInfoBuilder) -> Self {
188
StreamInfo {
189
muted: Rc::new(AtomicBool::new(false)),
190
stream_source: None,
191
stream_source_generator: builder.stream_source_generator,
192
channels: 0,
193
format: SampleFormat::U8,
194
frame_rate: 0,
195
buffer_bytes: 0,
196
period_bytes: 0,
197
direction: 0,
198
state: 0,
199
effects: builder.effects,
200
just_reset: false,
201
status_mutex: Rc::new(AsyncRwLock::new(WorkerStatus::Pause)),
202
sender: None,
203
worker_future: None,
204
release_signal: None,
205
card_index: builder.card_index,
206
ex: None,
207
#[cfg(windows)]
208
playback_stream_cache: None,
209
#[cfg(windows)]
210
audio_client_guid: builder.audio_client_guid,
211
}
212
}
213
}
214
215
impl StreamInfo {
216
/// Creates a minimal [`StreamInfoBuilder`]. See [`StreamInfoBuilder::new()`] for
217
/// the description of each parameter.
218
pub fn builder(
219
stream_source_generator: Arc<SysAudioStreamSourceGenerator>,
220
card_index: usize,
221
) -> StreamInfoBuilder {
222
StreamInfoBuilder::new(stream_source_generator, card_index)
223
}
224
225
/// Sets parameters of the stream, putting it into [`VIRTIO_SND_R_PCM_SET_PARAMS`] state.
226
///
227
/// * `params`: [`SetParams`] for the pcm stream runtime configuration.
228
pub async fn set_params(&mut self, params: SetParams) -> Result<(), Error> {
229
if self.state != 0
230
&& self.state != VIRTIO_SND_R_PCM_SET_PARAMS
231
&& self.state != VIRTIO_SND_R_PCM_PREPARE
232
&& self.state != VIRTIO_SND_R_PCM_RELEASE
233
{
234
error!(
235
"[Card {}] Invalid PCM state transition from {} to {}",
236
self.card_index,
237
get_virtio_snd_r_pcm_cmd_name(self.state),
238
get_virtio_snd_r_pcm_cmd_name(VIRTIO_SND_R_PCM_SET_PARAMS)
239
);
240
return Err(Error::OperationNotSupported);
241
}
242
243
// Only required for PREPARE -> SET_PARAMS
244
self.release_worker().await;
245
246
self.channels = params.channels;
247
self.format = params.format;
248
self.frame_rate = params.frame_rate;
249
self.buffer_bytes = params.buffer_bytes;
250
self.period_bytes = params.period_bytes;
251
self.direction = params.dir;
252
self.state = VIRTIO_SND_R_PCM_SET_PARAMS;
253
self.just_reset = false;
254
Ok(())
255
}
256
257
/// Prepares the stream, putting it into [`VIRTIO_SND_R_PCM_PREPARE`] state.
258
///
259
/// * `ex`: [`Executor`] to run the pcm worker.
260
/// * `tx_send`: Sender for sending `PcmResponse` for tx queue. (playback stream)
261
/// * `rx_send`: Sender for sending `PcmResponse` for rx queue. (capture stream)
262
pub async fn prepare(
263
&mut self,
264
ex: &Executor,
265
tx_send: &mpsc::UnboundedSender<PcmResponse>,
266
rx_send: &mpsc::UnboundedSender<PcmResponse>,
267
) -> Result<(), Error> {
268
if self.state == 0 && self.just_reset {
269
return Ok(());
270
}
271
if self.state != VIRTIO_SND_R_PCM_SET_PARAMS
272
&& self.state != VIRTIO_SND_R_PCM_PREPARE
273
&& self.state != VIRTIO_SND_R_PCM_RELEASE
274
{
275
error!(
276
"[Card {}] Invalid PCM state transition from {} to {}",
277
self.card_index,
278
get_virtio_snd_r_pcm_cmd_name(self.state),
279
get_virtio_snd_r_pcm_cmd_name(VIRTIO_SND_R_PCM_PREPARE)
280
);
281
return Err(Error::OperationNotSupported);
282
}
283
self.just_reset = false;
284
if self.state == VIRTIO_SND_R_PCM_PREPARE {
285
self.release_worker().await;
286
}
287
let frame_size = self.channels as usize * self.format.sample_bytes();
288
if self.period_bytes % frame_size != 0 {
289
error!(
290
"[Card {}] period_bytes must be divisible by frame size",
291
self.card_index
292
);
293
return Err(Error::OperationNotSupported);
294
}
295
self.stream_source = Some(
296
self.stream_source_generator
297
.generate()
298
.map_err(Error::GenerateStreamSource)?,
299
);
300
let stream_objects = match self.direction {
301
VIRTIO_SND_D_OUTPUT => SysAsyncStreamObjects {
302
stream: self
303
.create_directionstream_output(
304
frame_size,
305
#[cfg(windows)]
306
self.audio_client_guid.clone(),
307
ex,
308
)
309
.await?,
310
pcm_sender: tx_send.clone(),
311
},
312
VIRTIO_SND_D_INPUT => {
313
let buffer_reader = self.set_up_async_capture_stream(frame_size, ex).await?;
314
SysAsyncStreamObjects {
315
stream: DirectionalStream::Input(self.period_bytes, Box::new(buffer_reader)),
316
pcm_sender: rx_send.clone(),
317
}
318
}
319
_ => unreachable!(),
320
};
321
322
let (sender, receiver) = mpsc::unbounded();
323
self.sender = Some(sender);
324
self.state = VIRTIO_SND_R_PCM_PREPARE;
325
326
self.status_mutex = Rc::new(AsyncRwLock::new(WorkerStatus::Pause));
327
let period_dur = Duration::from_secs_f64(
328
self.period_bytes as f64 / frame_size as f64 / self.frame_rate as f64,
329
);
330
let release_signal = Rc::new((AsyncRwLock::new(false), Condvar::new()));
331
self.release_signal = Some(release_signal.clone());
332
let f = start_pcm_worker(
333
ex.clone(),
334
stream_objects.stream,
335
receiver,
336
self.status_mutex.clone(),
337
stream_objects.pcm_sender,
338
period_dur,
339
self.card_index,
340
self.muted.clone(),
341
release_signal,
342
);
343
self.worker_future = Some(Box::new(ex.spawn_local(f).into_future()));
344
self.ex = Some(ex.clone());
345
Ok(())
346
}
347
348
/// Starts the stream, putting it into [`VIRTIO_SND_R_PCM_START`] state.
349
pub async fn start(&mut self) -> Result<(), Error> {
350
if self.just_reset {
351
return Ok(());
352
}
353
if self.state != VIRTIO_SND_R_PCM_PREPARE && self.state != VIRTIO_SND_R_PCM_STOP {
354
error!(
355
"[Card {}] Invalid PCM state transition from {} to {}",
356
self.card_index,
357
get_virtio_snd_r_pcm_cmd_name(self.state),
358
get_virtio_snd_r_pcm_cmd_name(VIRTIO_SND_R_PCM_START)
359
);
360
return Err(Error::OperationNotSupported);
361
}
362
self.state = VIRTIO_SND_R_PCM_START;
363
let mut status = self.status_mutex.lock().await;
364
if *status != WorkerStatus::Quit {
365
*status = WorkerStatus::Running;
366
}
367
Ok(())
368
}
369
370
/// Stops the stream, putting it into [`VIRTIO_SND_R_PCM_STOP`] state.
371
pub async fn stop(&mut self) -> Result<(), Error> {
372
if self.just_reset {
373
return Ok(());
374
}
375
if self.state != VIRTIO_SND_R_PCM_START {
376
error!(
377
"[Card {}] Invalid PCM state transition from {} to {}",
378
self.card_index,
379
get_virtio_snd_r_pcm_cmd_name(self.state),
380
get_virtio_snd_r_pcm_cmd_name(VIRTIO_SND_R_PCM_STOP)
381
);
382
return Err(Error::OperationNotSupported);
383
}
384
self.state = VIRTIO_SND_R_PCM_STOP;
385
let mut status = self.status_mutex.lock().await;
386
if *status != WorkerStatus::Quit {
387
*status = WorkerStatus::Pause;
388
}
389
Ok(())
390
}
391
392
/// Releases the stream, putting it into [`VIRTIO_SND_R_PCM_RELEASE`] state.
393
pub async fn release(&mut self) -> Result<(), Error> {
394
if self.just_reset {
395
return Ok(());
396
}
397
if self.state != VIRTIO_SND_R_PCM_PREPARE && self.state != VIRTIO_SND_R_PCM_STOP {
398
error!(
399
"[Card {}] Invalid PCM state transition from {} to {}",
400
self.card_index,
401
get_virtio_snd_r_pcm_cmd_name(self.state),
402
get_virtio_snd_r_pcm_cmd_name(VIRTIO_SND_R_PCM_RELEASE)
403
);
404
return Err(Error::OperationNotSupported);
405
}
406
self.state = VIRTIO_SND_R_PCM_RELEASE;
407
self.stream_source = None;
408
self.release_worker().await;
409
Ok(())
410
}
411
412
async fn release_worker(&mut self) {
413
*self.status_mutex.lock().await = WorkerStatus::Quit;
414
if let Some(s) = self.sender.take() {
415
s.close_channel();
416
}
417
418
if let Some(release_signal) = self.release_signal.take() {
419
let (lock, cvar) = &*release_signal;
420
let mut signalled = lock.lock().await;
421
*signalled = true;
422
cvar.notify_all();
423
}
424
425
if let Some(f) = self.worker_future.take() {
426
f.await
427
.map_err(|error| {
428
warn!(
429
"[Card {}] Failure on releasing the worker_future: {}",
430
self.card_index, error
431
)
432
})
433
.ok();
434
}
435
self.ex.take(); // Remove ex as the worker is finished
436
}
437
438
pub fn snapshot(&self) -> StreamInfoSnapshot {
439
StreamInfoSnapshot {
440
channels: self.channels,
441
format: self.format,
442
frame_rate: self.frame_rate,
443
buffer_bytes: self.buffer_bytes,
444
period_bytes: self.period_bytes,
445
direction: self.direction, // VIRTIO_SND_D_*
446
// VIRTIO_SND_R_PCM_SET_PARAMS -> VIRTIO_SND_R_PCM_STOP, or 0 (uninitialized)
447
state: self.state,
448
effects: self.effects.clone(),
449
just_reset: self.just_reset,
450
}
451
}
452
453
pub fn restore(&mut self, state: &StreamInfoSnapshot) {
454
self.channels = state.channels;
455
self.format = state.format;
456
self.frame_rate = state.frame_rate;
457
self.buffer_bytes = state.buffer_bytes;
458
self.period_bytes = state.period_bytes;
459
self.direction = state.direction;
460
self.effects.clone_from(&state.effects);
461
self.just_reset = state.just_reset;
462
}
463
}
464
465
#[cfg(test)]
466
mod tests {
467
use audio_streams::NoopStreamSourceGenerator;
468
469
use super::*;
470
471
fn new_stream() -> StreamInfo {
472
let card_index = 0;
473
StreamInfo::builder(
474
Arc::new(Box::new(NoopStreamSourceGenerator::new())),
475
card_index,
476
)
477
.build()
478
}
479
480
fn stream_set_params(
481
mut stream: StreamInfo,
482
ex: &Executor,
483
expected_ok: bool,
484
expected_state: u32,
485
) -> StreamInfo {
486
let result = ex.run_until(stream.set_params(SetParams {
487
channels: 2,
488
format: SampleFormat::U8,
489
frame_rate: 48000,
490
buffer_bytes: 1024,
491
period_bytes: 512,
492
dir: VIRTIO_SND_D_OUTPUT,
493
}));
494
assert_eq!(result.unwrap().is_ok(), expected_ok);
495
assert_eq!(stream.state, expected_state);
496
stream
497
}
498
499
fn stream_prepare(
500
mut stream: StreamInfo,
501
ex: &Executor,
502
expected_ok: bool,
503
expected_state: u32,
504
) -> StreamInfo {
505
let (tx_send, _) = mpsc::unbounded();
506
let (rx_send, _) = mpsc::unbounded();
507
508
let result = ex.run_until(stream.prepare(ex, &tx_send, &rx_send));
509
assert_eq!(result.unwrap().is_ok(), expected_ok);
510
assert_eq!(stream.state, expected_state);
511
stream
512
}
513
514
fn stream_start(
515
mut stream: StreamInfo,
516
ex: &Executor,
517
expected_ok: bool,
518
expected_state: u32,
519
) -> StreamInfo {
520
let result = ex.run_until(stream.start());
521
assert_eq!(result.unwrap().is_ok(), expected_ok);
522
assert_eq!(stream.state, expected_state);
523
stream
524
}
525
526
fn stream_stop(
527
mut stream: StreamInfo,
528
ex: &Executor,
529
expected_ok: bool,
530
expected_state: u32,
531
) -> StreamInfo {
532
let result = ex.run_until(stream.stop());
533
assert_eq!(result.unwrap().is_ok(), expected_ok);
534
assert_eq!(stream.state, expected_state);
535
stream
536
}
537
538
fn stream_release(
539
mut stream: StreamInfo,
540
ex: &Executor,
541
expected_ok: bool,
542
expected_state: u32,
543
) -> StreamInfo {
544
let result = ex.run_until(stream.release());
545
assert_eq!(result.unwrap().is_ok(), expected_ok);
546
assert_eq!(stream.state, expected_state);
547
stream
548
}
549
550
#[test]
551
fn test_transitions_from_0() {
552
let ex = Executor::new().expect("Failed to create an executor");
553
554
// Valid transition to: {SET_PARAMS}
555
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
556
557
// Invalid transition to: {PREPARE, START, STOP, RELEASE}
558
stream_prepare(new_stream(), &ex, false, 0);
559
stream_start(new_stream(), &ex, false, 0);
560
stream_stop(new_stream(), &ex, false, 0);
561
stream_release(new_stream(), &ex, false, 0);
562
}
563
564
#[test]
565
fn test_transitions_from_set_params() {
566
let ex = Executor::new().expect("Failed to create an executor");
567
let new_stream_set_params = || -> StreamInfo {
568
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS)
569
};
570
571
// Valid transition to: {SET_PARAMS, PREPARE}
572
stream_set_params(
573
new_stream_set_params(),
574
&ex,
575
true,
576
VIRTIO_SND_R_PCM_SET_PARAMS,
577
);
578
stream_prepare(new_stream_set_params(), &ex, true, VIRTIO_SND_R_PCM_PREPARE);
579
580
// Invalid transition to: {START, STOP, RELEASE}
581
stream_start(
582
new_stream_set_params(),
583
&ex,
584
false,
585
VIRTIO_SND_R_PCM_SET_PARAMS,
586
);
587
stream_stop(
588
new_stream_set_params(),
589
&ex,
590
false,
591
VIRTIO_SND_R_PCM_SET_PARAMS,
592
);
593
stream_release(
594
new_stream_set_params(),
595
&ex,
596
false,
597
VIRTIO_SND_R_PCM_SET_PARAMS,
598
);
599
}
600
601
#[test]
602
fn test_transitions_from_prepare() {
603
let ex = Executor::new().expect("Failed to create an executor");
604
let new_stream_prepare = || -> StreamInfo {
605
let stream = stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
606
stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE)
607
};
608
609
// Valid transition to: {SET_PARAMS, PREPARE, START, RELEASE}
610
stream_set_params(new_stream_prepare(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
611
stream_prepare(new_stream_prepare(), &ex, true, VIRTIO_SND_R_PCM_PREPARE);
612
stream_start(new_stream_prepare(), &ex, true, VIRTIO_SND_R_PCM_START);
613
stream_release(new_stream_prepare(), &ex, true, VIRTIO_SND_R_PCM_RELEASE);
614
615
// Invalid transition to: {STOP}
616
stream_stop(new_stream_prepare(), &ex, false, VIRTIO_SND_R_PCM_PREPARE);
617
}
618
619
#[test]
620
fn test_transitions_from_start() {
621
let ex = Executor::new().expect("Failed to create an executor");
622
let new_stream_start = || -> StreamInfo {
623
let mut stream =
624
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
625
stream = stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE);
626
stream_start(stream, &ex, true, VIRTIO_SND_R_PCM_START)
627
};
628
629
// Valid transition to: {STOP}
630
stream_stop(new_stream_start(), &ex, true, VIRTIO_SND_R_PCM_STOP);
631
632
// Invalid transition to: {SET_PARAMS, PREPARE, START, RELEASE}
633
stream_set_params(new_stream_start(), &ex, false, VIRTIO_SND_R_PCM_START);
634
stream_prepare(new_stream_start(), &ex, false, VIRTIO_SND_R_PCM_START);
635
stream_start(new_stream_start(), &ex, false, VIRTIO_SND_R_PCM_START);
636
stream_release(new_stream_start(), &ex, false, VIRTIO_SND_R_PCM_START);
637
}
638
639
#[test]
640
fn test_transitions_from_stop() {
641
let ex = Executor::new().expect("Failed to create an executor");
642
let new_stream_stop = || -> StreamInfo {
643
let mut stream =
644
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
645
stream = stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE);
646
stream = stream_start(stream, &ex, true, VIRTIO_SND_R_PCM_START);
647
stream_stop(stream, &ex, true, VIRTIO_SND_R_PCM_STOP)
648
};
649
650
// Valid transition to: {START, RELEASE}
651
stream_start(new_stream_stop(), &ex, true, VIRTIO_SND_R_PCM_START);
652
stream_release(new_stream_stop(), &ex, true, VIRTIO_SND_R_PCM_RELEASE);
653
654
// Invalid transition to: {SET_PARAMS, PREPARE, STOP}
655
stream_set_params(new_stream_stop(), &ex, false, VIRTIO_SND_R_PCM_STOP);
656
stream_prepare(new_stream_stop(), &ex, false, VIRTIO_SND_R_PCM_STOP);
657
stream_stop(new_stream_stop(), &ex, false, VIRTIO_SND_R_PCM_STOP);
658
}
659
660
#[test]
661
fn test_transitions_from_release() {
662
let ex = Executor::new().expect("Failed to create an executor");
663
let new_stream_release = || -> StreamInfo {
664
let mut stream =
665
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
666
stream = stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE);
667
stream_release(stream, &ex, true, VIRTIO_SND_R_PCM_RELEASE)
668
};
669
670
// Valid transition to: {SET_PARAMS, PREPARE}
671
stream_set_params(new_stream_release(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
672
stream_prepare(new_stream_release(), &ex, true, VIRTIO_SND_R_PCM_PREPARE);
673
674
// Invalid transition to: {START, STOP, RELEASE}
675
stream_start(new_stream_release(), &ex, false, VIRTIO_SND_R_PCM_RELEASE);
676
stream_stop(new_stream_release(), &ex, false, VIRTIO_SND_R_PCM_RELEASE);
677
stream_release(new_stream_release(), &ex, false, VIRTIO_SND_R_PCM_RELEASE);
678
}
679
680
#[test]
681
fn test_transitions_from_0_just_reset() {
682
let ex = Executor::new().expect("Failed to create an executor");
683
let new_stream_0 = || -> StreamInfo {
684
let mut stream = new_stream();
685
stream.just_reset = true;
686
stream
687
};
688
689
// Valid transition to: {SET_PARAMS}
690
// After valid transition, just_reset reset to false
691
let mut stream = new_stream_0();
692
stream = stream_set_params(stream, &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
693
assert_eq!(stream.just_reset, false);
694
695
// Invalid transition to: {PREPARE, START, STOP, RELEASE}
696
// Return Ok but state doesn't change
697
stream_prepare(new_stream_0(), &ex, true, 0);
698
stream_start(new_stream_0(), &ex, true, 0);
699
stream_stop(new_stream_0(), &ex, true, 0);
700
stream_release(new_stream_0(), &ex, true, 0);
701
}
702
703
#[test]
704
fn test_transitions_from_set_params_just_reset() {
705
let ex = Executor::new().expect("Failed to create an executor");
706
let new_stream_set_params = || -> StreamInfo {
707
let mut stream =
708
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
709
stream.just_reset = true;
710
stream
711
};
712
713
// Valid transition to: {SET_PARAMS, PREPARE}
714
// After valid transition, just_reset reset to false
715
let mut stream = new_stream_set_params();
716
stream = stream_set_params(stream, &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
717
assert_eq!(stream.just_reset, false);
718
719
let mut stream = new_stream_set_params();
720
stream = stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE);
721
assert_eq!(stream.just_reset, false);
722
723
// Invalid transition to: {START, STOP, RELEASE}
724
// Return Ok but state doesn't change
725
stream_start(
726
new_stream_set_params(),
727
&ex,
728
true,
729
VIRTIO_SND_R_PCM_SET_PARAMS,
730
);
731
stream_stop(
732
new_stream_set_params(),
733
&ex,
734
true,
735
VIRTIO_SND_R_PCM_SET_PARAMS,
736
);
737
stream_release(
738
new_stream_set_params(),
739
&ex,
740
true,
741
VIRTIO_SND_R_PCM_SET_PARAMS,
742
);
743
}
744
745
#[test]
746
fn test_transitions_from_release_just_reset() {
747
let ex = Executor::new().expect("Failed to create an executor");
748
let new_stream_release = || -> StreamInfo {
749
let mut stream =
750
stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
751
stream = stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE);
752
stream = stream_release(stream, &ex, true, VIRTIO_SND_R_PCM_RELEASE);
753
stream.just_reset = true;
754
stream
755
};
756
757
// Valid transition to: {SET_PARAMS, PREPARE}
758
// After valid transition, just_reset reset to false
759
let mut stream = new_stream_release();
760
stream = stream_set_params(stream, &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
761
assert_eq!(stream.just_reset, false);
762
763
let mut stream = new_stream_release();
764
stream = stream_prepare(stream, &ex, true, VIRTIO_SND_R_PCM_PREPARE);
765
assert_eq!(stream.just_reset, false);
766
767
// Invalid transition to: {START, STOP, RELEASE}
768
// Return Ok but state doesn't change
769
stream_start(new_stream_release(), &ex, true, VIRTIO_SND_R_PCM_RELEASE);
770
stream_stop(new_stream_release(), &ex, true, VIRTIO_SND_R_PCM_RELEASE);
771
stream_release(new_stream_release(), &ex, true, VIRTIO_SND_R_PCM_RELEASE);
772
}
773
774
#[test]
775
fn test_stream_info_builder() {
776
let card_index = 0;
777
let builder = StreamInfo::builder(
778
Arc::new(Box::new(NoopStreamSourceGenerator::new())),
779
card_index,
780
)
781
.effects(vec![StreamEffect::EchoCancellation]);
782
783
let stream = builder.build();
784
assert_eq!(stream.effects, vec![StreamEffect::EchoCancellation]);
785
}
786
}
787
788