• 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 mod audio_options;
6 
7 use std::fs::File;
8 use std::io::{self, BufRead, BufReader, Write};
9 use std::thread::spawn;
10 use sys_util::{set_rt_prio_limit, set_rt_round_robin};
11 type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
12 
13 use audio_streams::StreamSource;
14 use libcras::CrasClient;
15 
16 use crate::audio_options::{AudioOptions, Subcommand};
17 
set_priority_to_realtime()18 fn set_priority_to_realtime() {
19     const AUDIO_THREAD_RTPRIO: u16 = 10;
20     if set_rt_prio_limit(AUDIO_THREAD_RTPRIO as u64).is_err()
21         || set_rt_round_robin(AUDIO_THREAD_RTPRIO as i32).is_err()
22     {
23         println!("Attempt to use real-time priority failed, running with default scheduler.");
24     }
25 }
26 
channel_string(num_channels: usize) -> String27 fn channel_string(num_channels: usize) -> String {
28     match num_channels {
29         1 => "Mono".to_string(),
30         2 => "Stereo".to_string(),
31         _ => format!("{} Channels", num_channels),
32     }
33 }
34 
playback(opts: AudioOptions) -> Result<()>35 fn playback(opts: AudioOptions) -> Result<()> {
36     let file = File::open(&opts.file_name).expect("failed to open file");
37     let mut buffered_file = BufReader::new(file);
38 
39     let num_channels = opts.num_channels.unwrap_or(2);
40     let frame_rate = opts.frame_rate.unwrap_or(48000);
41 
42     println!(
43         "Playing raw data '{}' : Signed 16 bit Little Endian, Rate {} Hz, {}",
44         opts.file_name.display(),
45         frame_rate,
46         channel_string(num_channels)
47     );
48 
49     let mut cras_client = CrasClient::new()?;
50     let (_control, mut stream) = cras_client.new_playback_stream(
51         num_channels,
52         frame_rate,
53         opts.buffer_size.unwrap_or(256),
54     )?;
55     let thread = spawn(move || {
56         set_priority_to_realtime();
57         loop {
58             let local_buffer = buffered_file
59                 .fill_buf()
60                 .expect("failed to read from input file");
61 
62             // Reached EOF
63             if local_buffer.len() == 0 {
64                 break;
65             }
66 
67             // Gets writable buffer from stream
68             let mut buffer = stream
69                 .next_playback_buffer()
70                 .expect("failed to get next playback buffer");
71 
72             // Writes data to stream buffer
73             let write_frames = buffer
74                 .write(&local_buffer)
75                 .expect("failed to write output data to buffer");
76 
77             // Mark the file data as written
78             buffered_file.consume(write_frames);
79         }
80     });
81     thread.join().expect("Failed to join playback thread");
82     // Stream and client should gracefully be closed out of this scope
83 
84     Ok(())
85 }
86 
capture(opts: AudioOptions) -> Result<()>87 fn capture(opts: AudioOptions) -> Result<()> {
88     let num_channels = opts.num_channels.unwrap_or(2);
89     let frame_rate = opts.frame_rate.unwrap_or(48000);
90 
91     println!(
92         "Recording raw data '{}' : Signed 16 bit Little Endian, Rate {} Hz, {}",
93         opts.file_name.display(),
94         frame_rate,
95         channel_string(num_channels)
96     );
97 
98     let mut cras_client = CrasClient::new()?;
99     cras_client.enable_cras_capture();
100     let (_control, mut stream) = cras_client.new_capture_stream(
101         num_channels,
102         frame_rate,
103         opts.buffer_size.unwrap_or(256),
104     )?;
105     let mut file = File::create(&opts.file_name).unwrap();
106     loop {
107         let _frames = match stream.next_capture_buffer() {
108             Err(e) => {
109                 return Err(e.into());
110             }
111             Ok(mut buf) => {
112                 let written = io::copy(&mut buf, &mut file)?;
113                 written
114             }
115         };
116     }
117 }
118 
main() -> Result<()>119 fn main() -> Result<()> {
120     let args: Vec<String> = std::env::args().collect();
121     let opts = match AudioOptions::parse_from_args(&args)? {
122         None => return Ok(()),
123         Some(v) => v,
124     };
125 
126     match opts.subcommand {
127         Subcommand::Capture => capture(opts)?,
128         Subcommand::Playback => playback(opts)?,
129     };
130     Ok(())
131 }
132