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