1use std::fmt;
6use std::rc::Rc;
7use std::sync::atomic::AtomicBool;
8use std::sync::atomic::Ordering;
9use std::sync::Arc;
10use std::time::Duration;
11
12use audio_streams::SampleFormat;
13use audio_streams::StreamEffect;
14use base::error;
15use base::warn;
16use cros_async::sync::Condvar;
17use cros_async::sync::RwLock as AsyncRwLock;
18use cros_async::Executor;
19use futures::channel::mpsc;
20use futures::Future;
21use futures::TryFutureExt;
22use serde::Deserialize;
23use serde::Serialize;
24
25use super::Error;
26use super::PcmResponse;
27use super::WorkerStatus;
28use crate::virtio::snd::common::*;
29use crate::virtio::snd::common_backend::async_funcs::*;
30use crate::virtio::snd::common_backend::DirectionalStream;
31use crate::virtio::snd::common_backend::SysAsyncStreamObjects;
32use crate::virtio::snd::constants::*;
33use crate::virtio::snd::sys::SysAudioStreamSource;
34use crate::virtio::snd::sys::SysAudioStreamSourceGenerator;
35use crate::virtio::DescriptorChain;
36
37#[derive(Copy, Clone, Debug)]
39pub 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#[derive(Clone)]
53pub 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
61impl StreamInfoBuilder {
62 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 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 pub fn build(self) -> StreamInfo {
95 self.into()
96 }
97}
98
99pub 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, pub state: u32, pub(crate) effects: Vec<StreamEffect>,
115
116 pub just_reset: bool,
119
120 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)>>, card_index: usize,
126 ex: Option<Executor>, #[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)]
137pub 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, pub state: u32, effects: Vec<StreamEffect>,
146 pub just_reset: bool,
147}
148
149impl 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
165impl 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
186impl 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
215impl StreamInfo {
216 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 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 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 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 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 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 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(); }
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, 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)]
466mod 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 stream_set_params(new_stream(), &ex, true, VIRTIO_SND_R_PCM_SET_PARAMS);
556
557 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 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 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 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 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 stream_stop(new_stream_start(), &ex, true, VIRTIO_SND_R_PCM_STOP);
631
632 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 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 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 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 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 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 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 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 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 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 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}