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 //! Provides an interface for playing and recording audio through CRAS server. 5 //! 6 //! `CrasClient` implements `StreamSource` trait and it can create playback or capture 7 //! stream - `CrasStream` which can be a 8 //! - `PlaybackBufferStream` for audio playback or 9 //! - `CaptureBufferStream` for audio capture. 10 //! 11 //! # Example of file audio playback 12 //! 13 //! `PlaybackBuffer`s to be filled with audio samples are obtained by calling 14 //! `next_playback_buffer` from `CrasStream`. 15 //! 16 //! Users playing audio fill the provided buffers with audio. When a `PlaybackBuffer` is dropped, 17 //! the samples written to it are committed to the `CrasStream` it came from. 18 //! 19 //! 20 //! ``` 21 //! // An example of playing raw audio data from a given file 22 //! use std::env; 23 //! use std::fs::File; 24 //! use std::io::{Read, Write}; 25 //! use std::thread::{spawn, JoinHandle}; 26 //! type Result<T> = std::result::Result<T, Box<std::error::Error>>; 27 //! 28 //! use libcras::{CrasClient, CrasClientType}; 29 //! use audio_streams::StreamSource; 30 //! 31 //! const BUFFER_SIZE: usize = 256; 32 //! const FRAME_RATE: usize = 44100; 33 //! const NUM_CHANNELS: usize = 2; 34 //! 35 //! # fn main() -> Result<()> { 36 //! # let args: Vec<String> = env::args().collect(); 37 //! # match args.len() { 38 //! # 2 => { 39 //! let mut cras_client = CrasClient::new()?; 40 //! cras_client.set_client_type(CrasClientType::CRAS_CLIENT_TYPE_TEST); 41 //! let (_control, mut stream) = cras_client 42 //! .new_playback_stream(NUM_CHANNELS, FRAME_RATE, BUFFER_SIZE)?; 43 //! 44 //! // Plays 1000 * BUFFER_SIZE samples from the given file 45 //! let mut file = File::open(&args[1])?; 46 //! let mut local_buffer = [0u8; BUFFER_SIZE * NUM_CHANNELS * 2]; 47 //! for _i in 0..1000 { 48 //! // Reads data to local buffer 49 //! let _read_count = file.read(&mut local_buffer)?; 50 //! 51 //! // Gets writable buffer from stream and 52 //! let mut buffer = stream.next_playback_buffer()?; 53 //! // Writes data to stream buffer 54 //! let _write_frames = buffer.write(&local_buffer)?; 55 //! } 56 //! // Stream and client should gracefully be closed out of this scope 57 //! # } 58 //! # _ => { 59 //! # println!("{} /path/to/playback_file.raw", args[0]); 60 //! # } 61 //! # }; 62 //! # Ok(()) 63 //! # } 64 //! ``` 65 //! 66 //! # Example of file audio capture 67 //! 68 //! `CaptureBuffer`s which contain audio samples are obtained by calling 69 //! `next_capture_buffer` from `CrasStream`. 70 //! 71 //! Users get captured audio samples from the provided buffers. When a `CaptureBuffer` is dropped, 72 //! the number of read samples will be committed to the `CrasStream` it came from. 73 //! ``` 74 //! use std::env; 75 //! use std::fs::File; 76 //! use std::io::{Read, Write}; 77 //! use std::thread::{spawn, JoinHandle}; 78 //! type Result<T> = std::result::Result<T, Box<std::error::Error>>; 79 //! 80 //! use libcras::{CrasClient, CrasClientType}; 81 //! use audio_streams::StreamSource; 82 //! 83 //! const BUFFER_SIZE: usize = 256; 84 //! const FRAME_RATE: usize = 44100; 85 //! const NUM_CHANNELS: usize = 2; 86 //! 87 //! # fn main() -> Result<()> { 88 //! # let args: Vec<String> = env::args().collect(); 89 //! # match args.len() { 90 //! # 2 => { 91 //! let mut cras_client = CrasClient::new()?; 92 //! cras_client.set_client_type(CrasClientType::CRAS_CLIENT_TYPE_TEST); 93 //! let (_control, mut stream) = cras_client 94 //! .new_capture_stream(NUM_CHANNELS, FRAME_RATE, BUFFER_SIZE)?; 95 //! 96 //! // Capture 1000 * BUFFER_SIZE samples to the given file 97 //! let mut file = File::create(&args[1])?; 98 //! let mut local_buffer = [0u8; BUFFER_SIZE * NUM_CHANNELS * 2]; 99 //! for _i in 0..1000 { 100 //! 101 //! // Gets readable buffer from stream and 102 //! let mut buffer = stream.next_capture_buffer()?; 103 //! // Reads data to local buffer 104 //! let read_count = buffer.read(&mut local_buffer)?; 105 //! // Writes data to file 106 //! let _read_frames = file.write(&local_buffer[..read_count])?; 107 //! } 108 //! // Stream and client should gracefully be closed out of this scope 109 //! # } 110 //! # _ => { 111 //! # println!("{} /path/to/capture_file.raw", args[0]); 112 //! # } 113 //! # }; 114 //! # Ok(()) 115 //! # } 116 //! ``` 117 use std::io; 118 use std::mem; 119 use std::os::unix::{ 120 io::{AsRawFd, RawFd}, 121 net::UnixStream, 122 }; 123 use std::{error, fmt}; 124 125 use audio_streams::{ 126 capture::{CaptureBufferStream, DummyCaptureStream}, 127 BufferDrop, DummyStreamControl, PlaybackBufferStream, StreamControl, StreamSource, 128 }; 129 pub use cras_sys::gen::CRAS_CLIENT_TYPE as CrasClientType; 130 use cras_sys::gen::*; 131 use sys_util::{PollContext, PollToken}; 132 133 mod audio_socket; 134 use crate::audio_socket::AudioSocket; 135 mod cras_server_socket; 136 use crate::cras_server_socket::CrasServerSocket; 137 mod cras_shm; 138 mod cras_stream; 139 use crate::cras_stream::{CrasCaptureData, CrasPlaybackData, CrasStream, CrasStreamData}; 140 mod cras_client_message; 141 use crate::cras_client_message::*; 142 143 #[derive(Debug)] 144 pub enum ErrorType { 145 CrasClientMessageError(cras_client_message::Error), 146 CrasStreamError(cras_stream::Error), 147 IoError(io::Error), 148 SysUtilError(sys_util::Error), 149 MessageTypeError, 150 UnexpectedExit, 151 } 152 153 #[derive(Debug)] 154 pub struct Error { 155 error_type: ErrorType, 156 } 157 158 impl Error { new(error_type: ErrorType) -> Self159 fn new(error_type: ErrorType) -> Self { 160 Self { error_type } 161 } 162 } 163 164 impl error::Error for Error {} 165 166 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 168 match self.error_type { 169 ErrorType::CrasClientMessageError(ref err) => err.fmt(f), 170 ErrorType::CrasStreamError(ref err) => err.fmt(f), 171 ErrorType::IoError(ref err) => err.fmt(f), 172 ErrorType::SysUtilError(ref err) => err.fmt(f), 173 ErrorType::MessageTypeError => write!(f, "Message type error"), 174 ErrorType::UnexpectedExit => write!(f, "Unexpected exit"), 175 } 176 } 177 } 178 179 type Result<T> = std::result::Result<T, Error>; 180 181 impl From<io::Error> for Error { from(io_err: io::Error) -> Self182 fn from(io_err: io::Error) -> Self { 183 Self::new(ErrorType::IoError(io_err)) 184 } 185 } 186 187 impl From<sys_util::Error> for Error { from(sys_util_err: sys_util::Error) -> Self188 fn from(sys_util_err: sys_util::Error) -> Self { 189 Self::new(ErrorType::SysUtilError(sys_util_err)) 190 } 191 } 192 193 impl From<cras_stream::Error> for Error { from(err: cras_stream::Error) -> Self194 fn from(err: cras_stream::Error) -> Self { 195 Self::new(ErrorType::CrasStreamError(err)) 196 } 197 } 198 199 impl From<cras_client_message::Error> for Error { from(err: cras_client_message::Error) -> Self200 fn from(err: cras_client_message::Error) -> Self { 201 Self::new(ErrorType::CrasClientMessageError(err)) 202 } 203 } 204 205 /// A CRAS server client, which implements StreamSource. It can create audio streams connecting 206 /// to CRAS server. 207 pub struct CrasClient { 208 server_socket: CrasServerSocket, 209 client_id: u32, 210 next_stream_id: u32, 211 cras_capture: bool, 212 client_type: CRAS_CLIENT_TYPE, 213 } 214 215 impl CrasClient { 216 /// Blocks creating a `CrasClient` with registered `client_id` 217 /// 218 /// # Results 219 /// 220 /// * `CrasClient` - A client to interact with CRAS server 221 /// 222 /// # Errors 223 /// 224 /// Returns error if error occurs while handling server message or message 225 /// type is incorrect new() -> Result<Self>226 pub fn new() -> Result<Self> { 227 // Create a connection to the server. 228 let mut server_socket = CrasServerSocket::new()?; 229 230 // Gets client ID from server 231 let client_id = { 232 match CrasClient::wait_for_message(&mut server_socket)? { 233 ServerResult::Connected(res, _server_state_fd) => res as u32, 234 _ => { 235 return Err(Error::new(ErrorType::MessageTypeError)); 236 } 237 } 238 }; 239 240 Ok(Self { 241 server_socket, 242 client_id, 243 next_stream_id: 0, 244 cras_capture: false, 245 client_type: CRAS_CLIENT_TYPE::CRAS_CLIENT_TYPE_UNKNOWN, 246 }) 247 } 248 249 /// Enables capturing audio through CRAS server. enable_cras_capture(&mut self)250 pub fn enable_cras_capture(&mut self) { 251 self.cras_capture = true; 252 } 253 254 /// Set the type of this client to report to CRAS when connecting streams. set_client_type(&mut self, client_type: CRAS_CLIENT_TYPE)255 pub fn set_client_type(&mut self, client_type: CRAS_CLIENT_TYPE) { 256 self.client_type = client_type; 257 } 258 259 // Gets next server_stream_id from client and increment stream_id counter. next_server_stream_id(&mut self) -> Result<u32>260 fn next_server_stream_id(&mut self) -> Result<u32> { 261 let res = self.next_stream_id; 262 self.next_stream_id += 1; 263 self.server_stream_id(&res) 264 } 265 266 // Gets server_stream_id from given stream_id server_stream_id(&self, stream_id: &u32) -> Result<u32>267 fn server_stream_id(&self, stream_id: &u32) -> Result<u32> { 268 Ok((self.client_id << 16) | stream_id) 269 } 270 271 // Creates general stream with given parameters create_stream<'a, T: BufferDrop + CrasStreamData<'a>>( &mut self, block_size: u32, direction: CRAS_STREAM_DIRECTION, rate: usize, channel_num: usize, format: snd_pcm_format_t, ) -> Result<CrasStream<'a, T>>272 fn create_stream<'a, T: BufferDrop + CrasStreamData<'a>>( 273 &mut self, 274 block_size: u32, 275 direction: CRAS_STREAM_DIRECTION, 276 rate: usize, 277 channel_num: usize, 278 format: snd_pcm_format_t, 279 ) -> Result<CrasStream<'a, T>> { 280 let stream_id = self.next_server_stream_id()?; 281 282 // Prepares server message 283 let audio_format = cras_audio_format_packed::new(format, rate, channel_num); 284 let msg_header = cras_server_message { 285 length: mem::size_of::<cras_connect_message>() as u32, 286 id: CRAS_SERVER_MESSAGE_ID::CRAS_SERVER_CONNECT_STREAM, 287 }; 288 let server_cmsg = cras_connect_message { 289 header: msg_header, 290 proto_version: CRAS_PROTO_VER, 291 direction, 292 stream_id, 293 stream_type: CRAS_STREAM_TYPE::CRAS_STREAM_TYPE_DEFAULT, 294 buffer_frames: block_size, 295 cb_threshold: block_size, 296 flags: 0, 297 format: audio_format, 298 dev_idx: CRAS_SPECIAL_DEVICE::NO_DEVICE as u32, 299 effects: 0, 300 client_type: self.client_type, 301 client_shm_size: 0, 302 }; 303 304 // Creates AudioSocket pair 305 let (sock1, sock2) = UnixStream::pair()?; 306 307 // Sends `CRAS_SERVER_CONNECT_STREAM` message 308 let socks = [sock2.as_raw_fd()]; 309 self.server_socket 310 .send_server_message_with_fds(&server_cmsg, &socks)?; 311 312 let audio_socket = AudioSocket::new(sock1); 313 let mut stream = CrasStream::new( 314 stream_id, 315 self.server_socket.try_clone()?, 316 block_size, 317 direction, 318 rate, 319 channel_num, 320 format, 321 audio_socket, 322 ); 323 324 loop { 325 let result = CrasClient::wait_for_message(&mut self.server_socket)?; 326 if let ServerResult::StreamConnected(_stream_id, header_fd, samples_fd) = result { 327 stream.init_shm(header_fd, samples_fd)?; 328 break; 329 } 330 } 331 332 Ok(stream) 333 } 334 335 // Blocks handling the first server message received from `socket`. wait_for_message(socket: &mut CrasServerSocket) -> Result<ServerResult>336 fn wait_for_message(socket: &mut CrasServerSocket) -> Result<ServerResult> { 337 #[derive(PollToken)] 338 enum Token { 339 ServerMsg, 340 } 341 let poll_ctx: PollContext<Token> = 342 PollContext::new().and_then(|pc| pc.add(socket, Token::ServerMsg).and(Ok(pc)))?; 343 344 let events = poll_ctx.wait()?; 345 // Check the first readable message 346 let tokens: Vec<Token> = events.iter_readable().map(|e| e.token()).collect(); 347 tokens 348 .get(0) 349 .ok_or_else(|| Error::new(ErrorType::UnexpectedExit)) 350 .and_then(|ref token| { 351 match token { 352 Token::ServerMsg => ServerResult::handle_server_message(socket), 353 } 354 .map_err(Into::into) 355 }) 356 } 357 } 358 359 impl StreamSource for CrasClient { new_playback_stream( &mut self, num_channels: usize, frame_rate: usize, buffer_size: usize, ) -> std::result::Result< (Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), Box<dyn error::Error>, >360 fn new_playback_stream( 361 &mut self, 362 num_channels: usize, 363 frame_rate: usize, 364 buffer_size: usize, 365 ) -> std::result::Result< 366 (Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), 367 Box<dyn error::Error>, 368 > { 369 Ok(( 370 Box::new(DummyStreamControl::new()), 371 Box::new(self.create_stream::<CrasPlaybackData>( 372 buffer_size as u32, 373 CRAS_STREAM_DIRECTION::CRAS_STREAM_OUTPUT, 374 frame_rate, 375 num_channels, 376 _snd_pcm_format::SND_PCM_FORMAT_S16_LE, 377 )?), 378 )) 379 } 380 new_capture_stream( &mut self, num_channels: usize, frame_rate: usize, buffer_size: usize, ) -> std::result::Result< (Box<dyn StreamControl>, Box<dyn CaptureBufferStream>), Box<dyn error::Error>, >381 fn new_capture_stream( 382 &mut self, 383 num_channels: usize, 384 frame_rate: usize, 385 buffer_size: usize, 386 ) -> std::result::Result< 387 (Box<dyn StreamControl>, Box<dyn CaptureBufferStream>), 388 Box<dyn error::Error>, 389 > { 390 if self.cras_capture { 391 Ok(( 392 Box::new(DummyStreamControl::new()), 393 Box::new(self.create_stream::<CrasCaptureData>( 394 buffer_size as u32, 395 CRAS_STREAM_DIRECTION::CRAS_STREAM_INPUT, 396 frame_rate, 397 num_channels, 398 _snd_pcm_format::SND_PCM_FORMAT_S16_LE, 399 )?), 400 )) 401 } else { 402 Ok(( 403 Box::new(DummyStreamControl::new()), 404 Box::new(DummyCaptureStream::new( 405 num_channels, 406 frame_rate, 407 buffer_size, 408 )), 409 )) 410 } 411 } 412 keep_fds(&self) -> Option<Vec<RawFd>>413 fn keep_fds(&self) -> Option<Vec<RawFd>> { 414 Some(vec![self.server_socket.as_raw_fd()]) 415 } 416 } 417