• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
new( stream_source_generator: Arc<SysAudioStreamSourceGenerator>, card_index: usize, ) -> Self67     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.
effects(mut self, effects: Vec<StreamEffect>) -> Self82     pub fn effects(mut self, effects: Vec<StreamEffect>) -> Self {
83         self.effects = effects;
84         self
85     }
86 
87     #[cfg(windows)]
audio_client_guid(mut self, audio_client_guid: Option<String>) -> Self88     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`].
build(self) -> StreamInfo94     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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result150     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 {
drop(&mut self)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 {
from(builder: StreamInfoBuilder) -> Self187     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.
builder( stream_source_generator: Arc<SysAudioStreamSourceGenerator>, card_index: usize, ) -> StreamInfoBuilder218     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.
set_params(&mut self, params: SetParams) -> Result<(), Error>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)
prepare( &mut self, ex: &Executor, tx_send: &mpsc::UnboundedSender<PcmResponse>, rx_send: &mpsc::UnboundedSender<PcmResponse>, ) -> Result<(), Error>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.
start(&mut self) -> Result<(), Error>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.
stop(&mut self) -> Result<(), Error>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.
release(&mut self) -> Result<(), Error>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 
release_worker(&mut self)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 
snapshot(&self) -> StreamInfoSnapshot438     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 
restore(&mut self, state: &StreamInfoSnapshot)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 
new_stream() -> StreamInfo471     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 
stream_set_params( mut stream: StreamInfo, ex: &Executor, expected_ok: bool, expected_state: u32, ) -> StreamInfo480     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 
stream_prepare( mut stream: StreamInfo, ex: &Executor, expected_ok: bool, expected_state: u32, ) -> StreamInfo499     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 
stream_start( mut stream: StreamInfo, ex: &Executor, expected_ok: bool, expected_state: u32, ) -> StreamInfo514     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 
stream_stop( mut stream: StreamInfo, ex: &Executor, expected_ok: bool, expected_state: u32, ) -> StreamInfo526     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 
stream_release( mut stream: StreamInfo, ex: &Executor, expected_ok: bool, expected_state: u32, ) -> StreamInfo538     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]
test_transitions_from_0()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]
test_transitions_from_set_params()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]
test_transitions_from_prepare()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]
test_transitions_from_start()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]
test_transitions_from_stop()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]
test_transitions_from_release()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]
test_transitions_from_0_just_reset()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]
test_transitions_from_set_params_just_reset()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]
test_transitions_from_release_just_reset()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]
test_stream_info_builder()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