• 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::{StreamSource, DummyStreamSource};
17 //! use std::io::Write;
18 //!
19 //! const buffer_size: usize = 120;
20 //! const num_channels: usize = 2;
21 //! const frame_size: usize = num_channels * 2; // 16-bit samples are two bytes.
22 //!
23 //! # fn main() -> std::result::Result<(), Box<std::error::Error>> {
24 //! let mut stream_source = DummyStreamSource::new();
25 //!
26 //! let (_, mut stream) = stream_source
27 //!     .new_playback_stream(num_channels, 48000, buffer_size)?;
28 //! // Play 10 buffers of DC.
29 //! let pb_bufs = [[0xa5u8; buffer_size * frame_size]; 10];
30 //! for pb_buf in &pb_bufs {
31 //!     let mut stream_buffer = stream.next_playback_buffer()?;
32 //!     assert_eq!(stream_buffer.write(pb_buf)?, buffer_size * frame_size);
33 //! }
34 //! # Ok (())
35 //! # }
36 //! ```
37 
38 use std::error;
39 use std::fmt::{self, Display};
40 use std::io::{self, Write};
41 use std::os::unix::io::RawFd;
42 use std::result::Result;
43 use std::time::{Duration, Instant};
44 
45 pub mod capture;
46 
47 /// `StreamSource` creates streams for playback or capture of audio.
48 pub trait StreamSource: Send {
49     /// Returns a stream control and buffer generator object. These are separate as the buffer
50     /// generator might want to be passed to the audio stream.
new_playback_stream( &mut self, num_channels: usize, frame_rate: usize, buffer_size: usize, ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), Box<dyn error::Error>>51     fn new_playback_stream(
52         &mut self,
53         num_channels: usize,
54         frame_rate: usize,
55         buffer_size: usize,
56     ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), Box<dyn error::Error>>;
57 
58     /// Returns a stream control and buffer generator object. These are separate as the buffer
59     /// generator might want to be passed to the audio stream.
60     /// Default implementation returns `DummyStreamControl` and `DummyCaptureStream`.
new_capture_stream( &mut self, num_channels: usize, frame_rate: usize, buffer_size: usize, ) -> Result< ( Box<dyn StreamControl>, Box<dyn capture::CaptureBufferStream>, ), Box<dyn error::Error>, >61     fn new_capture_stream(
62         &mut self,
63         num_channels: usize,
64         frame_rate: usize,
65         buffer_size: usize,
66     ) -> Result<
67         (
68             Box<dyn StreamControl>,
69             Box<dyn capture::CaptureBufferStream>,
70         ),
71         Box<dyn error::Error>,
72     > {
73         Ok((
74             Box::new(DummyStreamControl::new()),
75             Box::new(capture::DummyCaptureStream::new(
76                 num_channels,
77                 frame_rate,
78                 buffer_size,
79             )),
80         ))
81     }
82 
83     /// Returns any open file descriptors needed by the implementor. The FD list helps users of the
84     /// StreamSource enter Linux jails making sure not to close needed FDs.
keep_fds(&self) -> Option<Vec<RawFd>>85     fn keep_fds(&self) -> Option<Vec<RawFd>> {
86         None
87     }
88 }
89 
90 /// `PlaybackBufferStream` provides `PlaybackBuffer`s to fill with audio samples for playback.
91 pub trait PlaybackBufferStream: Send {
next_playback_buffer<'a>(&'a mut self) -> Result<PlaybackBuffer<'a>, Box<dyn error::Error>>92     fn next_playback_buffer<'a>(&'a mut self) -> Result<PlaybackBuffer<'a>, Box<dyn error::Error>>;
93 }
94 
95 /// `StreamControl` provides a way to set the volume and mute states of a stream. `StreamControl`
96 /// is separate from the stream so it can be owned by a different thread if needed.
97 pub trait StreamControl: Send + Sync {
set_volume(&mut self, _scaler: f64)98     fn set_volume(&mut self, _scaler: f64) {}
set_mute(&mut self, _mute: bool)99     fn set_mute(&mut self, _mute: bool) {}
100 }
101 
102 /// `BufferDrop` is used as a callback mechanism for `PlaybackBuffer` objects. It is meant to be
103 /// implemented by the audio stream, allowing arbitrary code to be run after a buffer is filled or
104 /// read by the user.
105 pub trait BufferDrop {
106     /// Called when an audio buffer is dropped. `nframes` indicates the number of audio frames that
107     /// were read or written to the device.
trigger(&mut self, nframes: usize)108     fn trigger(&mut self, nframes: usize);
109 }
110 
111 /// Errors that are possible from a `PlaybackBuffer`.
112 #[derive(Debug)]
113 pub enum PlaybackBufferError {
114     InvalidLength,
115 }
116 
117 impl error::Error for PlaybackBufferError {}
118 
119 impl Display for PlaybackBufferError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result120     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121         match self {
122             PlaybackBufferError::InvalidLength => write!(f, "Invalid buffer length"),
123         }
124     }
125 }
126 
127 /// `AudioBuffer` is one buffer that holds buffer_size audio frames and its drop function.
128 /// It is the inner data of `PlaybackBuffer` and `CaptureBuffer`.
129 struct AudioBuffer<'a> {
130     buffer: &'a mut [u8],
131     offset: usize,     // Read or Write offset in frames.
132     frame_size: usize, // Size of a frame in bytes.
133     drop: &'a mut dyn BufferDrop,
134 }
135 
136 /// `PlaybackBuffer` is one buffer that holds buffer_size audio frames. It is used to temporarily
137 /// allow access to an audio buffer and notifes the owning stream of write completion when dropped.
138 pub struct PlaybackBuffer<'a> {
139     buffer: AudioBuffer<'a>,
140 }
141 
142 impl<'a> PlaybackBuffer<'a> {
143     /// Creates a new `PlaybackBuffer` that holds a reference to the backing memory specified in
144     /// `buffer`.
new<F>( frame_size: usize, buffer: &'a mut [u8], drop: &'a mut F, ) -> Result<Self, PlaybackBufferError> where F: BufferDrop,145     pub fn new<F>(
146         frame_size: usize,
147         buffer: &'a mut [u8],
148         drop: &'a mut F,
149     ) -> Result<Self, PlaybackBufferError>
150     where
151         F: BufferDrop,
152     {
153         if buffer.len() % frame_size != 0 {
154             return Err(PlaybackBufferError::InvalidLength);
155         }
156 
157         Ok(PlaybackBuffer {
158             buffer: AudioBuffer {
159                 buffer,
160                 offset: 0,
161                 frame_size,
162                 drop,
163             },
164         })
165     }
166 
167     /// Returns the number of audio frames that fit in the buffer.
frame_capacity(&self) -> usize168     pub fn frame_capacity(&self) -> usize {
169         self.buffer.buffer.len() / self.buffer.frame_size
170     }
171 
172     /// 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)173     pub fn copy_cb<F: FnOnce(&mut [u8])>(&mut self, size: usize, cb: F) {
174         // only write complete frames.
175         let len = size / self.buffer.frame_size * self.buffer.frame_size;
176         cb(&mut self.buffer.buffer[self.buffer.offset..(self.buffer.offset + len)]);
177         self.buffer.offset += len;
178     }
179 }
180 
181 impl<'a> Write for PlaybackBuffer<'a> {
write(&mut self, buf: &[u8]) -> io::Result<usize>182     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
183         // only write complete frames.
184         let len = buf.len() / self.buffer.frame_size * self.buffer.frame_size;
185         let written = (&mut self.buffer.buffer[self.buffer.offset..]).write(&buf[..len])?;
186         self.buffer.offset += written;
187         Ok(written)
188     }
189 
flush(&mut self) -> io::Result<()>190     fn flush(&mut self) -> io::Result<()> {
191         Ok(())
192     }
193 }
194 
195 impl<'a> Drop for PlaybackBuffer<'a> {
drop(&mut self)196     fn drop(&mut self) {
197         self.buffer
198             .drop
199             .trigger(self.buffer.offset / self.buffer.frame_size);
200     }
201 }
202 
203 /// Stream that accepts playback samples but drops them.
204 pub struct DummyStream {
205     buffer: Vec<u8>,
206     frame_size: usize,
207     interval: Duration,
208     next_frame: Duration,
209     start_time: Option<Instant>,
210     buffer_drop: DummyBufferDrop,
211 }
212 
213 /// DummyStream data that is needed from the buffer complete callback.
214 struct DummyBufferDrop {
215     which_buffer: bool,
216 }
217 
218 impl BufferDrop for DummyBufferDrop {
trigger(&mut self, _nwritten: usize)219     fn trigger(&mut self, _nwritten: usize) {
220         // When a buffer completes, switch to the other one.
221         self.which_buffer ^= true;
222     }
223 }
224 
225 impl DummyStream {
226     // TODO(allow other formats)
new(num_channels: usize, frame_rate: usize, buffer_size: usize) -> Self227     pub fn new(num_channels: usize, frame_rate: usize, buffer_size: usize) -> Self {
228         const S16LE_SIZE: usize = 2;
229         let frame_size = S16LE_SIZE * num_channels;
230         let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);
231         DummyStream {
232             buffer: vec![0; buffer_size * frame_size],
233             frame_size,
234             interval,
235             next_frame: interval,
236             start_time: None,
237             buffer_drop: DummyBufferDrop {
238                 which_buffer: false,
239             },
240         }
241     }
242 }
243 
244 impl PlaybackBufferStream for DummyStream {
next_playback_buffer<'a>(&'a mut self) -> Result<PlaybackBuffer<'a>, Box<dyn error::Error>>245     fn next_playback_buffer<'a>(&'a mut self) -> Result<PlaybackBuffer<'a>, Box<dyn error::Error>> {
246         if let Some(start_time) = self.start_time {
247             if start_time.elapsed() < self.next_frame {
248                 std::thread::sleep(self.next_frame - start_time.elapsed());
249             }
250             self.next_frame += self.interval;
251         } else {
252             self.start_time = Some(Instant::now());
253             self.next_frame = self.interval;
254         }
255         Ok(PlaybackBuffer::new(
256             self.frame_size,
257             &mut self.buffer,
258             &mut self.buffer_drop,
259         )?)
260     }
261 }
262 
263 /// No-op control for `DummyStream`s.
264 #[derive(Default)]
265 pub struct DummyStreamControl;
266 
267 impl DummyStreamControl {
new() -> Self268     pub fn new() -> Self {
269         DummyStreamControl {}
270     }
271 }
272 
273 impl StreamControl for DummyStreamControl {}
274 
275 /// Source of `DummyStream` and `DummyStreamControl` objects.
276 #[derive(Default)]
277 pub struct DummyStreamSource;
278 
279 impl DummyStreamSource {
new() -> Self280     pub fn new() -> Self {
281         DummyStreamSource {}
282     }
283 }
284 
285 impl StreamSource for DummyStreamSource {
new_playback_stream( &mut self, num_channels: usize, frame_rate: usize, buffer_size: usize, ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), Box<dyn error::Error>>286     fn new_playback_stream(
287         &mut self,
288         num_channels: usize,
289         frame_rate: usize,
290         buffer_size: usize,
291     ) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), Box<dyn error::Error>>
292     {
293         Ok((
294             Box::new(DummyStreamControl::new()),
295             Box::new(DummyStream::new(num_channels, frame_rate, buffer_size)),
296         ))
297     }
298 }
299 
300 #[cfg(test)]
301 mod tests {
302     use super::*;
303 
304     #[test]
invalid_buffer_length()305     fn invalid_buffer_length() {
306         // Playback buffers can't be created with a size that isn't divisible by the frame size.
307         let mut pb_buf = [0xa5u8; 480 * 2 * 2 + 1];
308         let mut buffer_drop = DummyBufferDrop {
309             which_buffer: false,
310         };
311         assert!(PlaybackBuffer::new(2, &mut pb_buf, &mut buffer_drop).is_err());
312     }
313 
314     #[test]
trigger()315     fn trigger() {
316         struct TestDrop {
317             frame_count: usize,
318         };
319         impl BufferDrop for TestDrop {
320             fn trigger(&mut self, nwritten: usize) {
321                 self.frame_count += nwritten;
322             }
323         }
324         let mut test_drop = TestDrop { frame_count: 0 };
325         {
326             const FRAME_SIZE: usize = 4;
327             let mut buf = [0u8; 480 * FRAME_SIZE];
328             let mut pb_buf = PlaybackBuffer::new(FRAME_SIZE, &mut buf, &mut test_drop).unwrap();
329             pb_buf.write(&[0xa5u8; 480 * FRAME_SIZE]).unwrap();
330         }
331         assert_eq!(test_drop.frame_count, 480);
332     }
333 
334     #[test]
sixteen_bit_stereo()335     fn sixteen_bit_stereo() {
336         let mut server = DummyStreamSource::new();
337         let (_, mut stream) = server.new_playback_stream(2, 48000, 480).unwrap();
338         let mut stream_buffer = stream.next_playback_buffer().unwrap();
339         assert_eq!(stream_buffer.frame_capacity(), 480);
340         let pb_buf = [0xa5u8; 480 * 2 * 2];
341         assert_eq!(stream_buffer.write(&pb_buf).unwrap(), 480 * 2 * 2);
342     }
343 
344     #[test]
consumption_rate()345     fn consumption_rate() {
346         let mut server = DummyStreamSource::new();
347         let (_, mut stream) = server.new_playback_stream(2, 48000, 480).unwrap();
348         let start = Instant::now();
349         {
350             let mut stream_buffer = stream.next_playback_buffer().unwrap();
351             let pb_buf = [0xa5u8; 480 * 2 * 2];
352             assert_eq!(stream_buffer.write(&pb_buf).unwrap(), 480 * 2 * 2);
353         }
354         // The second call should block until the first buffer is consumed.
355         let _stream_buffer = stream.next_playback_buffer().unwrap();
356         let elapsed = start.elapsed();
357         assert!(
358             elapsed > Duration::from_millis(10),
359             "next_playback_buffer didn't block long enough {}",
360             elapsed.subsec_millis()
361         );
362     }
363 }
364