• 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::cmp::min;
5 use std::io;
6 use std::marker::PhantomData;
7 use std::{error, fmt};
8 
9 use audio_streams::{
10     capture::{CaptureBuffer, CaptureBufferStream},
11     BoxError, BufferDrop, PlaybackBuffer, PlaybackBufferStream,
12 };
13 use cras_sys::gen::{snd_pcm_format_t, CRAS_AUDIO_MESSAGE_ID, CRAS_STREAM_DIRECTION};
14 use sys_util::error;
15 
16 use crate::audio_socket::{AudioMessage, AudioSocket};
17 use crate::cras_server_socket::CrasServerSocket;
18 use crate::cras_shm::*;
19 
20 #[derive(Debug)]
21 pub enum Error {
22     IoError(io::Error),
23     MessageTypeError,
24 }
25 
26 impl error::Error for Error {}
27 
28 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result29     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30         match self {
31             Error::IoError(ref err) => err.fmt(f),
32             Error::MessageTypeError => write!(f, "Message type error"),
33         }
34     }
35 }
36 
37 impl From<io::Error> for Error {
from(io_err: io::Error) -> Error38     fn from(io_err: io::Error) -> Error {
39         Error::IoError(io_err)
40     }
41 }
42 
43 /// A trait controls the state of `CrasAudioHeader` and
44 /// interacts with server's audio thread through `AudioSocket`.
45 pub trait CrasStreamData<'a>: Send {
46     // Creates `CrasStreamData` with only `AudioSocket`.
new(audio_sock: AudioSocket, header: CrasAudioHeader<'a>) -> Self47     fn new(audio_sock: AudioSocket, header: CrasAudioHeader<'a>) -> Self;
header_mut(&mut self) -> &mut CrasAudioHeader<'a>48     fn header_mut(&mut self) -> &mut CrasAudioHeader<'a>;
audio_sock_mut(&mut self) -> &mut AudioSocket49     fn audio_sock_mut(&mut self) -> &mut AudioSocket;
50 }
51 
52 /// `CrasStreamData` implementation for `PlaybackBufferStream`.
53 pub struct CrasPlaybackData<'a> {
54     audio_sock: AudioSocket,
55     header: CrasAudioHeader<'a>,
56 }
57 
58 impl<'a> CrasStreamData<'a> for CrasPlaybackData<'a> {
new(audio_sock: AudioSocket, header: CrasAudioHeader<'a>) -> Self59     fn new(audio_sock: AudioSocket, header: CrasAudioHeader<'a>) -> Self {
60         Self { audio_sock, header }
61     }
62 
header_mut(&mut self) -> &mut CrasAudioHeader<'a>63     fn header_mut(&mut self) -> &mut CrasAudioHeader<'a> {
64         &mut self.header
65     }
66 
audio_sock_mut(&mut self) -> &mut AudioSocket67     fn audio_sock_mut(&mut self) -> &mut AudioSocket {
68         &mut self.audio_sock
69     }
70 }
71 
72 impl<'a> BufferDrop for CrasPlaybackData<'a> {
trigger(&mut self, nframes: usize)73     fn trigger(&mut self, nframes: usize) {
74         let log_err = |e| error!("BufferDrop error: {}", e);
75         if let Err(e) = self.header.commit_written_frames(nframes as u32) {
76             log_err(e);
77         }
78         if let Err(e) = self.audio_sock.data_ready(nframes as u32) {
79             log_err(e);
80         }
81     }
82 }
83 
84 /// `CrasStreamData` implementation for `CaptureBufferStream`.
85 pub struct CrasCaptureData<'a> {
86     audio_sock: AudioSocket,
87     header: CrasAudioHeader<'a>,
88 }
89 
90 impl<'a> CrasStreamData<'a> for CrasCaptureData<'a> {
new(audio_sock: AudioSocket, header: CrasAudioHeader<'a>) -> Self91     fn new(audio_sock: AudioSocket, header: CrasAudioHeader<'a>) -> Self {
92         Self { audio_sock, header }
93     }
94 
header_mut(&mut self) -> &mut CrasAudioHeader<'a>95     fn header_mut(&mut self) -> &mut CrasAudioHeader<'a> {
96         &mut self.header
97     }
98 
audio_sock_mut(&mut self) -> &mut AudioSocket99     fn audio_sock_mut(&mut self) -> &mut AudioSocket {
100         &mut self.audio_sock
101     }
102 }
103 
104 impl<'a> BufferDrop for CrasCaptureData<'a> {
trigger(&mut self, nframes: usize)105     fn trigger(&mut self, nframes: usize) {
106         let log_err = |e| error!("BufferDrop error: {}", e);
107         if let Err(e) = self.header.commit_read_frames(nframes as u32) {
108             log_err(e);
109         }
110         if let Err(e) = self.audio_sock.capture_ready(nframes as u32) {
111             log_err(e);
112         }
113     }
114 }
115 
116 #[allow(dead_code)]
117 pub struct CrasStream<'a, T: CrasStreamData<'a> + BufferDrop> {
118     stream_id: u32,
119     server_socket: CrasServerSocket,
120     block_size: u32,
121     direction: CRAS_STREAM_DIRECTION,
122     rate: u32,
123     num_channels: usize,
124     format: snd_pcm_format_t,
125     /// A structure for stream to interact with server audio thread.
126     controls: T,
127     /// The `PhantomData` is used by `controls: T`
128     phantom: PhantomData<CrasAudioHeader<'a>>,
129     audio_buffer: CrasAudioBuffer,
130 }
131 
132 impl<'a, T: CrasStreamData<'a> + BufferDrop> CrasStream<'a, T> {
133     /// Creates a CrasStream by given arguments.
134     ///
135     /// # Returns
136     /// `CrasStream` - CRAS client stream.
137     #[allow(clippy::too_many_arguments)]
try_new( stream_id: u32, server_socket: CrasServerSocket, block_size: u32, direction: CRAS_STREAM_DIRECTION, rate: u32, num_channels: usize, format: snd_pcm_format_t, audio_sock: AudioSocket, header_fd: CrasAudioShmHeaderFd, samples_fd: CrasShmFd, ) -> Result<Self, Error>138     pub fn try_new(
139         stream_id: u32,
140         server_socket: CrasServerSocket,
141         block_size: u32,
142         direction: CRAS_STREAM_DIRECTION,
143         rate: u32,
144         num_channels: usize,
145         format: snd_pcm_format_t,
146         audio_sock: AudioSocket,
147         header_fd: CrasAudioShmHeaderFd,
148         samples_fd: CrasShmFd,
149     ) -> Result<Self, Error> {
150         let (header, audio_buffer) = create_header_and_buffers(header_fd, samples_fd)?;
151 
152         Ok(Self {
153             stream_id,
154             server_socket,
155             block_size,
156             direction,
157             rate,
158             num_channels,
159             format,
160             controls: T::new(audio_sock, header),
161             phantom: PhantomData,
162             audio_buffer,
163         })
164     }
165 
wait_request_data(&mut self) -> Result<(), Error>166     fn wait_request_data(&mut self) -> Result<(), Error> {
167         match self.controls.audio_sock_mut().read_audio_message()? {
168             AudioMessage::Success {
169                 id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_REQUEST_DATA,
170                 ..
171             } => Ok(()),
172             _ => Err(Error::MessageTypeError),
173         }
174     }
175 
wait_data_ready(&mut self) -> Result<u32, Error>176     fn wait_data_ready(&mut self) -> Result<u32, Error> {
177         match self.controls.audio_sock_mut().read_audio_message()? {
178             AudioMessage::Success {
179                 id: CRAS_AUDIO_MESSAGE_ID::AUDIO_MESSAGE_DATA_READY,
180                 frames,
181             } => Ok(frames),
182             _ => Err(Error::MessageTypeError),
183         }
184     }
185 }
186 
187 impl<'a, T: CrasStreamData<'a> + BufferDrop> Drop for CrasStream<'a, T> {
188     /// A blocking drop function, sends the disconnect message to `CrasClient` and waits for
189     /// the return message.
190     /// Logs an error message to stderr if the method fails.
drop(&mut self)191     fn drop(&mut self) {
192         if let Err(e) = self.server_socket.disconnect_stream(self.stream_id) {
193             error!("CrasStream::Drop error: {}", e);
194         }
195     }
196 }
197 
198 impl<'a, T: CrasStreamData<'a> + BufferDrop> PlaybackBufferStream for CrasStream<'a, T> {
next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError>199     fn next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError> {
200         // Wait for request audio message
201         self.wait_request_data()?;
202         let header = self.controls.header_mut();
203         let frame_size = header.get_frame_size();
204         let (offset, len) = header.get_write_offset_and_len()?;
205         let buf = &mut self.audio_buffer.get_buffer()[offset..offset + len];
206 
207         PlaybackBuffer::new(frame_size, buf, &mut self.controls).map_err(Box::from)
208     }
209 }
210 
211 impl<'a, T: CrasStreamData<'a> + BufferDrop> CaptureBufferStream for CrasStream<'a, T> {
next_capture_buffer(&mut self) -> Result<CaptureBuffer, BoxError>212     fn next_capture_buffer(&mut self) -> Result<CaptureBuffer, BoxError> {
213         // Wait for data ready message
214         let frames = self.wait_data_ready()?;
215         let header = self.controls.header_mut();
216         let frame_size = header.get_frame_size();
217         let shm_frames = header.get_readable_frames()?;
218         let len = min(shm_frames, frames as usize) * frame_size;
219         let offset = header.get_read_buffer_offset()?;
220         let buf = &mut self.audio_buffer.get_buffer()[offset..offset + len];
221 
222         CaptureBuffer::new(frame_size, buf, &mut self.controls).map_err(Box::from)
223     }
224 }
225