1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! Provides an interface for playing and recording audio. 6 //! 7 //! When implementing an audio playback system, the `StreamSource` trait is implemented. 8 //! Implementors of this trait allow creation of `PlaybackBufferStream` objects. The 9 //! `PlaybackBufferStream` provides the actual audio buffers to be filled with audio samples. These 10 //! buffers are obtained by calling `next_playback_buffer`. 11 //! 12 //! Users playing audio fill the provided buffers with audio. When a `PlaybackBuffer` is dropped, 13 //! the samples written to it are committed to the `PlaybackBufferStream` it came from. 14 //! 15 //! ``` 16 //! use audio_streams::{BoxError, SampleFormat, StreamSource, NoopStreamSource}; 17 //! use std::io::Write; 18 //! 19 //! const buffer_size: usize = 120; 20 //! const num_channels: usize = 2; 21 //! 22 //! # fn main() -> std::result::Result<(), BoxError> { 23 //! let mut stream_source = NoopStreamSource::new(); 24 //! let sample_format = SampleFormat::S16LE; 25 //! let frame_size = num_channels * sample_format.sample_bytes(); 26 //! 27 //! let (_, mut stream) = stream_source 28 //! .new_playback_stream(num_channels, sample_format, 48000, buffer_size)?; 29 //! // Play 10 buffers of DC. 30 //! let mut buf = Vec::new(); 31 //! buf.resize(buffer_size * frame_size, 0xa5u8); 32 //! for _ in 0..10 { 33 //! let mut stream_buffer = stream.next_playback_buffer()?; 34 //! assert_eq!(stream_buffer.write(&buf)?, buffer_size * frame_size); 35 //! } 36 //! # Ok (()) 37 //! # } 38 //! ``` 39 40 use std::cmp::min; 41 use std::error; 42 use std::fmt::{self, Display}; 43 use std::io::{self, Write}; 44 use std::os::unix::io::RawFd; 45 use std::result::Result; 46 use std::str::FromStr; 47 use std::time::{Duration, Instant}; 48 49 #[derive(Copy, Clone, Debug, PartialEq)] 50 pub enum SampleFormat { 51 U8, 52 S16LE, 53 S24LE, 54 S32LE, 55 } 56 57 impl SampleFormat { sample_bytes(self) -> usize58 pub fn sample_bytes(self) -> usize { 59 use SampleFormat::*; 60 match self { 61 U8 => 1, 62 S16LE => 2, 63 S24LE => 4, // Not a typo, S24_LE samples are stored in 4 byte chunks. 64 S32LE => 4, 65 } 66 } 67 } 68 69 impl Display for SampleFormat { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 71 use SampleFormat::*; 72 match self { 73 U8 => write!(f, "Unsigned 8 bit"), 74 S16LE => write!(f, "Signed 16 bit Little Endian"), 75 S24LE => write!(f, "Signed 24 bit Little Endian"), 76 S32LE => write!(f, "Signed 32 bit Little Endian"), 77 } 78 } 79 } 80 81 /// Valid directions of an audio stream. 82 #[derive(Copy, Clone, Debug, PartialEq)] 83 pub enum StreamDirection { 84 Playback, 85 Capture, 86 } 87 88 /// Valid effects for an audio stream. 89 #[derive(Copy, Clone, Debug, PartialEq)] 90 pub enum StreamEffect { 91 NoEffect, 92 EchoCancellation, 93 } 94 95 pub mod capture; 96 pub mod shm_streams; 97 98 impl Default for StreamEffect { default() -> Self99 fn default() -> Self { 100 StreamEffect::NoEffect 101 } 102 } 103 104 /// Errors that can pass across threads. 105 pub type BoxError = Box<dyn error::Error + Send + Sync>; 106 107 /// Errors that are possible from a `StreamEffect`. 108 #[derive(Debug)] 109 pub enum StreamEffectError { 110 InvalidEffect, 111 } 112 113 impl error::Error for StreamEffectError {} 114 115 impl Display for StreamEffectError { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 117 match self { 118 StreamEffectError::InvalidEffect => write!(f, "Must be in [EchoCancellation, aec]"), 119 } 120 } 121 } 122 123 impl FromStr for StreamEffect { 124 type Err = StreamEffectError; from_str(s: &str) -> std::result::Result<Self, Self::Err>125 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 126 match s { 127 "EchoCancellation" | "aec" => Ok(StreamEffect::EchoCancellation), 128 _ => Err(StreamEffectError::InvalidEffect), 129 } 130 } 131 } 132 133 /// `StreamSource` creates streams for playback or capture of audio. 134 pub trait StreamSource: Send { 135 /// Returns a stream control and buffer generator object. These are separate as the buffer 136 /// generator might want to be passed to the audio stream. 137 #[allow(clippy::type_complexity)] new_playback_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>138 fn new_playback_stream( 139 &mut self, 140 num_channels: usize, 141 format: SampleFormat, 142 frame_rate: u32, 143 buffer_size: usize, 144 ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>; 145 146 /// Returns a stream control and buffer generator object. These are separate as the buffer 147 /// generator might want to be passed to the audio stream. 148 /// Default implementation returns `NoopStreamControl` and `NoopCaptureStream`. 149 #[allow(clippy::type_complexity)] new_capture_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ) -> Result< ( Box<dyn StreamControl>, Box<dyn capture::CaptureBufferStream>, ), BoxError, >150 fn new_capture_stream( 151 &mut self, 152 num_channels: usize, 153 format: SampleFormat, 154 frame_rate: u32, 155 buffer_size: usize, 156 ) -> Result< 157 ( 158 Box<dyn StreamControl>, 159 Box<dyn capture::CaptureBufferStream>, 160 ), 161 BoxError, 162 > { 163 Ok(( 164 Box::new(NoopStreamControl::new()), 165 Box::new(capture::NoopCaptureStream::new( 166 num_channels, 167 format, 168 frame_rate, 169 buffer_size, 170 )), 171 )) 172 } 173 174 /// Returns any open file descriptors needed by the implementor. The FD list helps users of the 175 /// StreamSource enter Linux jails making sure not to close needed FDs. keep_fds(&self) -> Option<Vec<RawFd>>176 fn keep_fds(&self) -> Option<Vec<RawFd>> { 177 None 178 } 179 } 180 181 /// `PlaybackBufferStream` provides `PlaybackBuffer`s to fill with audio samples for playback. 182 pub trait PlaybackBufferStream: Send { next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError>183 fn next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError>; 184 } 185 186 /// `StreamControl` provides a way to set the volume and mute states of a stream. `StreamControl` 187 /// is separate from the stream so it can be owned by a different thread if needed. 188 pub trait StreamControl: Send + Sync { set_volume(&mut self, _scaler: f64)189 fn set_volume(&mut self, _scaler: f64) {} set_mute(&mut self, _mute: bool)190 fn set_mute(&mut self, _mute: bool) {} 191 } 192 193 /// `BufferDrop` is used as a callback mechanism for `PlaybackBuffer` objects. It is meant to be 194 /// implemented by the audio stream, allowing arbitrary code to be run after a buffer is filled or 195 /// read by the user. 196 pub trait BufferDrop { 197 /// Called when an audio buffer is dropped. `nframes` indicates the number of audio frames that 198 /// were read or written to the device. trigger(&mut self, nframes: usize)199 fn trigger(&mut self, nframes: usize); 200 } 201 202 /// Errors that are possible from a `PlaybackBuffer`. 203 #[derive(Debug)] 204 pub enum PlaybackBufferError { 205 InvalidLength, 206 } 207 208 impl error::Error for PlaybackBufferError {} 209 210 impl Display for PlaybackBufferError { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 212 match self { 213 PlaybackBufferError::InvalidLength => write!(f, "Invalid buffer length"), 214 } 215 } 216 } 217 218 /// `AudioBuffer` is one buffer that holds buffer_size audio frames and its drop function. 219 /// It is the inner data of `PlaybackBuffer` and `CaptureBuffer`. 220 struct AudioBuffer<'a> { 221 buffer: &'a mut [u8], 222 offset: usize, // Read or Write offset in frames. 223 frame_size: usize, // Size of a frame in bytes. 224 drop: &'a mut dyn BufferDrop, 225 } 226 227 /// `PlaybackBuffer` is one buffer that holds buffer_size audio frames. It is used to temporarily 228 /// allow access to an audio buffer and notifes the owning stream of write completion when dropped. 229 pub struct PlaybackBuffer<'a> { 230 buffer: AudioBuffer<'a>, 231 } 232 233 impl<'a> PlaybackBuffer<'a> { 234 /// Creates a new `PlaybackBuffer` that holds a reference to the backing memory specified in 235 /// `buffer`. new<F>( frame_size: usize, buffer: &'a mut [u8], drop: &'a mut F, ) -> Result<Self, PlaybackBufferError> where F: BufferDrop,236 pub fn new<F>( 237 frame_size: usize, 238 buffer: &'a mut [u8], 239 drop: &'a mut F, 240 ) -> Result<Self, PlaybackBufferError> 241 where 242 F: BufferDrop, 243 { 244 if buffer.len() % frame_size != 0 { 245 return Err(PlaybackBufferError::InvalidLength); 246 } 247 248 Ok(PlaybackBuffer { 249 buffer: AudioBuffer { 250 buffer, 251 offset: 0, 252 frame_size, 253 drop, 254 }, 255 }) 256 } 257 258 /// Returns the number of audio frames that fit in the buffer. frame_capacity(&self) -> usize259 pub fn frame_capacity(&self) -> usize { 260 self.buffer.buffer.len() / self.buffer.frame_size 261 } 262 263 /// Writes up to `size` bytes directly to this buffer inside of the given callback function. copy_cb<F: FnOnce(&mut [u8])>(&mut self, size: usize, cb: F)264 pub fn copy_cb<F: FnOnce(&mut [u8])>(&mut self, size: usize, cb: F) { 265 // only write complete frames. 266 let len = min( 267 size / self.buffer.frame_size * self.buffer.frame_size, 268 self.buffer.buffer.len() - self.buffer.offset, 269 ); 270 cb(&mut self.buffer.buffer[self.buffer.offset..(self.buffer.offset + len)]); 271 self.buffer.offset += len; 272 } 273 } 274 275 impl<'a> Write for PlaybackBuffer<'a> { write(&mut self, buf: &[u8]) -> io::Result<usize>276 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 277 // only write complete frames. 278 let len = buf.len() / self.buffer.frame_size * self.buffer.frame_size; 279 let written = (&mut self.buffer.buffer[self.buffer.offset..]).write(&buf[..len])?; 280 self.buffer.offset += written; 281 Ok(written) 282 } 283 flush(&mut self) -> io::Result<()>284 fn flush(&mut self) -> io::Result<()> { 285 Ok(()) 286 } 287 } 288 289 impl<'a> Drop for PlaybackBuffer<'a> { drop(&mut self)290 fn drop(&mut self) { 291 self.buffer 292 .drop 293 .trigger(self.buffer.offset / self.buffer.frame_size); 294 } 295 } 296 297 /// Stream that accepts playback samples but drops them. 298 pub struct NoopStream { 299 buffer: Vec<u8>, 300 frame_size: usize, 301 interval: Duration, 302 next_frame: Duration, 303 start_time: Option<Instant>, 304 buffer_drop: NoopBufferDrop, 305 } 306 307 /// NoopStream data that is needed from the buffer complete callback. 308 struct NoopBufferDrop { 309 which_buffer: bool, 310 } 311 312 impl BufferDrop for NoopBufferDrop { trigger(&mut self, _nwritten: usize)313 fn trigger(&mut self, _nwritten: usize) { 314 // When a buffer completes, switch to the other one. 315 self.which_buffer ^= true; 316 } 317 } 318 319 impl NoopStream { new( num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ) -> Self320 pub fn new( 321 num_channels: usize, 322 format: SampleFormat, 323 frame_rate: u32, 324 buffer_size: usize, 325 ) -> Self { 326 let frame_size = format.sample_bytes() * num_channels; 327 let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64); 328 NoopStream { 329 buffer: vec![0; buffer_size * frame_size], 330 frame_size, 331 interval, 332 next_frame: interval, 333 start_time: None, 334 buffer_drop: NoopBufferDrop { 335 which_buffer: false, 336 }, 337 } 338 } 339 } 340 341 impl PlaybackBufferStream for NoopStream { next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError>342 fn next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError> { 343 if let Some(start_time) = self.start_time { 344 let elapsed = start_time.elapsed(); 345 if elapsed < self.next_frame { 346 std::thread::sleep(self.next_frame - elapsed); 347 } 348 self.next_frame += self.interval; 349 } else { 350 self.start_time = Some(Instant::now()); 351 self.next_frame = self.interval; 352 } 353 Ok(PlaybackBuffer::new( 354 self.frame_size, 355 &mut self.buffer, 356 &mut self.buffer_drop, 357 )?) 358 } 359 } 360 361 /// No-op control for `NoopStream`s. 362 #[derive(Default)] 363 pub struct NoopStreamControl; 364 365 impl NoopStreamControl { new() -> Self366 pub fn new() -> Self { 367 NoopStreamControl {} 368 } 369 } 370 371 impl StreamControl for NoopStreamControl {} 372 373 /// Source of `NoopStream` and `NoopStreamControl` objects. 374 #[derive(Default)] 375 pub struct NoopStreamSource; 376 377 impl NoopStreamSource { new() -> Self378 pub fn new() -> Self { 379 NoopStreamSource {} 380 } 381 } 382 383 impl StreamSource for NoopStreamSource { 384 #[allow(clippy::type_complexity)] new_playback_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>385 fn new_playback_stream( 386 &mut self, 387 num_channels: usize, 388 format: SampleFormat, 389 frame_rate: u32, 390 buffer_size: usize, 391 ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError> { 392 Ok(( 393 Box::new(NoopStreamControl::new()), 394 Box::new(NoopStream::new( 395 num_channels, 396 format, 397 frame_rate, 398 buffer_size, 399 )), 400 )) 401 } 402 } 403 404 #[cfg(test)] 405 mod tests { 406 use super::*; 407 408 #[test] invalid_buffer_length()409 fn invalid_buffer_length() { 410 // Playback buffers can't be created with a size that isn't divisible by the frame size. 411 let mut pb_buf = [0xa5u8; 480 * 2 * 2 + 1]; 412 let mut buffer_drop = NoopBufferDrop { 413 which_buffer: false, 414 }; 415 assert!(PlaybackBuffer::new(2, &mut pb_buf, &mut buffer_drop).is_err()); 416 } 417 418 #[test] trigger()419 fn trigger() { 420 struct TestDrop { 421 frame_count: usize, 422 }; 423 impl BufferDrop for TestDrop { 424 fn trigger(&mut self, nwritten: usize) { 425 self.frame_count += nwritten; 426 } 427 } 428 let mut test_drop = TestDrop { frame_count: 0 }; 429 { 430 const FRAME_SIZE: usize = 4; 431 let mut buf = [0u8; 480 * FRAME_SIZE]; 432 let mut pb_buf = PlaybackBuffer::new(FRAME_SIZE, &mut buf, &mut test_drop).unwrap(); 433 pb_buf.write_all(&[0xa5u8; 480 * FRAME_SIZE]).unwrap(); 434 } 435 assert_eq!(test_drop.frame_count, 480); 436 } 437 438 #[test] sixteen_bit_stereo()439 fn sixteen_bit_stereo() { 440 let mut server = NoopStreamSource::new(); 441 let (_, mut stream) = server 442 .new_playback_stream(2, SampleFormat::S16LE, 48000, 480) 443 .unwrap(); 444 let mut stream_buffer = stream.next_playback_buffer().unwrap(); 445 assert_eq!(stream_buffer.frame_capacity(), 480); 446 let pb_buf = [0xa5u8; 480 * 2 * 2]; 447 assert_eq!(stream_buffer.write(&pb_buf).unwrap(), 480 * 2 * 2); 448 } 449 450 #[test] consumption_rate()451 fn consumption_rate() { 452 let mut server = NoopStreamSource::new(); 453 let (_, mut stream) = server 454 .new_playback_stream(2, SampleFormat::S16LE, 48000, 480) 455 .unwrap(); 456 let start = Instant::now(); 457 { 458 let mut stream_buffer = stream.next_playback_buffer().unwrap(); 459 let pb_buf = [0xa5u8; 480 * 2 * 2]; 460 assert_eq!(stream_buffer.write(&pb_buf).unwrap(), 480 * 2 * 2); 461 } 462 // The second call should block until the first buffer is consumed. 463 let _stream_buffer = stream.next_playback_buffer().unwrap(); 464 let elapsed = start.elapsed(); 465 assert!( 466 elapsed > Duration::from_millis(10), 467 "next_playback_buffer didn't block long enough {}", 468 elapsed.subsec_millis() 469 ); 470 } 471 } 472