diff options
Diffstat (limited to 'cras/client/libcras/src/audio_socket.rs')
-rw-r--r-- | cras/client/libcras/src/audio_socket.rs | 316 |
1 files changed, 0 insertions, 316 deletions
diff --git a/cras/client/libcras/src/audio_socket.rs b/cras/client/libcras/src/audio_socket.rs deleted file mode 100644 index ac56144c..00000000 --- a/cras/client/libcras/src/audio_socket.rs +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2019 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -use std::io; -use std::io::{Read, Write}; -use std::mem; -use std::os::unix::{ - io::{AsRawFd, RawFd}, - net::UnixStream, -}; -use std::time::Duration; - -use cras_sys::gen::{audio_message, CRAS_AUDIO_MESSAGE_ID}; -use data_model::DataInit; -use sys_util::{PollContext, PollToken}; - -/// A structure for interacting with the CRAS server audio thread through a `UnixStream::pair`. -pub struct AudioSocket { - socket: UnixStream, -} - -/// Audio message results which are exchanged by `CrasStream` and CRAS audio server. -/// through an audio socket. -#[allow(dead_code)] -#[derive(Debug)] -pub enum AudioMessage { - /// * `id` - Audio message id, which is a `enum CRAS_AUDIO_MESSAGE_ID`. - /// * `frames` - A `u32` indicating the read or written frame count. - Success { - id: CRAS_AUDIO_MESSAGE_ID, - frames: u32, - }, - /// * `error` - Error code when a error occurs. - Error(i32), -} - -/// Converts AudioMessage to raw audio_message for CRAS audio server. -impl Into<audio_message> for AudioMessage { - fn into(self) -> audio_message { - match self { - AudioMessage::Success { id, frames } => audio_message { - id, - error: 0, - frames, - }, - AudioMessage::Error(error) => audio_message { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA, - error, - frames: 0, - }, - } - } -} - -/// Converts AudioMessage from raw audio_message from CRAS audio server. -impl From<audio_message> for AudioMessage { - fn from(message: audio_message) -> Self { - match message.error { - 0 => AudioMessage::Success { - id: message.id as CRAS_AUDIO_MESSAGE_ID, - frames: message.frames, - }, - error => AudioMessage::Error(error), - } - } -} - -impl AudioSocket { - /// Creates `AudioSocket` from a `UnixStream`. - /// - /// # Arguments - /// `socket` - A `UnixStream`. - pub fn new(socket: UnixStream) -> Self { - AudioSocket { socket } - } - - fn read_from_socket<T>(&mut self) -> io::Result<T> - where - T: Sized + DataInit + Default, - { - let mut message: T = Default::default(); - let rc = self.socket.read(message.as_mut_slice())?; - if rc == mem::size_of::<T>() { - Ok(message) - } else { - Err(io::Error::new(io::ErrorKind::Other, "Read truncated data.")) - } - } - - /// Blocks reading an `audio message`. - /// - /// # Returns - /// `AudioMessage` - AudioMessage enum. - /// - /// # Errors - /// Returns io::Error if error occurs. - pub fn read_audio_message(&mut self) -> io::Result<AudioMessage> { - match self.read_audio_message_with_timeout(None)? { - None => Err(io::Error::new(io::ErrorKind::Other, "Unexpected exit")), - Some(message) => Ok(message), - } - } - - /// Blocks waiting for an `audio message` until `timeout` occurs. If `timeout` - /// is None, blocks indefinitely. - /// - /// # Returns - /// Some(AudioMessage) - AudioMessage enum if we receive a message before timeout. - /// None - If the timeout expires. - /// - /// # Errors - /// Returns io::Error if error occurs. - pub fn read_audio_message_with_timeout( - &mut self, - timeout: Option<Duration>, - ) -> io::Result<Option<AudioMessage>> { - #[derive(PollToken)] - enum Token { - AudioMsg, - } - let poll_ctx: PollContext<Token> = - match PollContext::new().and_then(|pc| pc.add(self, Token::AudioMsg).and(Ok(pc))) { - Ok(pc) => pc, - Err(e) => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Failed to create PollContext: {}", e), - )); - } - }; - let events = { - let result = match timeout { - None => poll_ctx.wait(), - Some(duration) => poll_ctx.wait_timeout(duration), - }; - match result { - Ok(v) => v, - Err(e) => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Failed to poll: {:?}", e), - )); - } - } - }; - - // Check the first readable message - let tokens: Vec<Token> = events.iter_readable().map(|e| e.token()).collect(); - match tokens.get(0) { - None => Ok(None), - Some(&Token::AudioMsg) => { - let raw_msg: audio_message = self.read_from_socket()?; - Ok(Some(AudioMessage::from(raw_msg))) - } - } - } - - /// Sends raw audio message with given AudioMessage enum. - /// - /// # Arguments - /// * `msg` - enum AudioMessage, which could be `Success` with message id - /// and frames or `Error` with error code. - /// - /// # Errors - /// Returns error if `libc::write` fails. - fn send_audio_message(&mut self, msg: AudioMessage) -> io::Result<()> { - let msg: audio_message = msg.into(); - let rc = self.socket.write(msg.as_slice())?; - if rc < mem::size_of::<audio_message>() { - Err(io::Error::new(io::ErrorKind::Other, "Sent truncated data.")) - } else { - Ok(()) - } - } - - /// Sends the data ready message with written frame count. - /// - /// # Arguments - /// * `frames` - An `u32` indicating the written frame count. - pub fn data_ready(&mut self, frames: u32) -> io::Result<()> { - self.send_audio_message(AudioMessage::Success { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_READY, - frames, - }) - } - - /// Sends the capture ready message with read frame count. - /// - /// # Arguments - /// - /// * `frames` - An `u32` indicating the number of read frames. - pub fn capture_ready(&mut self, frames: u32) -> io::Result<()> { - self.send_audio_message(AudioMessage::Success { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_CAPTURED, - frames, - }) - } -} - -impl AsRawFd for AudioSocket { - fn as_raw_fd(&self) -> RawFd { - self.socket.as_raw_fd() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // PartialEq for comparing AudioMessage in tests - impl PartialEq for AudioMessage { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - AudioMessage::Success { id, frames }, - AudioMessage::Success { - id: other_id, - frames: other_frames, - }, - ) => id == other_id && frames == other_frames, - (AudioMessage::Error(err), AudioMessage::Error(other_err)) => err == other_err, - _ => false, - } - } - } - - fn init_audio_socket_pair() -> (AudioSocket, AudioSocket) { - let (sock1, sock2) = UnixStream::pair().unwrap(); - let sender = AudioSocket::new(sock1); - let receiver = AudioSocket::new(sock2); - (sender, receiver) - } - - #[test] - fn audio_socket_send_and_recv_audio_message() { - let (mut sender, mut receiver) = init_audio_socket_pair(); - let message_succ = AudioMessage::Success { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA, - frames: 0, - }; - sender.send_audio_message(message_succ).unwrap(); - let res = receiver.read_audio_message().unwrap(); - assert_eq!( - res, - AudioMessage::Success { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA, - frames: 0 - } - ); - - let message_err = AudioMessage::Error(123); - sender.send_audio_message(message_err).unwrap(); - let res = receiver.read_audio_message().unwrap(); - assert_eq!(res, AudioMessage::Error(123)); - } - - #[test] - fn audio_socket_data_ready_send_and_recv() { - let (sock1, sock2) = UnixStream::pair().unwrap(); - let mut audio_socket_send = AudioSocket::new(sock1); - let mut audio_socket_recv = AudioSocket::new(sock2); - audio_socket_send.data_ready(256).unwrap(); - - // Test receiving by using raw audio_message since CRAS audio server use this. - let audio_msg: audio_message = audio_socket_recv.read_from_socket().unwrap(); - let ref_audio_msg = audio_message { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_READY, - error: 0, - frames: 256, - }; - // Use brace to copy unaligned data locally - assert_eq!({ audio_msg.id }, { ref_audio_msg.id }); - assert_eq!({ audio_msg.error }, { ref_audio_msg.error }); - assert_eq!({ audio_msg.frames }, { ref_audio_msg.frames }); - } - - #[test] - fn audio_socket_capture_ready() { - let (sock1, sock2) = UnixStream::pair().unwrap(); - let mut audio_socket_send = AudioSocket::new(sock1); - let mut audio_socket_recv = AudioSocket::new(sock2); - audio_socket_send - .capture_ready(256) - .expect("Failed to send capture ready message."); - - // Test receiving by using raw audio_message since CRAS audio server use this. - let audio_msg: audio_message = audio_socket_recv - .read_from_socket() - .expect("Failed to read audio message from AudioSocket."); - let ref_audio_msg = audio_message { - id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_CAPTURED, - error: 0, - frames: 256, - }; - // Use brace to copy unaligned data locally - assert_eq!({ audio_msg.id }, { ref_audio_msg.id }); - assert_eq!({ audio_msg.error }, { ref_audio_msg.error }); - assert_eq!({ audio_msg.frames }, { ref_audio_msg.frames }); - } - - #[test] - fn audio_socket_send_when_broken_pipe() { - let sock1 = { - let (sock1, _) = UnixStream::pair().unwrap(); - sock1 - }; - let mut audio_socket = AudioSocket::new(sock1); - let res = audio_socket.data_ready(256); - //Broken pipe - assert_eq!( - res.expect_err("Result should be an error.").kind(), - io::Error::from_raw_os_error(32).kind(), - "Error should be broken pipe.", - ); - } -} |