• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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