1 // Copyright 2020 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 use crate::virtio::snd::constants::*;
6 use crate::virtio::snd::layout::*;
7
8 use base::{
9 error, net::UnixSeqpacket, Error as BaseError, Event, FromRawDescriptor, IntoRawDescriptor,
10 MemoryMapping, MemoryMappingBuilder, MmapError, PollToken, SafeDescriptor, ScmSocket,
11 SharedMemory, WaitContext,
12 };
13 use data_model::{DataInit, VolatileMemory, VolatileMemoryError};
14
15 use std::collections::HashMap;
16 use std::fs::File;
17 use std::io::{Error as IOError, ErrorKind as IOErrorKind, Seek, SeekFrom};
18 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
19 use std::path::Path;
20 use std::sync::mpsc::{channel, Receiver, RecvError, Sender};
21 use std::sync::Arc;
22 use std::thread::JoinHandle;
23
24 use sync::Mutex;
25
26 use thiserror::Error as ThisError;
27
28 pub type Result<T> = std::result::Result<T, Error>;
29
30 #[derive(ThisError, Debug)]
31 pub enum Error {
32 #[error("Failed to connect to VioS server: {0:?}")]
33 ServerConnectionError(IOError),
34 #[error("Failed to communicate with VioS server: {0:?}")]
35 ServerError(BaseError),
36 #[error("Failed to communicate with VioS server: {0:?}")]
37 ServerIOError(IOError),
38 #[error("Failed to get size of tx shared memory: {0}")]
39 FileSizeError(IOError),
40 #[error("Error duplicating file descriptor: {0}")]
41 DupError(BaseError),
42 #[error("Error accessing VioS server's shared memory: {0}")]
43 ServerMmapError(MmapError),
44 #[error("Error accessing guest's shared memory: {0}")]
45 GuestMmapError(MmapError),
46 #[error("Error memory mapping client_shm: {0}")]
47 BaseMmapError(BaseError),
48 #[error("Error accessing volatile memory: {0}")]
49 VolatileMemoryError(VolatileMemoryError),
50 #[error("{0}")]
51 ProtocolError(ProtocolErrorKind),
52 #[error("No PCM streams available")]
53 NoStreamsAvailable,
54 #[error("No stream with id {0}")]
55 InvalidStreamId(u32),
56 #[error("Stream is unexpected state: {0:?}")]
57 UnexpectedState(StreamState),
58 #[error("Invalid operation for stream direction: {0}")]
59 WrongDirection(u8),
60 #[error("Insuficient space for the new buffer in the queue's buffer area")]
61 OutOfSpace,
62 #[error("Unsupported frame rate: {0}")]
63 UnsupportedFrameRate(u32),
64 #[error("Platform not supported")]
65 PlatformNotSupported,
66 #[error("Command failed with status {0}")]
67 CommandFailed(u32),
68 #[error("IO buffer operation failed: status = {0}")]
69 IOBufferError(u32),
70 #[error("Failed to duplicate UnixSeqpacket: {0}")]
71 UnixSeqpacketDupError(IOError),
72 #[error("Sender was dropped without sending buffer status, the recv thread may have exited")]
73 BufferStatusSenderLost(RecvError),
74 #[error("Failed to create Recv event: {0}")]
75 EventCreateError(BaseError),
76 #[error("Failed to dup Recv event: {0}")]
77 EventDupError(BaseError),
78 #[error("Failed to create Recv thread's WaitContext: {0}")]
79 WaitContextCreateError(BaseError),
80 #[error("Error waiting for events")]
81 WaitError(BaseError),
82 }
83
84 #[derive(ThisError, Debug)]
85 pub enum ProtocolErrorKind {
86 #[error("The server sent a config of the wrong size: {0}")]
87 UnexpectedConfigSize(usize),
88 #[error("Received {1} file descriptors from the server, expected {0}")]
89 UnexpectedNumberOfFileDescriptors(usize, usize), // expected, received
90 #[error("Server's version ({0}) doesn't match client's")]
91 VersionMismatch(u32),
92 #[error("Received a msg with an unexpected size: expected {0}, received {1}")]
93 UnexpectedMessageSize(usize, usize), // expected, received
94 }
95
96 /// The client for the VioS backend
97 ///
98 /// Uses a protocol equivalent to virtio-snd over a shared memory file and a unix socket for
99 /// notifications. It's thread safe, it can be encapsulated in an Arc smart pointer and shared
100 /// between threads.
101 pub struct VioSClient {
102 config: VioSConfig,
103 // These mutexes should almost never be held simultaneously. If at some point they have to the
104 // locking order should match the order in which they are declared here.
105 streams: Mutex<Vec<VioSStreamInfo>>,
106 control_socket: Mutex<UnixSeqpacket>,
107 event_socket: Mutex<UnixSeqpacket>,
108 tx: Mutex<IoBufferQueue>,
109 rx: Mutex<IoBufferQueue>,
110 rx_subscribers: Arc<Mutex<HashMap<usize, Sender<(u32, usize)>>>>,
111 recv_running: Arc<Mutex<bool>>,
112 recv_event: Mutex<Event>,
113 recv_thread: Mutex<Option<JoinHandle<Result<()>>>>,
114 }
115
116 impl VioSClient {
117 /// Create a new client given the path to the audio server's socket.
try_new<P: AsRef<Path>>(server: P) -> Result<VioSClient>118 pub fn try_new<P: AsRef<Path>>(server: P) -> Result<VioSClient> {
119 let client_socket =
120 UnixSeqpacket::connect(server).map_err(|e| Error::ServerConnectionError(e))?;
121 let mut config: VioSConfig = Default::default();
122 let mut fds: Vec<RawFd> = Vec::new();
123 const NUM_FDS: usize = 5;
124 fds.resize(NUM_FDS, 0);
125 let (recv_size, fd_count) = client_socket
126 .recv_with_fds(config.as_mut_slice(), &mut fds)
127 .map_err(|e| Error::ServerError(e))?;
128
129 // Resize the vector to the actual number of file descriptors received and wrap them in
130 // SafeDescriptors to prevent leaks
131 fds.resize(fd_count, -1);
132 let mut safe_fds: Vec<SafeDescriptor> = fds
133 .into_iter()
134 .map(|fd| unsafe {
135 // safe because the SafeDescriptor object completely assumes ownership of the fd.
136 SafeDescriptor::from_raw_descriptor(fd)
137 })
138 .collect();
139
140 if recv_size != std::mem::size_of::<VioSConfig>() {
141 return Err(Error::ProtocolError(
142 ProtocolErrorKind::UnexpectedConfigSize(recv_size),
143 ));
144 }
145
146 if config.version != VIOS_VERSION {
147 return Err(Error::ProtocolError(ProtocolErrorKind::VersionMismatch(
148 config.version,
149 )));
150 }
151
152 fn pop<T: FromRawFd>(
153 safe_fds: &mut Vec<SafeDescriptor>,
154 expected: usize,
155 received: usize,
156 ) -> Result<T> {
157 unsafe {
158 // Safe because we transfer ownership from the SafeDescriptor to T
159 Ok(T::from_raw_fd(
160 safe_fds
161 .pop()
162 .ok_or(Error::ProtocolError(
163 ProtocolErrorKind::UnexpectedNumberOfFileDescriptors(
164 expected, received,
165 ),
166 ))?
167 .into_raw_descriptor(),
168 ))
169 }
170 }
171
172 let rx_shm_file = pop::<File>(&mut safe_fds, NUM_FDS, fd_count)?;
173 let tx_shm_file = pop::<File>(&mut safe_fds, NUM_FDS, fd_count)?;
174 let rx_socket = pop::<UnixSeqpacket>(&mut safe_fds, NUM_FDS, fd_count)?;
175 let tx_socket = pop::<UnixSeqpacket>(&mut safe_fds, NUM_FDS, fd_count)?;
176 let event_socket = pop::<UnixSeqpacket>(&mut safe_fds, NUM_FDS, fd_count)?;
177
178 if !safe_fds.is_empty() {
179 return Err(Error::ProtocolError(
180 ProtocolErrorKind::UnexpectedNumberOfFileDescriptors(NUM_FDS, fd_count),
181 ));
182 }
183
184 let rx_subscribers: Arc<Mutex<HashMap<usize, Sender<(u32, usize)>>>> =
185 Arc::new(Mutex::new(HashMap::new()));
186 let recv_running = Arc::new(Mutex::new(true));
187 let recv_event = Event::new().map_err(|e| Error::EventCreateError(e))?;
188
189 let mut client = VioSClient {
190 config,
191 streams: Mutex::new(Vec::new()),
192 control_socket: Mutex::new(client_socket),
193 event_socket: Mutex::new(event_socket),
194 tx: Mutex::new(IoBufferQueue::new(tx_socket, tx_shm_file)?),
195 rx: Mutex::new(IoBufferQueue::new(rx_socket, rx_shm_file)?),
196 rx_subscribers,
197 recv_running,
198 recv_event: Mutex::new(recv_event),
199 recv_thread: Mutex::new(None),
200 };
201 client.request_and_cache_streams_info()?;
202 Ok(client)
203 }
204
ensure_bg_thread_started(&self) -> Result<()>205 pub fn ensure_bg_thread_started(&self) -> Result<()> {
206 if self.recv_thread.lock().is_some() {
207 return Ok(());
208 }
209 let event_socket = self
210 .recv_event
211 .lock()
212 .try_clone()
213 .map_err(|e| Error::EventDupError(e))?;
214 let rx_socket = self
215 .rx
216 .lock()
217 .socket
218 .try_clone()
219 .map_err(|e| Error::UnixSeqpacketDupError(e))?;
220 let mut opt = self.recv_thread.lock();
221 // The lock on recv_thread was released above to avoid holding more than one lock at a time
222 // while duplicating the fds. So we have to check again the condition.
223 if opt.is_none() {
224 *opt = Some(spawn_recv_thread(
225 self.rx_subscribers.clone(),
226 event_socket,
227 self.recv_running.clone(),
228 rx_socket,
229 ));
230 }
231 Ok(())
232 }
233
234 /// Gets an unused stream id of the specified direction. `direction` must be one of
235 /// VIRTIO_SND_D_INPUT OR VIRTIO_SND_D_OUTPUT.
get_unused_stream_id(&self, direction: u8) -> Option<u32>236 pub fn get_unused_stream_id(&self, direction: u8) -> Option<u32> {
237 self.streams
238 .lock()
239 .iter()
240 .filter(|s| s.state == StreamState::Available && s.direction == direction as u8)
241 .map(|s| s.id)
242 .next()
243 }
244
245 /// Configures a stream with the given parameters.
set_stream_parameters(&self, stream_id: u32, params: VioSStreamParams) -> Result<()>246 pub fn set_stream_parameters(&self, stream_id: u32, params: VioSStreamParams) -> Result<()> {
247 self.validate_stream_id(
248 stream_id,
249 &[StreamState::Available, StreamState::Acquired],
250 None,
251 )?;
252 let raw_params: virtio_snd_pcm_set_params = (stream_id, params).into();
253 self.send_cmd(raw_params)?;
254 self.streams.lock()[stream_id as usize].state = StreamState::Acquired;
255 Ok(())
256 }
257
258 /// Send the PREPARE_STREAM command to the server.
prepare_stream(&self, stream_id: u32) -> Result<()>259 pub fn prepare_stream(&self, stream_id: u32) -> Result<()> {
260 self.common_stream_op(
261 stream_id,
262 &[StreamState::Available, StreamState::Acquired],
263 StreamState::Acquired,
264 STREAM_PREPARE,
265 )
266 }
267
268 /// Send the RELEASE_STREAM command to the server.
release_stream(&self, stream_id: u32) -> Result<()>269 pub fn release_stream(&self, stream_id: u32) -> Result<()> {
270 self.common_stream_op(
271 stream_id,
272 &[StreamState::Acquired],
273 StreamState::Available,
274 STREAM_RELEASE,
275 )
276 }
277
278 /// Send the START_STREAM command to the server.
start_stream(&self, stream_id: u32) -> Result<()>279 pub fn start_stream(&self, stream_id: u32) -> Result<()> {
280 self.common_stream_op(
281 stream_id,
282 &[StreamState::Acquired],
283 StreamState::Active,
284 STREAM_START,
285 )
286 }
287
288 /// Send the STOP_STREAM command to the server.
stop_stream(&self, stream_id: u32) -> Result<()>289 pub fn stop_stream(&self, stream_id: u32) -> Result<()> {
290 self.common_stream_op(
291 stream_id,
292 &[StreamState::Active],
293 StreamState::Acquired,
294 STREAM_STOP,
295 )
296 }
297
298 /// Send audio frames to the server. The audio data is taken from a shared memory resource.
inject_audio_data( &self, stream_id: u32, buffer: &mut SharedMemory, src_offset: usize, size: usize, ) -> Result<()>299 pub fn inject_audio_data(
300 &self,
301 stream_id: u32,
302 buffer: &mut SharedMemory,
303 src_offset: usize,
304 size: usize,
305 ) -> Result<()> {
306 self.validate_stream_id(stream_id, &[StreamState::Active], Some(VIRTIO_SND_D_OUTPUT))?;
307 let mut tx_lock = self.tx.lock();
308 let tx = &mut *tx_lock;
309 let dst_offset = tx.push_buffer(buffer, src_offset, size)?;
310 let msg = IoTransferMsg::new(stream_id, dst_offset, size);
311 seq_socket_send(&tx.socket, msg)
312 }
313
request_audio_data( &self, stream_id: u32, buffer: &mut SharedMemory, dst_offset: usize, size: usize, ) -> Result<usize>314 pub fn request_audio_data(
315 &self,
316 stream_id: u32,
317 buffer: &mut SharedMemory,
318 dst_offset: usize,
319 size: usize,
320 ) -> Result<usize> {
321 self.validate_stream_id(stream_id, &[StreamState::Active], Some(VIRTIO_SND_D_INPUT))?;
322 let (src_offset, status_promise) = {
323 let mut rx_lock = self.rx.lock();
324 let rx = &mut *rx_lock;
325 let src_offset = rx.allocate_buffer(size)?;
326 // Register to receive the status before sending the buffer to the server
327 let (sender, receiver): (Sender<(u32, usize)>, Receiver<(u32, usize)>) = channel();
328 // It's OK to acquire rx_subscriber's lock after rx_lock
329 self.rx_subscribers.lock().insert(src_offset, sender);
330 let msg = IoTransferMsg::new(stream_id, src_offset, size);
331 seq_socket_send(&rx.socket, msg)?;
332 (src_offset, receiver)
333 };
334 // Make sure no mutexes are held while awaiting for the buffer to be written to
335 let recv_size = await_status(status_promise)?;
336 {
337 let mut rx_lock = self.rx.lock();
338 rx_lock
339 .pop_buffer(buffer, dst_offset, recv_size, src_offset)
340 .map(|()| recv_size)
341 }
342 }
343
344 /// Get a list of file descriptors used by the implementation.
keep_fds(&self) -> Vec<RawFd>345 pub fn keep_fds(&self) -> Vec<RawFd> {
346 let control_fd = self.control_socket.lock().as_raw_fd();
347 let event_fd = self.event_socket.lock().as_raw_fd();
348 let (tx_socket_fd, tx_shm_fd) = {
349 let lock = self.tx.lock();
350 (lock.socket.as_raw_fd(), lock.file.as_raw_fd())
351 };
352 let (rx_socket_fd, rx_shm_fd) = {
353 let lock = self.rx.lock();
354 (lock.socket.as_raw_fd(), lock.file.as_raw_fd())
355 };
356 vec![
357 control_fd,
358 event_fd,
359 tx_socket_fd,
360 tx_shm_fd,
361 rx_socket_fd,
362 rx_shm_fd,
363 ]
364 }
365
send_cmd<T: DataInit>(&self, data: T) -> Result<()>366 fn send_cmd<T: DataInit>(&self, data: T) -> Result<()> {
367 let mut control_socket_lock = self.control_socket.lock();
368 seq_socket_send(&mut *control_socket_lock, data)?;
369 recv_cmd_status(&mut *control_socket_lock)
370 }
371
validate_stream_id( &self, stream_id: u32, permitted_states: &[StreamState], direction: Option<u8>, ) -> Result<()>372 fn validate_stream_id(
373 &self,
374 stream_id: u32,
375 permitted_states: &[StreamState],
376 direction: Option<u8>,
377 ) -> Result<()> {
378 let streams_lock = self.streams.lock();
379 let stream_idx = stream_id as usize;
380 if stream_idx >= streams_lock.len() {
381 return Err(Error::InvalidStreamId(stream_id));
382 }
383 if !permitted_states.contains(&streams_lock[stream_idx].state) {
384 return Err(Error::UnexpectedState(streams_lock[stream_idx].state));
385 }
386 match direction {
387 None => Ok(()),
388 Some(d) => {
389 if d == streams_lock[stream_idx].direction {
390 Ok(())
391 } else {
392 Err(Error::WrongDirection(streams_lock[stream_idx].direction))
393 }
394 }
395 }
396 }
397
common_stream_op( &self, stream_id: u32, expected_states: &[StreamState], new_state: StreamState, op: u32, ) -> Result<()>398 fn common_stream_op(
399 &self,
400 stream_id: u32,
401 expected_states: &[StreamState],
402 new_state: StreamState,
403 op: u32,
404 ) -> Result<()> {
405 self.validate_stream_id(stream_id, expected_states, None)?;
406 let msg = virtio_snd_pcm_hdr {
407 hdr: virtio_snd_hdr { code: op.into() },
408 stream_id: stream_id.into(),
409 };
410 self.send_cmd(msg)?;
411 self.streams.lock()[stream_id as usize].state = new_state;
412 Ok(())
413 }
414
request_and_cache_streams_info(&mut self) -> Result<()>415 fn request_and_cache_streams_info(&mut self) -> Result<()> {
416 let num_streams = self.config.streams as usize;
417 let info_size = std::mem::size_of::<virtio_snd_pcm_info>();
418 let req = virtio_snd_query_info {
419 hdr: virtio_snd_hdr {
420 code: STREAM_INFO.into(),
421 },
422 start_id: 0u32.into(),
423 count: (num_streams as u32).into(),
424 size: (std::mem::size_of::<virtio_snd_query_info>() as u32).into(),
425 };
426 self.send_cmd(req)?;
427 let control_socket_lock = self.control_socket.lock();
428 let info_vec = control_socket_lock
429 .recv_as_vec()
430 .map_err(|e| Error::ServerIOError(e))?;
431 if info_vec.len() != num_streams * info_size {
432 return Err(Error::ProtocolError(
433 ProtocolErrorKind::UnexpectedMessageSize(num_streams * info_size, info_vec.len()),
434 ));
435 }
436 self.streams = Mutex::new(
437 info_vec
438 .chunks(info_size)
439 .enumerate()
440 .map(|(id, info_buffer)| {
441 // unwrap is safe because we checked the size of the vector
442 let virtio_stream_info = virtio_snd_pcm_info::from_slice(&info_buffer).unwrap();
443 VioSStreamInfo::new(id as u32, &virtio_stream_info)
444 })
445 .collect(),
446 );
447 Ok(())
448 }
449 }
450
451 impl Drop for VioSClient {
drop(&mut self)452 fn drop(&mut self) {
453 // Stop the recv thread
454 *self.recv_running.lock() = false;
455 if let Err(e) = self.recv_event.lock().write(1u64) {
456 error!("Failed to notify recv thread: {:?}", e);
457 }
458 if let Some(handle) = self.recv_thread.lock().take() {
459 match handle.join() {
460 Ok(r) => {
461 if let Err(e) = r {
462 error!("Error detected on Recv Thread: {}", e);
463 }
464 }
465 Err(e) => error!("Recv thread panicked: {:?}", e),
466 };
467 }
468 }
469 }
470
471 #[derive(PollToken)]
472 enum Token {
473 Notification,
474 RxBufferMsg,
475 }
476
spawn_recv_thread( rx_subscribers: Arc<Mutex<HashMap<usize, Sender<(u32, usize)>>>>, event: Event, running: Arc<Mutex<bool>>, rx_socket: UnixSeqpacket, ) -> JoinHandle<Result<()>>477 fn spawn_recv_thread(
478 rx_subscribers: Arc<Mutex<HashMap<usize, Sender<(u32, usize)>>>>,
479 event: Event,
480 running: Arc<Mutex<bool>>,
481 rx_socket: UnixSeqpacket,
482 ) -> JoinHandle<Result<()>> {
483 std::thread::spawn(move || {
484 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
485 (&rx_socket, Token::RxBufferMsg),
486 (&event, Token::Notification),
487 ])
488 .map_err(|e| Error::WaitContextCreateError(e))?;
489 while *running.lock() {
490 let events = wait_ctx.wait().map_err(|e| Error::WaitError(e))?;
491 for evt in events {
492 match evt.token {
493 Token::RxBufferMsg => {
494 let mut msg: IoStatusMsg = Default::default();
495 let size = rx_socket
496 .recv(msg.as_mut_slice())
497 .map_err(|e| Error::ServerIOError(e))?;
498 if size != std::mem::size_of::<IoStatusMsg>() {
499 return Err(Error::ProtocolError(
500 ProtocolErrorKind::UnexpectedMessageSize(
501 std::mem::size_of::<IoStatusMsg>(),
502 size,
503 ),
504 ));
505 }
506 let mut status = msg.status.status.into();
507 if status == u32::MAX {
508 // Anyone waiting for this would continue to wait for as long as status is
509 // u32::MAX
510 status -= 1;
511 }
512 let offset = msg.buffer_offset as usize;
513 let consumed_len = msg.consumed_len as usize;
514 // Acquire and immediately release the mutex protecting the hashmap
515 let promise_opt = rx_subscribers.lock().remove(&offset);
516 match promise_opt {
517 None => error!(
518 "Received an unexpected buffer status message: {}. This is a BUG!!",
519 offset
520 ),
521 Some(sender) => {
522 if let Err(e) = sender.send((status, consumed_len)) {
523 error!("Failed to notify waiting thread: {:?}", e);
524 }
525 }
526 }
527 }
528 Token::Notification => {
529 // Just consume the notification and check for termination on the next
530 // iteration
531 if let Err(e) = event.read() {
532 error!("Failed to consume notification from recv thread: {:?}", e);
533 }
534 }
535 }
536 }
537 }
538 Ok(())
539 })
540 }
541
await_status(promise: Receiver<(u32, usize)>) -> Result<usize>542 fn await_status(promise: Receiver<(u32, usize)>) -> Result<usize> {
543 let (status, consumed_len) = promise
544 .recv()
545 .map_err(|e| Error::BufferStatusSenderLost(e))?;
546 if status == VIRTIO_SND_S_OK {
547 Ok(consumed_len)
548 } else {
549 Err(Error::IOBufferError(status))
550 }
551 }
552
553 struct IoBufferQueue {
554 socket: UnixSeqpacket,
555 file: File,
556 mmap: MemoryMapping,
557 size: usize,
558 next: usize,
559 }
560
561 impl IoBufferQueue {
new(socket: UnixSeqpacket, mut file: File) -> Result<IoBufferQueue>562 fn new(socket: UnixSeqpacket, mut file: File) -> Result<IoBufferQueue> {
563 let size = file
564 .seek(SeekFrom::End(0))
565 .map_err(|e| Error::FileSizeError(e))? as usize;
566
567 let mmap = MemoryMappingBuilder::new(size)
568 .from_file(&file)
569 .build()
570 .map_err(|e| Error::ServerMmapError(e))?;
571
572 Ok(IoBufferQueue {
573 socket,
574 file,
575 mmap,
576 size,
577 next: 0,
578 })
579 }
580
allocate_buffer(&mut self, size: usize) -> Result<usize>581 fn allocate_buffer(&mut self, size: usize) -> Result<usize> {
582 if size > self.size {
583 return Err(Error::OutOfSpace);
584 }
585 let offset = if size > self.size - self.next {
586 // Can't fit the new buffer at the end of the area, so put it at the beginning
587 0
588 } else {
589 self.next
590 };
591 self.next = offset + size;
592 Ok(offset)
593 }
594
push_buffer(&mut self, src: &mut SharedMemory, offset: usize, size: usize) -> Result<usize>595 fn push_buffer(&mut self, src: &mut SharedMemory, offset: usize, size: usize) -> Result<usize> {
596 let shm_offset = self.allocate_buffer(size)?;
597 let (src_mmap, mmap_offset) = mmap_buffer(src, offset, size)?;
598 let src_slice = src_mmap
599 .get_slice(mmap_offset, size)
600 .map_err(|e| Error::VolatileMemoryError(e))?;
601 let dst_slice = self
602 .mmap
603 .get_slice(shm_offset, size)
604 .map_err(|e| Error::VolatileMemoryError(e))?;
605 src_slice.copy_to_volatile_slice(dst_slice);
606 Ok(shm_offset)
607 }
608
pop_buffer( &mut self, dst: &mut SharedMemory, dst_offset: usize, size: usize, src_offset: usize, ) -> Result<()>609 fn pop_buffer(
610 &mut self,
611 dst: &mut SharedMemory,
612 dst_offset: usize,
613 size: usize,
614 src_offset: usize,
615 ) -> Result<()> {
616 let (dst_mmap, mmap_offset) = mmap_buffer(dst, dst_offset, size)?;
617 let dst_slice = dst_mmap
618 .get_slice(mmap_offset, size)
619 .map_err(|e| Error::VolatileMemoryError(e))?;
620 let src_slice = self
621 .mmap
622 .get_slice(src_offset, size)
623 .map_err(|e| Error::VolatileMemoryError(e))?;
624 src_slice.copy_to_volatile_slice(dst_slice);
625 Ok(())
626 }
627 }
628
629 /// Description of a stream made available by the server.
630 pub struct VioSStreamInfo {
631 pub id: u32,
632 pub hda_fn_nid: u32,
633 pub features: u32,
634 pub formats: u64,
635 pub rates: u64,
636 pub direction: u8,
637 pub channels_min: u8,
638 pub channels_max: u8,
639 state: StreamState,
640 }
641
642 impl VioSStreamInfo {
new(id: u32, info: &virtio_snd_pcm_info) -> VioSStreamInfo643 fn new(id: u32, info: &virtio_snd_pcm_info) -> VioSStreamInfo {
644 VioSStreamInfo {
645 id,
646 hda_fn_nid: info.hdr.hda_fn_nid.to_native(),
647 features: info.features.to_native(),
648 formats: info.formats.to_native(),
649 rates: info.rates.to_native(),
650 direction: info.direction,
651 channels_min: info.channels_min,
652 channels_max: info.channels_max,
653 state: StreamState::Available,
654 }
655 }
656 }
657
658 #[derive(PartialEq, Debug, Copy, Clone)]
659 pub enum StreamState {
660 Available,
661 Acquired,
662 Active,
663 }
664
665 /// Groups the parameters used to configure a stream prior to using it.
666 pub struct VioSStreamParams {
667 pub buffer_bytes: u32,
668 pub period_bytes: u32,
669 pub features: u32,
670 pub channels: u8,
671 pub format: u8,
672 pub rate: u8,
673 }
674
675 impl Into<virtio_snd_pcm_set_params> for (u32, VioSStreamParams) {
into(self) -> virtio_snd_pcm_set_params676 fn into(self) -> virtio_snd_pcm_set_params {
677 virtio_snd_pcm_set_params {
678 hdr: virtio_snd_pcm_hdr {
679 hdr: virtio_snd_hdr {
680 code: STREAM_SET_PARAMS.into(),
681 },
682 stream_id: self.0.into(),
683 },
684 buffer_bytes: self.1.buffer_bytes.into(),
685 period_bytes: self.1.period_bytes.into(),
686 features: self.1.features.into(),
687 channels: self.1.channels,
688 format: self.1.format,
689 rate: self.1.rate,
690 padding: 0u8,
691 }
692 }
693 }
694
695 /// Memory map a shared memory object to access an audio buffer. The buffer may not be located at an
696 /// offset aligned to page size, so the offset within the mapped region is returned along with the
697 /// MemoryMapping struct.
mmap_buffer( src: &mut SharedMemory, offset: usize, size: usize, ) -> Result<(MemoryMapping, usize)>698 fn mmap_buffer(
699 src: &mut SharedMemory,
700 offset: usize,
701 size: usize,
702 ) -> Result<(MemoryMapping, usize)> {
703 // If the buffer is not aligned to page size a bigger region needs to be mapped.
704 let aligned_offset = offset & !(base::pagesize() - 1);
705 let offset_from_mapping_start = offset - aligned_offset;
706 let extended_size = size + offset_from_mapping_start;
707
708 let mmap = MemoryMappingBuilder::new(extended_size)
709 .offset(aligned_offset as u64)
710 .from_shared_memory(src)
711 .build()
712 .map_err(|e| Error::GuestMmapError(e))?;
713
714 Ok((mmap, offset_from_mapping_start))
715 }
716
recv_cmd_status(control_socket: &mut UnixSeqpacket) -> Result<()>717 fn recv_cmd_status(control_socket: &mut UnixSeqpacket) -> Result<()> {
718 let mut status: virtio_snd_hdr = Default::default();
719 control_socket
720 .recv(status.as_mut_slice())
721 .map_err(|e| Error::ServerIOError(e))?;
722 if status.code.to_native() == VIRTIO_SND_S_OK {
723 Ok(())
724 } else {
725 Err(Error::CommandFailed(status.code.to_native()))
726 }
727 }
728
seq_socket_send<T: DataInit>(socket: &UnixSeqpacket, data: T) -> Result<()>729 fn seq_socket_send<T: DataInit>(socket: &UnixSeqpacket, data: T) -> Result<()> {
730 loop {
731 let send_res = socket.send(data.as_slice());
732 if let Err(e) = send_res {
733 match e.kind() {
734 // Retry if interrupted
735 IOErrorKind::Interrupted => continue,
736 _ => return Err(Error::ServerIOError(e)),
737 }
738 }
739 // Success
740 break;
741 }
742 Ok(())
743 }
744
745 const VIOS_VERSION: u32 = 1;
746
747 #[repr(C)]
748 #[derive(Copy, Clone, Default)]
749 struct VioSConfig {
750 version: u32,
751 jacks: u32,
752 streams: u32,
753 chmaps: u32,
754 }
755 // Safe because it only has data and has no implicit padding.
756 unsafe impl DataInit for VioSConfig {}
757
758 #[repr(C)]
759 #[derive(Copy, Clone)]
760 struct IoTransferMsg {
761 io_xfer: virtio_snd_pcm_xfer,
762 buffer_offset: u32,
763 buffer_len: u32,
764 }
765 // Safe because it only has data and has no implicit padding.
766 unsafe impl DataInit for IoTransferMsg {}
767
768 impl IoTransferMsg {
new(stream_id: u32, buffer_offset: usize, buffer_len: usize) -> IoTransferMsg769 fn new(stream_id: u32, buffer_offset: usize, buffer_len: usize) -> IoTransferMsg {
770 IoTransferMsg {
771 io_xfer: virtio_snd_pcm_xfer {
772 stream_id: stream_id.into(),
773 },
774 buffer_offset: buffer_offset as u32,
775 buffer_len: buffer_len as u32,
776 }
777 }
778 }
779
780 #[repr(C)]
781 #[derive(Copy, Clone, Default)]
782 struct IoStatusMsg {
783 status: virtio_snd_pcm_status,
784 buffer_offset: u32,
785 consumed_len: u32,
786 }
787 // Safe because it only has data and has no implicit padding.
788 unsafe impl DataInit for IoStatusMsg {}
789