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