• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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