• 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 use std::io;
5 use std::io::{Read, Write};
6 use std::mem;
7 use std::os::unix::{
8     io::{AsRawFd, RawFd},
9     net::UnixStream,
10 };
11 use std::time::Duration;
12 
13 use cras_sys::gen::{audio_message, CRAS_AUDIO_MESSAGE_ID};
14 use data_model::DataInit;
15 use sys_util::{PollContext, PollToken};
16 
17 /// A structure for interacting with the CRAS server audio thread through a `UnixStream::pair`.
18 pub struct AudioSocket {
19     socket: UnixStream,
20 }
21 
22 /// Audio message results which are exchanged by `CrasStream` and CRAS audio server.
23 /// through an audio socket.
24 #[allow(dead_code)]
25 #[derive(Debug)]
26 pub enum AudioMessage {
27     /// * `id` - Audio message id, which is a `enum CRAS_AUDIO_MESSAGE_ID`.
28     /// * `frames` - A `u32` indicating the read or written frame count.
29     Success {
30         id: CRAS_AUDIO_MESSAGE_ID,
31         frames: u32,
32     },
33     /// * `error` - Error code when a error occurs.
34     Error(i32),
35 }
36 
37 /// Converts AudioMessage to raw audio_message for CRAS audio server.
38 impl Into<audio_message> for AudioMessage {
into(self) -> audio_message39     fn into(self) -> audio_message {
40         match self {
41             AudioMessage::Success { id, frames } => audio_message {
42                 id,
43                 error: 0,
44                 frames,
45             },
46             AudioMessage::Error(error) => audio_message {
47                 id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA,
48                 error,
49                 frames: 0,
50             },
51         }
52     }
53 }
54 
55 /// Converts AudioMessage from raw audio_message from CRAS audio server.
56 impl From<audio_message> for AudioMessage {
from(message: audio_message) -> Self57     fn from(message: audio_message) -> Self {
58         match message.error {
59             0 => AudioMessage::Success {
60                 id: message.id as CRAS_AUDIO_MESSAGE_ID,
61                 frames: message.frames,
62             },
63             error => AudioMessage::Error(error),
64         }
65     }
66 }
67 
68 impl AudioSocket {
69     /// Creates `AudioSocket` from a `UnixStream`.
70     ///
71     /// # Arguments
72     /// `socket` - A `UnixStream`.
new(socket: UnixStream) -> Self73     pub fn new(socket: UnixStream) -> Self {
74         AudioSocket { socket }
75     }
76 
read_from_socket<T>(&mut self) -> io::Result<T> where T: Sized + DataInit + Default,77     fn read_from_socket<T>(&mut self) -> io::Result<T>
78     where
79         T: Sized + DataInit + Default,
80     {
81         let mut message: T = Default::default();
82         let rc = self.socket.read(message.as_mut_slice())?;
83         if rc == mem::size_of::<T>() {
84             Ok(message)
85         } else {
86             Err(io::Error::new(io::ErrorKind::Other, "Read truncated data."))
87         }
88     }
89 
90     /// Blocks reading an `audio message`.
91     ///
92     /// # Returns
93     /// `AudioMessage` - AudioMessage enum.
94     ///
95     /// # Errors
96     /// Returns io::Error if error occurs.
read_audio_message(&mut self) -> io::Result<AudioMessage>97     pub fn read_audio_message(&mut self) -> io::Result<AudioMessage> {
98         match self.read_audio_message_with_timeout(None)? {
99             None => Err(io::Error::new(io::ErrorKind::Other, "Unexpected exit")),
100             Some(message) => Ok(message),
101         }
102     }
103 
104     /// Blocks waiting for an `audio message` until `timeout` occurs. If `timeout`
105     /// is None, blocks indefinitely.
106     ///
107     /// # Returns
108     /// Some(AudioMessage) - AudioMessage enum if we receive a message before timeout.
109     /// None - If the timeout expires.
110     ///
111     /// # Errors
112     /// Returns io::Error if error occurs.
read_audio_message_with_timeout( &mut self, timeout: Option<Duration>, ) -> io::Result<Option<AudioMessage>>113     pub fn read_audio_message_with_timeout(
114         &mut self,
115         timeout: Option<Duration>,
116     ) -> io::Result<Option<AudioMessage>> {
117         #[derive(PollToken)]
118         enum Token {
119             AudioMsg,
120         }
121         let poll_ctx: PollContext<Token> =
122             match PollContext::new().and_then(|pc| pc.add(self, Token::AudioMsg).and(Ok(pc))) {
123                 Ok(pc) => pc,
124                 Err(e) => {
125                     return Err(io::Error::new(
126                         io::ErrorKind::Other,
127                         format!("Failed to create PollContext: {}", e),
128                     ));
129                 }
130             };
131         let events = {
132             let result = match timeout {
133                 None => poll_ctx.wait(),
134                 Some(duration) => poll_ctx.wait_timeout(duration),
135             };
136             match result {
137                 Ok(v) => v,
138                 Err(e) => {
139                     return Err(io::Error::new(
140                         io::ErrorKind::Other,
141                         format!("Failed to poll: {:?}", e),
142                     ));
143                 }
144             }
145         };
146 
147         // Check the first readable message
148         let tokens: Vec<Token> = events.iter_readable().map(|e| e.token()).collect();
149         match tokens.get(0) {
150             None => Ok(None),
151             Some(&Token::AudioMsg) => {
152                 let raw_msg: audio_message = self.read_from_socket()?;
153                 Ok(Some(AudioMessage::from(raw_msg)))
154             }
155         }
156     }
157 
158     /// Sends raw audio message with given AudioMessage enum.
159     ///
160     /// # Arguments
161     /// * `msg` - enum AudioMessage, which could be `Success` with message id
162     /// and frames or `Error` with error code.
163     ///
164     /// # Errors
165     /// Returns error if `libc::write` fails.
send_audio_message(&mut self, msg: AudioMessage) -> io::Result<()>166     fn send_audio_message(&mut self, msg: AudioMessage) -> io::Result<()> {
167         let msg: audio_message = msg.into();
168         let rc = self.socket.write(msg.as_slice())?;
169         if rc < mem::size_of::<audio_message>() {
170             Err(io::Error::new(io::ErrorKind::Other, "Sent truncated data."))
171         } else {
172             Ok(())
173         }
174     }
175 
176     /// Sends the data ready message with written frame count.
177     ///
178     /// # Arguments
179     /// * `frames` - An `u32` indicating the written frame count.
data_ready(&mut self, frames: u32) -> io::Result<()>180     pub fn data_ready(&mut self, frames: u32) -> io::Result<()> {
181         self.send_audio_message(AudioMessage::Success {
182             id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_READY,
183             frames,
184         })
185     }
186 
187     /// Sends the capture ready message with read frame count.
188     ///
189     /// # Arguments
190     ///
191     /// * `frames` - An `u32` indicating the number of read frames.
capture_ready(&mut self, frames: u32) -> io::Result<()>192     pub fn capture_ready(&mut self, frames: u32) -> io::Result<()> {
193         self.send_audio_message(AudioMessage::Success {
194             id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_CAPTURED,
195             frames,
196         })
197     }
198 }
199 
200 impl AsRawFd for AudioSocket {
as_raw_fd(&self) -> RawFd201     fn as_raw_fd(&self) -> RawFd {
202         self.socket.as_raw_fd()
203     }
204 }
205 
206 #[cfg(test)]
207 mod tests {
208     use super::*;
209 
210     // PartialEq for comparing AudioMessage in tests
211     impl PartialEq for AudioMessage {
eq(&self, other: &Self) -> bool212         fn eq(&self, other: &Self) -> bool {
213             match (self, other) {
214                 (
215                     AudioMessage::Success { id, frames },
216                     AudioMessage::Success {
217                         id: other_id,
218                         frames: other_frames,
219                     },
220                 ) => id == other_id && frames == other_frames,
221                 (AudioMessage::Error(err), AudioMessage::Error(other_err)) => err == other_err,
222                 _ => false,
223             }
224         }
225     }
226 
init_audio_socket_pair() -> (AudioSocket, AudioSocket)227     fn init_audio_socket_pair() -> (AudioSocket, AudioSocket) {
228         let (sock1, sock2) = UnixStream::pair().unwrap();
229         let sender = AudioSocket::new(sock1);
230         let receiver = AudioSocket::new(sock2);
231         (sender, receiver)
232     }
233 
234     #[test]
audio_socket_send_and_recv_audio_message()235     fn audio_socket_send_and_recv_audio_message() {
236         let (mut sender, mut receiver) = init_audio_socket_pair();
237         let message_succ = AudioMessage::Success {
238             id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA,
239             frames: 0,
240         };
241         sender.send_audio_message(message_succ).unwrap();
242         let res = receiver.read_audio_message().unwrap();
243         assert_eq!(
244             res,
245             AudioMessage::Success {
246                 id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA,
247                 frames: 0
248             }
249         );
250 
251         let message_err = AudioMessage::Error(123);
252         sender.send_audio_message(message_err).unwrap();
253         let res = receiver.read_audio_message().unwrap();
254         assert_eq!(res, AudioMessage::Error(123));
255     }
256 
257     #[test]
audio_socket_data_ready_send_and_recv()258     fn audio_socket_data_ready_send_and_recv() {
259         let (sock1, sock2) = UnixStream::pair().unwrap();
260         let mut audio_socket_send = AudioSocket::new(sock1);
261         let mut audio_socket_recv = AudioSocket::new(sock2);
262         audio_socket_send.data_ready(256).unwrap();
263 
264         // Test receiving by using raw audio_message since CRAS audio server use this.
265         let audio_msg: audio_message = audio_socket_recv.read_from_socket().unwrap();
266         let ref_audio_msg = audio_message {
267             id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_READY,
268             error: 0,
269             frames: 256,
270         };
271         // Use brace to copy unaligned data locally
272         assert_eq!({ audio_msg.id }, { ref_audio_msg.id });
273         assert_eq!({ audio_msg.error }, { ref_audio_msg.error });
274         assert_eq!({ audio_msg.frames }, { ref_audio_msg.frames });
275     }
276 
277     #[test]
audio_socket_capture_ready()278     fn audio_socket_capture_ready() {
279         let (sock1, sock2) = UnixStream::pair().unwrap();
280         let mut audio_socket_send = AudioSocket::new(sock1);
281         let mut audio_socket_recv = AudioSocket::new(sock2);
282         audio_socket_send
283             .capture_ready(256)
284             .expect("Failed to send capture ready message.");
285 
286         // Test receiving by using raw audio_message since CRAS audio server use this.
287         let audio_msg: audio_message = audio_socket_recv
288             .read_from_socket()
289             .expect("Failed to read audio message from AudioSocket.");
290         let ref_audio_msg = audio_message {
291             id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_CAPTURED,
292             error: 0,
293             frames: 256,
294         };
295         // Use brace to copy unaligned data locally
296         assert_eq!({ audio_msg.id }, { ref_audio_msg.id });
297         assert_eq!({ audio_msg.error }, { ref_audio_msg.error });
298         assert_eq!({ audio_msg.frames }, { ref_audio_msg.frames });
299     }
300 
301     #[test]
audio_socket_send_when_broken_pipe()302     fn audio_socket_send_when_broken_pipe() {
303         let sock1 = {
304             let (sock1, _) = UnixStream::pair().unwrap();
305             sock1
306         };
307         let mut audio_socket = AudioSocket::new(sock1);
308         let res = audio_socket.data_ready(256);
309         //Broken pipe
310         assert_eq!(
311             res.expect_err("Result should be an error.").kind(),
312             io::Error::from_raw_os_error(32).kind(),
313             "Error should be broken pipe.",
314         );
315     }
316 }
317