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