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