• 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 use std::error;
6 use std::fmt;
7 use std::fs::File;
8 use std::io::{self, BufReader, BufWriter, Read, Write};
9 use std::os::raw::c_int;
10 use std::path::Path;
11 use std::sync::atomic::{AtomicBool, Ordering};
12 
13 use audio_streams::{SampleFormat, StreamSource};
14 use hound::{WavReader, WavSpec, WavWriter};
15 use libcras::{BoxError, CrasClient, CrasNodeType};
16 use sys_util::{register_signal_handler, set_rt_prio_limit, set_rt_round_robin};
17 
18 use crate::arguments::{AudioOptions, FileType, LoopbackType};
19 
20 #[derive(Debug)]
21 pub enum Error {
22     CreateStream(BoxError),
23     FetchStream(BoxError),
24     FloatingPointSamples,
25     InvalidWavFile(hound::Error),
26     Io(io::Error),
27     Libcras(libcras::Error),
28     NoLoopbackNode(CrasNodeType),
29     OpenFile(hound::Error),
30     SampleBits(u16),
31     SysUtil(sys_util::Error),
32 }
33 
34 impl error::Error for Error {}
35 
36 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result37     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38         use Error::*;
39         match self {
40             CreateStream(e) => write!(f, "Failed to create stream: {}", e),
41             FetchStream(e) => write!(f, "Failed to fetch buffer from stream: {}", e),
42             FloatingPointSamples => write!(f, "Floating point audio samples are not supported"),
43             InvalidWavFile(e) => write!(f, "Could not open file as WAV file: {}", e),
44             Io(e) => write!(f, "IO Error: {}", e),
45             Libcras(e) => write!(f, "Libcras Error: {}", e),
46             NoLoopbackNode(typ) => write!(f, "No loopback node found with type {:?}", typ),
47             OpenFile(e) => write!(f, "Could not open WAV file for writing: {}", e),
48             SampleBits(bits) => write!(
49                 f,
50                 "Sample size {} is not supported, only 8, 16, 24, and 32 bit samples are supported",
51                 bits
52             ),
53             SysUtil(e) => write!(f, "SysUtil Error: {}", e),
54         }
55     }
56 }
57 
58 type Result<T> = std::result::Result<T, Error>;
59 
60 static INTERRUPTED: AtomicBool = AtomicBool::new(false);
61 
sigint_handler(_: c_int)62 extern "C" fn sigint_handler(_: c_int) {
63     // Check if we've already received one SIGINT. If we have, the program may
64     // be misbehaving and not terminating, so to be safe we'll forcefully exit.
65     if INTERRUPTED.load(Ordering::Acquire) {
66         std::process::exit(1);
67     }
68     INTERRUPTED.store(true, Ordering::Release);
69 }
70 
add_sigint_handler() -> Result<()>71 fn add_sigint_handler() -> Result<()> {
72     const SIGINT: c_int = 2;
73     let result = unsafe { register_signal_handler(SIGINT, sigint_handler) };
74     result.map_err(Error::SysUtil)
75 }
76 
set_priority_to_realtime()77 fn set_priority_to_realtime() {
78     const AUDIO_THREAD_RTPRIO: u16 = 10;
79     if set_rt_prio_limit(AUDIO_THREAD_RTPRIO as u64).is_err()
80         || set_rt_round_robin(AUDIO_THREAD_RTPRIO as i32).is_err()
81     {
82         println!("Attempt to use real-time priority failed, running with default scheduler.");
83     }
84 }
85 
channel_string(num_channels: usize) -> String86 fn channel_string(num_channels: usize) -> String {
87     match num_channels {
88         1 => "Mono".to_string(),
89         2 => "Stereo".to_string(),
90         _ => format!("{} Channels", num_channels),
91     }
92 }
93 
94 struct WavSource {
95     wav_reader: WavReader<BufReader<File>>,
96     format: SampleFormat,
97     num_channels: usize,
98     frame_rate: u32,
99 }
100 
101 impl WavSource {
try_new(opts: &AudioOptions) -> Result<Self>102     fn try_new(opts: &AudioOptions) -> Result<Self> {
103         let wav_reader = WavReader::open(&opts.file_name).map_err(Error::InvalidWavFile)?;
104         let spec = wav_reader.spec();
105         if spec.sample_format == hound::SampleFormat::Float {
106             return Err(Error::FloatingPointSamples);
107         }
108 
109         let format = match spec.bits_per_sample {
110             8 => SampleFormat::U8,
111             16 => SampleFormat::S16LE,
112             24 => SampleFormat::S24LE,
113             32 => SampleFormat::S32LE,
114             s => return Err(Error::SampleBits(s)),
115         };
116         if opts.format.is_some() && Some(format) != opts.format {
117             eprintln!("Warning: format changed to {:?}", format);
118         }
119 
120         let num_channels = spec.channels as usize;
121         if opts.num_channels.is_some() && Some(num_channels) != opts.num_channels {
122             eprintln!("Warning: number of channels changed to {}", num_channels);
123         }
124 
125         let frame_rate = spec.sample_rate;
126         if opts.frame_rate.is_some() && Some(frame_rate) != opts.frame_rate {
127             eprintln!("Warning: frame rate changed to {}", frame_rate);
128         }
129 
130         Ok(Self {
131             wav_reader,
132             format,
133             num_channels,
134             frame_rate,
135         })
136     }
137 
format(&self) -> SampleFormat138     fn format(&self) -> SampleFormat {
139         self.format
140     }
141 
num_channels(&self) -> usize142     fn num_channels(&self) -> usize {
143         self.num_channels
144     }
145 
frame_rate(&self) -> u32146     fn frame_rate(&self) -> u32 {
147         self.frame_rate
148     }
149 }
150 
151 impl Read for WavSource {
read(&mut self, mut buf: &mut [u8]) -> io::Result<usize>152     fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
153         let frame_size = self.format.sample_bytes() * self.num_channels;
154         let read_len = buf.len() - buf.len() % frame_size;
155         let num_samples = read_len / self.format.sample_bytes();
156         let samples = self.wav_reader.samples::<i32>();
157         let mut read = 0;
158         for s in samples.take(num_samples) {
159             match s {
160                 Ok(sample) => {
161                     let result = match self.format {
162                         SampleFormat::U8 => buf.write_all(&((sample + 128) as u8).to_le_bytes()),
163                         SampleFormat::S16LE => buf.write_all(&(sample as i16).to_le_bytes()),
164                         SampleFormat::S24LE | SampleFormat::S32LE => {
165                             buf.write_all(&sample.to_le_bytes())
166                         }
167                     };
168 
169                     match result {
170                         Ok(()) => read += self.format.sample_bytes(),
171                         Err(_) => return Ok(read),
172                     };
173                 }
174                 Err(_) => return Ok(read),
175             };
176         }
177         Ok(read)
178     }
179 }
180 
playback(opts: AudioOptions) -> Result<()>181 pub fn playback(opts: AudioOptions) -> Result<()> {
182     let num_channels;
183     let frame_rate;
184     let format;
185     let mut sample_source: Box<dyn Read> = match opts.file_type {
186         FileType::Wav => {
187             let wav_source = WavSource::try_new(&opts)?;
188             num_channels = wav_source.num_channels();
189             frame_rate = wav_source.frame_rate();
190             format = wav_source.format();
191             Box::new(wav_source)
192         }
193         FileType::Raw => {
194             num_channels = opts.num_channels.unwrap_or(2);
195             frame_rate = opts.frame_rate.unwrap_or(48000);
196             format = opts.format.unwrap_or(SampleFormat::S16LE);
197             Box::new(BufReader::new(
198                 File::open(&opts.file_name).map_err(Error::Io)?,
199             ))
200         }
201     };
202 
203     println!(
204         "Playing {} '{}' : {}, Rate {} Hz, {}",
205         opts.file_type,
206         opts.file_name.display(),
207         format,
208         frame_rate,
209         channel_string(num_channels)
210     );
211 
212     let mut cras_client = CrasClient::new().map_err(Error::Libcras)?;
213     let (_control, mut stream) = cras_client
214         .new_playback_stream(
215             num_channels,
216             format,
217             frame_rate,
218             opts.buffer_size.unwrap_or(256),
219         )
220         .map_err(Error::CreateStream)?;
221     set_priority_to_realtime();
222 
223     add_sigint_handler()?;
224     while !INTERRUPTED.load(Ordering::Acquire) {
225         let mut buffer = stream.next_playback_buffer().map_err(Error::FetchStream)?;
226 
227         let frame_size = num_channels * format.sample_bytes();
228         let frames = buffer.frame_capacity();
229 
230         let mut chunk = (&mut sample_source).take((frames * frame_size) as u64);
231         let transferred = io::copy(&mut chunk, &mut buffer).map_err(Error::Io)?;
232         if transferred == 0 {
233             break;
234         }
235     }
236     // Stream and client should gracefully be closed out of this scope
237 
238     Ok(())
239 }
240 
241 struct WavSink {
242     wav_writer: WavWriter<BufWriter<File>>,
243     format: SampleFormat,
244 }
245 
246 impl WavSink {
try_new<P: AsRef<Path>>( path: P, num_channels: usize, format: SampleFormat, frame_rate: u32, ) -> Result<Self>247     fn try_new<P: AsRef<Path>>(
248         path: P,
249         num_channels: usize,
250         format: SampleFormat,
251         frame_rate: u32,
252     ) -> Result<Self> {
253         let spec = WavSpec {
254             channels: num_channels as u16,
255             sample_rate: frame_rate,
256             bits_per_sample: (format.sample_bytes() * 8) as u16,
257             sample_format: hound::SampleFormat::Int,
258         };
259         let wav_writer = WavWriter::create(path, spec).map_err(Error::OpenFile)?;
260         Ok(Self { wav_writer, format })
261     }
262 }
263 
264 impl Write for WavSink {
write(&mut self, samples: &[u8]) -> io::Result<usize>265     fn write(&mut self, samples: &[u8]) -> io::Result<usize> {
266         let sample_bytes = self.format.sample_bytes();
267         if samples.len() % sample_bytes != 0 {
268             return Err(io::Error::new(
269                 io::ErrorKind::InvalidInput,
270                 format!(
271                     "u8 samples vector of length {} cannot be interpreted as {:?} samples",
272                     samples.len(),
273                     self.format
274                 ),
275             ));
276         }
277         let num_samples = samples.len() / sample_bytes;
278         match self.format {
279             SampleFormat::U8 => {
280                 for sample in samples {
281                     self.wav_writer.write_sample(*sample as i8).map_err(|e| {
282                         io::Error::new(
283                             io::ErrorKind::Other,
284                             format!("Failed to write sample: {}", e),
285                         )
286                     })?;
287                 }
288             }
289             SampleFormat::S16LE => {
290                 // hound offers an optimized i16 writer, so special case here.
291                 let mut writer = self.wav_writer.get_i16_writer(num_samples as u32);
292                 for i in 0..num_samples {
293                     let sample = i16::from_le_bytes([
294                         samples[sample_bytes * i],
295                         samples[sample_bytes * i + 1],
296                     ]);
297                     writer.write_sample(sample);
298                 }
299                 // I16Writer buffers internally and must be explicitly flushed to write
300                 // samples to the backing writer. Flush is not called automatically
301                 // on drop.
302                 // The flush method only writes data from the i16_writer to the underlying
303                 // WavWriter, it does not actually guarantee a flush to disk.
304                 writer.flush().map_err(|e| {
305                     io::Error::new(
306                         io::ErrorKind::Other,
307                         format!("Failed to flush SampleWriter: {}", e),
308                     )
309                 })?;
310             }
311             SampleFormat::S24LE | SampleFormat::S32LE => {
312                 for i in 0..num_samples {
313                     let mut sample = i32::from_le_bytes([
314                         samples[sample_bytes * i],
315                         samples[sample_bytes * i + 1],
316                         samples[sample_bytes * i + 2],
317                         samples[sample_bytes * i + 3],
318                     ]);
319 
320                     // Upsample to 32 bit since CRAS doesn't support S24_3LE.
321                     // Our wav encoder/decoder, hound, does have support for
322                     // S24_LE, but it hasn't released a new version since the
323                     // support was added. If getting that support is an issue,
324                     // push upstream to cut a new a release.
325                     if self.format == SampleFormat::S24LE {
326                         sample <<= 8;
327                     }
328 
329                     self.wav_writer.write_sample(sample).map_err(|e| {
330                         io::Error::new(
331                             io::ErrorKind::Other,
332                             format!("Failed to write sample: {}", e),
333                         )
334                     })?;
335                 }
336             }
337         }
338 
339         Ok(samples.len())
340     }
341 
flush(&mut self) -> io::Result<()>342     fn flush(&mut self) -> io::Result<()> {
343         self.wav_writer.flush().map_err(|e| {
344             io::Error::new(
345                 io::ErrorKind::Other,
346                 format!("Failed to flush WavWriter: {}", e),
347             )
348         })
349     }
350 }
351 
capture(opts: AudioOptions) -> Result<()>352 pub fn capture(opts: AudioOptions) -> Result<()> {
353     let num_channels = opts.num_channels.unwrap_or(2);
354     let format = opts.format.unwrap_or(SampleFormat::S16LE);
355     let frame_rate = opts.frame_rate.unwrap_or(48000);
356     let buffer_size = opts.buffer_size.unwrap_or(256);
357 
358     let mut sample_sink: Box<dyn Write> = match opts.file_type {
359         FileType::Raw => Box::new(BufWriter::new(
360             File::create(&opts.file_name).map_err(Error::Io)?,
361         )),
362         FileType::Wav => Box::new(WavSink::try_new(
363             &opts.file_name,
364             num_channels,
365             format,
366             frame_rate,
367         )?),
368     };
369 
370     println!(
371         "Recording {} '{}' : {}, Rate {} Hz, {}",
372         opts.file_type,
373         opts.file_name.display(),
374         format,
375         frame_rate,
376         channel_string(num_channels)
377     );
378 
379     let mut cras_client = CrasClient::new().map_err(Error::Libcras)?;
380     cras_client.enable_cras_capture();
381     let (_control, mut stream) = match opts.loopback_type {
382         Some(loopback_type) => {
383             let node_type = match loopback_type {
384                 LoopbackType::PreDsp => CrasNodeType::CRAS_NODE_TYPE_POST_MIX_PRE_DSP,
385                 LoopbackType::PostDsp => CrasNodeType::CRAS_NODE_TYPE_POST_DSP,
386             };
387 
388             let loopback_node = cras_client
389                 .input_nodes()
390                 .find(|node| node.node_type == node_type)
391                 .ok_or(Error::NoLoopbackNode(node_type))?;
392 
393             cras_client
394                 .new_pinned_capture_stream(
395                     loopback_node.iodev_index,
396                     num_channels,
397                     format,
398                     frame_rate,
399                     buffer_size,
400                 )
401                 .map_err(Error::CreateStream)?
402         }
403         None => cras_client
404             .new_capture_stream(num_channels, format, frame_rate, buffer_size)
405             .map_err(Error::CreateStream)?,
406     };
407     set_priority_to_realtime();
408     add_sigint_handler()?;
409     while !INTERRUPTED.load(Ordering::Acquire) {
410         let mut buf = stream.next_capture_buffer().map_err(Error::FetchStream)?;
411         io::copy(&mut buf, &mut sample_sink).map_err(Error::Io)?;
412     }
413     Ok(())
414 }
415