• 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::mem;
6 use std::os::unix::io::{AsRawFd, RawFd};
7 use std::ptr;
8 use std::ptr::NonNull;
9 use std::slice;
10 
11 use libc;
12 
13 use cras_sys::gen::{
14     cras_audio_shm_header, cras_server_state, CRAS_NUM_SHM_BUFFERS, CRAS_SHM_BUFFERS_MASK,
15 };
16 use data_model::VolatileRef;
17 
18 /// A structure wrapping a fd which contains a shared `cras_audio_shm_header`.
19 /// * `shm_fd` - A shared memory fd contains a `cras_audio_shm_header`
20 pub struct CrasAudioShmHeaderFd {
21     fd: CrasShmFd,
22 }
23 
24 impl CrasAudioShmHeaderFd {
25     /// Creates a `CrasAudioShmHeaderFd` by shared memory fd
26     /// # Arguments
27     /// * `fd` - A shared memory file descriptor, which will be owned by the resulting structure and
28     /// the fd will be closed on drop.
29     ///
30     /// # Returns
31     /// A structure wrapping a `CrasShmFd` with the input fd and `size` which equals to
32     /// the size of `cras_audio_shm_header`.
33     ///
34     /// To use this function safely, we need to make sure
35     /// - The input fd is a valid shared memory fd.
36     /// - The input shared memory fd won't be used by others.
37     /// - The shared memory area in the input fd contains a `cras_audio_shm_header`.
new(fd: libc::c_int) -> Self38     pub unsafe fn new(fd: libc::c_int) -> Self {
39         Self {
40             fd: CrasShmFd::new(fd, mem::size_of::<cras_audio_shm_header>()),
41         }
42     }
43 }
44 
45 /// A wrapper for the raw structure `cras_audio_shm_header` with
46 /// size information for the separate audio samples shm area and several
47 /// `VolatileRef` to sub fields for safe access to the header.
48 #[allow(dead_code)]
49 pub struct CrasAudioHeader<'a> {
50     addr: *mut libc::c_void,
51     /// Size of the buffer for samples in CrasAudioBuffer
52     samples_len: usize,
53     used_size: VolatileRef<'a, u32>,
54     frame_size: VolatileRef<'a, u32>,
55     read_buf_idx: VolatileRef<'a, u32>,
56     write_buf_idx: VolatileRef<'a, u32>,
57     read_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
58     write_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
59     buffer_offset: [VolatileRef<'a, u32>; CRAS_NUM_SHM_BUFFERS as usize],
60 }
61 
62 // It is safe to send audio buffers between threads as this struct has exclusive ownership of the
63 // pointers contained in it.
64 unsafe impl<'a> Send for CrasAudioHeader<'a> {}
65 
66 /// An unsafe macro for getting `VolatileRef` for a field from a given NonNull pointer.
67 /// It Supports
68 /// - Nested sub-field
69 /// - Element of an array field
70 ///
71 /// To use this macro safely, we need to
72 /// - Make sure the pointer address is readable and writable for its structure.
73 /// - Make sure all `VolatileRef`s generated from this macro have exclusive ownership for the same
74 /// pointer.
75 #[macro_export]
76 macro_rules! vref_from_addr {
77     ($addr:ident, $($field:ident).*) => {
78         VolatileRef::new(&mut $addr.as_mut().$($field).* as *mut _)
79     };
80 
81     ($addr:ident, $field:ident[$idx:tt]) => {
82         VolatileRef::new(&mut $addr.as_mut().$field[$idx] as *mut _)
83     };
84 }
85 
86 // Generates error when an index is out of range.
index_out_of_range() -> io::Error87 fn index_out_of_range() -> io::Error {
88     io::Error::new(io::ErrorKind::InvalidInput, "Index out of range.")
89 }
90 
91 impl<'a> CrasAudioHeader<'a> {
92     // Creates a `CrasAudioHeader` with given `CrasAudioShmHeaderFd` and `samples_len`
new(header_fd: CrasAudioShmHeaderFd, samples_len: usize) -> io::Result<Self>93     fn new(header_fd: CrasAudioShmHeaderFd, samples_len: usize) -> io::Result<Self> {
94         // Safe because the creator of CrasAudioShmHeaderFd already
95         // ensured that header_fd contains a cras_audio_shm_header.
96         let mmap_addr = unsafe {
97             cras_mmap(
98                 header_fd.fd.size,
99                 libc::PROT_READ | libc::PROT_WRITE,
100                 header_fd.fd.as_raw_fd(),
101             )?
102         };
103 
104         let mut addr = NonNull::new(mmap_addr as *mut cras_audio_shm_header)
105             .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to create header."))?;
106 
107         // Safe because we know that mmap_addr (contained in addr) contains a
108         // cras_audio_shm_header, and the mapped area will be exclusively
109         // owned by this struct.
110         unsafe {
111             Ok(CrasAudioHeader {
112                 addr: addr.as_ptr() as *mut libc::c_void,
113                 samples_len,
114                 used_size: vref_from_addr!(addr, config.used_size),
115                 frame_size: vref_from_addr!(addr, config.frame_bytes),
116                 read_buf_idx: vref_from_addr!(addr, read_buf_idx),
117                 write_buf_idx: vref_from_addr!(addr, write_buf_idx),
118                 read_offset: [
119                     vref_from_addr!(addr, read_offset[0]),
120                     vref_from_addr!(addr, read_offset[1]),
121                 ],
122                 write_offset: [
123                     vref_from_addr!(addr, write_offset[0]),
124                     vref_from_addr!(addr, write_offset[1]),
125                 ],
126                 buffer_offset: [
127                     vref_from_addr!(addr, buffer_offset[0]),
128                     vref_from_addr!(addr, buffer_offset[1]),
129                 ],
130             })
131         }
132     }
133 
134     /// Calculates the length of a buffer with the given offset. This length will
135     /// be `used_size`, unless the offset is closer than `used_size` to the end
136     /// of samples, in which case the length will be as long as possible.
137     ///
138     /// If that buffer length is invalid (too small to hold a frame of audio data),
139     /// then returns an error.
140     /// The returned buffer length will be rounded down to a multiple of `frame_size`.
buffer_len_from_offset(&self, offset: usize) -> io::Result<usize>141     fn buffer_len_from_offset(&self, offset: usize) -> io::Result<usize> {
142         if offset > self.samples_len {
143             return Err(io::Error::new(
144                 io::ErrorKind::InvalidInput,
145                 format!(
146                     "Buffer offset {} exceeds the length of samples area ({}).",
147                     offset, self.samples_len
148                 ),
149             ));
150         }
151 
152         let used_size = self.get_used_size();
153         let frame_size = self.get_frame_size();
154 
155         // We explicitly allow a buffer shorter than used_size, but only
156         // at the end of the samples area.
157         // This is useful if we're playing a file where the number of samples is
158         // not a multiple of used_size (meaning the length of the samples area
159         // won't be either). Then, the last buffer played will be smaller than
160         // used_size.
161         let mut buffer_length = used_size.min(self.samples_len - offset);
162         if buffer_length < frame_size {
163             return Err(io::Error::new(
164                 io::ErrorKind::InvalidInput,
165                 format!(
166                     "Buffer offset {} gives buffer length {} smaller than frame size {}.",
167                     offset, buffer_length, frame_size
168                 ),
169             ));
170         }
171 
172         // Round buffer_length down to a multiple of frame size
173         buffer_length = buffer_length / frame_size * frame_size;
174         Ok(buffer_length)
175     }
176 
177     /// Gets the base of the write buffer and the writable length (rounded to `frame_size`).
178     /// Does not take into account the write offset.
179     ///
180     /// # Returns
181     ///
182     ///  * (`usize`, `usize`) - write buffer base as an offset from the start of
183     ///                         the samples area and buffer length in bytes.
get_write_offset_and_len(&self) -> io::Result<(usize, usize)>184     pub fn get_write_offset_and_len(&self) -> io::Result<(usize, usize)> {
185         let idx = self.get_write_buf_idx() as usize;
186         let offset = self.get_buffer_offset(idx)?;
187         let len = self.buffer_len_from_offset(offset)?;
188 
189         Ok((offset, len))
190     }
191 
192     /// Gets the buffer offset of the read buffer.
193     ///
194     ///  # Returns
195     ///
196     ///  * `usize` - read offset in bytes
get_read_buffer_offset(&self) -> io::Result<usize>197     pub fn get_read_buffer_offset(&self) -> io::Result<usize> {
198         let idx = self.get_read_buf_idx() as usize;
199         self.get_buffer_offset(idx)
200     }
201 
202     /// Gets the offset of a buffer from the start of samples.
203     ///
204     /// # Arguments
205     /// `index` - 0 <= `index` < `CRAS_NUM_SHM_BUFFERS`. The index of the buffer
206     /// for which we want the `buffer_offset`.
207     ///
208     /// # Returns
209     /// * `usize` - buffer offset in bytes
get_buffer_offset(&self, idx: usize) -> io::Result<usize>210     fn get_buffer_offset(&self, idx: usize) -> io::Result<usize> {
211         let buffer_offset = self
212             .buffer_offset
213             .get(idx)
214             .ok_or_else(index_out_of_range)?
215             .load() as usize;
216         self.check_buffer_offset(idx, buffer_offset)?;
217         Ok(buffer_offset)
218     }
219 
220     /// Gets the number of bytes per frame from the shared memory structure.
221     ///
222     /// # Returns
223     ///
224     /// * `usize` - Number of bytes per frame
get_frame_size(&self) -> usize225     pub fn get_frame_size(&self) -> usize {
226         self.frame_size.load() as usize
227     }
228 
229     /// Gets the size in bytes of the shared memory buffer.
get_used_size(&self) -> usize230     fn get_used_size(&self) -> usize {
231         self.used_size.load() as usize
232     }
233 
234     /// Gets the index of the current written buffer.
235     ///
236     /// # Returns
237     /// `u32` - the returned index is less than `CRAS_NUM_SHM_BUFFERS`.
get_write_buf_idx(&self) -> u32238     fn get_write_buf_idx(&self) -> u32 {
239         self.write_buf_idx.load() & CRAS_SHM_BUFFERS_MASK
240     }
241 
get_read_buf_idx(&self) -> u32242     fn get_read_buf_idx(&self) -> u32 {
243         self.read_buf_idx.load() & CRAS_SHM_BUFFERS_MASK
244     }
245 
246     /// Switches the written buffer.
switch_write_buf_idx(&mut self)247     fn switch_write_buf_idx(&mut self) {
248         self.write_buf_idx
249             .store(self.get_write_buf_idx() as u32 ^ 1u32)
250     }
251 
252     /// Switches the buffer to read.
switch_read_buf_idx(&mut self)253     fn switch_read_buf_idx(&mut self) {
254         self.read_buf_idx
255             .store(self.get_read_buf_idx() as u32 ^ 1u32)
256     }
257 
258     /// Checks if the offset value for setting write_offset or read_offset is
259     /// out of range or not.
260     ///
261     /// # Arguments
262     /// `idx` - The index of the buffer for which we're checking the offset.
263     /// `offset` - 0 <= `offset` <= `used_size` && `buffer_offset[idx]` + `offset` <=
264     /// `samples_len`. Writable or readable size equals to 0 when offset equals
265     /// to `used_size`.
266     ///
267     /// # Errors
268     /// Returns an error if `offset` is out of range or if idx is not a valid
269     /// buffer idx.
check_rw_offset(&self, idx: usize, offset: u32) -> io::Result<()>270     fn check_rw_offset(&self, idx: usize, offset: u32) -> io::Result<()> {
271         let buffer_len = self.buffer_len_from_offset(self.get_buffer_offset(idx)?)?;
272         if offset as usize > buffer_len {
273             return Err(io::Error::new(
274                 io::ErrorKind::InvalidInput,
275                 format!(
276                     "Offset {} is larger than buffer size {}.",
277                     offset, buffer_len
278                 ),
279             ));
280         }
281 
282         Ok(())
283     }
284 
285     /// Sets `write_offset[idx]` to the count of written bytes.
286     ///
287     /// # Arguments
288     /// `idx` - 0 <= `idx` < `CRAS_NUM_SHM_BUFFERS`
289     /// `offset` - 0 <= `offset` <= `used_size` && `offset` + `used_size` <=
290     /// `samples_len`. Writable size equals to 0 when offset equals to
291     /// `used_size`.
292     ///
293     /// # Errors
294     /// Returns an error if `offset` is out of range.
set_write_offset(&mut self, idx: usize, offset: u32) -> io::Result<()>295     fn set_write_offset(&mut self, idx: usize, offset: u32) -> io::Result<()> {
296         self.check_rw_offset(idx, offset)?;
297         let write_offset = self.write_offset.get(idx).ok_or_else(index_out_of_range)?;
298         write_offset.store(offset);
299         Ok(())
300     }
301 
302     /// Sets `read_offset[idx]` of to count of written bytes.
303     ///
304     /// # Arguments
305     /// `idx` - 0 <= `idx` < `CRAS_NUM_SHM_BUFFERS`
306     /// `offset` - 0 <= `offset` <= `used_size` && `offset` + `used_size` <=
307     /// `samples_len`. Readable size equals to 0 when offset equals to
308     /// `used_size`.
309     ///
310     /// # Errors
311     /// Returns error if index out of range.
set_read_offset(&mut self, idx: usize, offset: u32) -> io::Result<()>312     fn set_read_offset(&mut self, idx: usize, offset: u32) -> io::Result<()> {
313         self.check_rw_offset(idx, offset)?;
314         let read_offset = self.read_offset.get(idx).ok_or_else(index_out_of_range)?;
315         read_offset.store(offset);
316         Ok(())
317     }
318 
319     /// Check that `offset` is a valid buffer offset for the buffer at `idx`
320     /// An offset is not valid if it is
321     ///  * outside of the samples area
322     ///  * overlaps some other buffer `[other_offset, other_offset + used_size)`
323     ///  * is close enough to the end of the samples area that the buffer would
324     ///    be shorter than `frame_size`.
check_buffer_offset(&self, idx: usize, offset: usize) -> io::Result<()>325     fn check_buffer_offset(&self, idx: usize, offset: usize) -> io::Result<()> {
326         let start = offset;
327         let end = start + self.buffer_len_from_offset(start)?;
328 
329         let other_idx = (idx ^ 1) as usize;
330         let other_start = self
331             .buffer_offset
332             .get(other_idx)
333             .ok_or_else(index_out_of_range)?
334             .load() as usize;
335         let other_end = other_start + self.buffer_len_from_offset(other_start)?;
336         if start < other_end && other_start < end {
337             return Err(io::Error::new(
338                 io::ErrorKind::InvalidInput,
339                 format!(
340                     "Setting buffer {} to [{}, {}) overlaps buffer {} at [{}, {})",
341                     idx, start, end, other_idx, other_start, other_end,
342                 ),
343             ));
344         }
345         Ok(())
346     }
347 
348     /// Sets the location of the audio buffer `idx` within the samples area to
349     /// `offset`, so that CRAS will read/write samples for that buffer from that
350     /// offset.
351     ///
352     /// # Arguments
353     /// `idx` - 0 <= `idx` < `CRAS_NUM_SHM_BUFFERS`
354     /// `offset` - 0 <= `offset` && `offset` + `frame_size` <= `samples_len`
355     ///
356     /// # Errors
357     /// If `idx` is out of range
358     /// If the offset is invalid, which can happen if `offset` is
359     ///  * outside of the samples area
360     ///  * overlaps some other buffer `[other_offset, other_offset + used_size)`
361     ///  * is close enough to the end of the samples area that the buffer would
362     ///    be shorter than `frame_size`.
set_buffer_offset(&mut self, idx: usize, offset: usize) -> io::Result<()>363     fn set_buffer_offset(&mut self, idx: usize, offset: usize) -> io::Result<()> {
364         self.check_buffer_offset(idx, offset)?;
365 
366         let buffer_offset = self.buffer_offset.get(idx).ok_or_else(index_out_of_range)?;
367         buffer_offset.store(offset as u32);
368         Ok(())
369     }
370 
371     /// Commits written frames by switching the current buffer to the other one
372     /// after samples are ready and indexes of current buffer are all set.
373     /// - Sets `write_offset` of current buffer to `frame_count * frame_size`
374     /// - Sets `read_offset` of current buffer to `0`.
375     ///
376     /// # Arguments
377     ///
378     /// * `frame_count` - Number of frames written to the current buffer
379     ///
380     /// # Errors
381     ///
382     /// * Returns error if `frame_count` is larger than buffer size
383     ///
384     /// This function is safe because we switch `write_buf_idx` after letting
385     /// `write_offset` and `read_offset` ready and we read / write shared memory
386     /// variables with volatile operations.
commit_written_frames(&mut self, frame_count: u32) -> io::Result<()>387     pub fn commit_written_frames(&mut self, frame_count: u32) -> io::Result<()> {
388         // Uses `u64` to prevent possible overflow
389         let byte_count = frame_count as u64 * self.get_frame_size() as u64;
390         if byte_count > self.get_used_size() as u64 {
391             Err(io::Error::new(
392                 io::ErrorKind::InvalidInput,
393                 "frame_count * frame_size is larger than used_size",
394             ))
395         } else {
396             let idx = self.get_write_buf_idx() as usize;
397             // Sets `write_offset` of current buffer to frame_count * frame_size
398             self.set_write_offset(idx, byte_count as u32)?;
399             // Sets `read_offset` of current buffer to `0`.
400             self.set_read_offset(idx, 0)?;
401             // Switch to the other buffer
402             self.switch_write_buf_idx();
403             Ok(())
404         }
405     }
406 
407     /// Get readable frames in current buffer.
408     ///
409     /// # Returns
410     ///
411     /// * `usize` - number of readable frames.
412     ///
413     /// # Errors
414     ///
415     /// Returns error if index out of range.
get_readable_frames(&self) -> io::Result<usize>416     pub fn get_readable_frames(&self) -> io::Result<usize> {
417         let idx = self.get_read_buf_idx() as usize;
418         let read_offset = self.read_offset.get(idx).ok_or_else(index_out_of_range)?;
419         let write_offset = self.write_offset.get(idx).ok_or_else(index_out_of_range)?;
420         let nframes =
421             (write_offset.load() as i32 - read_offset.load() as i32) / self.get_frame_size() as i32;
422         if nframes < 0 {
423             Ok(0)
424         } else {
425             Ok(nframes as usize)
426         }
427     }
428 
429     /// Commit read frames from reader, .
430     /// - Sets `read_offset` of current buffer to `read_offset + frame_count * frame_size`.
431     /// If `read_offset` is larger than or equal to `write_offset`, then
432     /// - Sets `read_offset` and `write_offset` to `0` and switch `read_buf_idx`.
433     ///
434     /// # Arguments
435     ///
436     /// * `frame_count` - Read frames in current read buffer.
437     ///
438     /// # Errors
439     ///
440     /// Returns error if index out of range.
commit_read_frames(&mut self, frame_count: u32) -> io::Result<()>441     pub fn commit_read_frames(&mut self, frame_count: u32) -> io::Result<()> {
442         let idx = self.get_read_buf_idx() as usize;
443         let read_offset = self.read_offset.get(idx).ok_or_else(index_out_of_range)?;
444         let write_offset = self.write_offset.get(idx).ok_or_else(index_out_of_range)?;
445         read_offset.store(read_offset.load() + frame_count * self.get_frame_size() as u32);
446         if read_offset.load() >= write_offset.load() {
447             read_offset.store(0);
448             write_offset.store(0);
449             self.switch_read_buf_idx();
450         }
451         Ok(())
452     }
453 }
454 
455 impl<'a> Drop for CrasAudioHeader<'a> {
drop(&mut self)456     fn drop(&mut self) {
457         // Safe because all references must be gone by the time drop is called.
458         unsafe {
459             libc::munmap(self.addr as *mut _, mem::size_of::<cras_audio_shm_header>());
460         }
461     }
462 }
463 
464 // To use this safely, we need to make sure
465 // - The given fd contains valid space which is larger than `len` + `offset`
cras_mmap_offset( len: usize, prot: libc::c_int, fd: libc::c_int, offset: usize, ) -> io::Result<*mut libc::c_void>466 unsafe fn cras_mmap_offset(
467     len: usize,
468     prot: libc::c_int,
469     fd: libc::c_int,
470     offset: usize,
471 ) -> io::Result<*mut libc::c_void> {
472     if offset > libc::off_t::max_value() as usize {
473         return Err(io::Error::new(
474             io::ErrorKind::InvalidInput,
475             "Requested offset is out of range of `libc::off_t`.",
476         ));
477     }
478     // It's safe because we handle its returned results.
479     match libc::mmap(
480         ptr::null_mut(),
481         len,
482         prot,
483         libc::MAP_SHARED,
484         fd,
485         offset as libc::off_t,
486     ) {
487         libc::MAP_FAILED => Err(io::Error::last_os_error()),
488         shm_ptr => Ok(shm_ptr),
489     }
490 }
491 
492 // To use this safely, we need to make sure
493 // - The given fd contains valid space which is larger than `len`
cras_mmap( len: usize, prot: libc::c_int, fd: libc::c_int, ) -> io::Result<*mut libc::c_void>494 unsafe fn cras_mmap(
495     len: usize,
496     prot: libc::c_int,
497     fd: libc::c_int,
498 ) -> io::Result<*mut libc::c_void> {
499     cras_mmap_offset(len, prot, fd, 0)
500 }
501 
502 /// A structure that points to RO shared memory area - `cras_server_state`
503 /// The structure is created from a shared memory fd which contains the structure.
504 #[allow(dead_code)]
505 pub struct CrasServerState {
506     addr: *mut libc::c_void,
507     size: usize,
508 }
509 
510 impl CrasServerState {
511     /// An unsafe function for creating `CrasServerState`. To use this function safely, we need to
512     /// - Make sure that the `shm_fd` must come from the server's message that provides the shared
513     /// memory region. The Id for the message is `CRAS_CLIENT_MESSAGE_ID::CRAS_CLIENT_CONNECTED`.
514     #[allow(dead_code)]
new(shm_fd: CrasShmFd) -> io::Result<Self>515     pub unsafe fn new(shm_fd: CrasShmFd) -> io::Result<Self> {
516         let size = mem::size_of::<cras_server_state>();
517         if size > shm_fd.size {
518             Err(io::Error::new(
519                 io::ErrorKind::InvalidInput,
520                 "Invalid shared memory size.",
521             ))
522         } else {
523             let addr = cras_mmap(size, libc::PROT_READ, shm_fd.as_raw_fd())?;
524             Ok(CrasServerState { addr, size })
525         }
526     }
527 
528     // Gets `cras_server_state` reference from the structure.
529     #[allow(dead_code)]
get_ref(&self) -> VolatileRef<cras_server_state>530     fn get_ref(&self) -> VolatileRef<cras_server_state> {
531         unsafe { VolatileRef::new(self.addr as *mut _) }
532     }
533 }
534 
535 impl Drop for CrasServerState {
536     /// Call `munmap` for `addr`.
drop(&mut self)537     fn drop(&mut self) {
538         unsafe {
539             // Safe because all references must be gone by the time drop is called.
540             libc::munmap(self.addr, self.size);
541         }
542     }
543 }
544 
545 /// A structure holding the mapped shared memory area used to exchange
546 /// samples with CRAS. The shared memory is owned exclusively by this structure,
547 /// and will be cleaned up on drop.
548 /// * `addr` - The address of the mapped shared memory.
549 /// * `len` - Length of the mapped shared memory in bytes.
550 pub struct CrasAudioBuffer {
551     addr: *mut u8,
552     len: usize,
553 }
554 
555 // It is safe to send audio buffers between threads as this struct has exclusive ownership of the
556 // shared memory area contained in it.
557 unsafe impl Send for CrasAudioBuffer {}
558 
559 impl CrasAudioBuffer {
new(samples_fd: CrasShmFd) -> io::Result<Self>560     fn new(samples_fd: CrasShmFd) -> io::Result<Self> {
561         // This is safe because we checked that the size of the shm in samples_fd
562         // was at least samples_fd.size when it was created.
563         let addr = unsafe {
564             cras_mmap(
565                 samples_fd.size,
566                 libc::PROT_READ | libc::PROT_WRITE,
567                 samples_fd.as_raw_fd(),
568             )? as *mut u8
569         };
570         Ok(Self {
571             addr,
572             len: samples_fd.size,
573         })
574     }
575 
576     /// Provides a mutable slice to be filled with audio samples.
get_buffer(&mut self) -> &mut [u8]577     pub fn get_buffer(&mut self) -> &mut [u8] {
578         // This is safe because it takes a mutable reference to self, and there can only be one
579         // taken at a time. Although this is shared memory, the reader side must have it mapped as
580         // read only.
581         unsafe { slice::from_raw_parts_mut(self.addr, self.len) }
582     }
583 }
584 
585 impl Drop for CrasAudioBuffer {
drop(&mut self)586     fn drop(&mut self) {
587         // Safe because all references must be gone by the time drop is called.
588         unsafe {
589             libc::munmap(self.addr as *mut _, self.len);
590         }
591     }
592 }
593 
594 /// Creates header and buffer from given shared memory fds.
create_header_and_buffers<'a>( header_fd: CrasAudioShmHeaderFd, samples_fd: CrasShmFd, ) -> io::Result<(CrasAudioHeader<'a>, CrasAudioBuffer)>595 pub fn create_header_and_buffers<'a>(
596     header_fd: CrasAudioShmHeaderFd,
597     samples_fd: CrasShmFd,
598 ) -> io::Result<(CrasAudioHeader<'a>, CrasAudioBuffer)> {
599     let header = CrasAudioHeader::new(header_fd, samples_fd.size)?;
600     let buffer = CrasAudioBuffer::new(samples_fd)?;
601 
602     Ok((header, buffer))
603 }
604 
605 /// A structure wrapping a fd which contains a shared memory area and its size.
606 /// * `fd` - The shared memory file descriptor, a `libc::c_int`.
607 /// * `size` - Size of the shared memory area.
608 pub struct CrasShmFd {
609     fd: libc::c_int,
610     size: usize,
611 }
612 
613 impl CrasShmFd {
614     /// Creates a `CrasShmFd` by shared memory fd and size
615     /// # Arguments
616     /// * `fd` - A shared memory file descriptor, which will be owned by the resulting structure and
617     /// the fd will be closed on drop.
618     /// * `size` - Size of the shared memory.
619     ///
620     /// # Returns
621     /// * `CrasShmFd` - Wrap the input arguments without doing anything.
622     ///
623     /// To use this function safely, we need to make sure
624     /// - The input fd is a valid shared memory fd.
625     /// - The input shared memory fd won't be used by others.
626     /// - The input fd contains memory size larger than `size`.
new(fd: libc::c_int, size: usize) -> CrasShmFd627     pub unsafe fn new(fd: libc::c_int, size: usize) -> CrasShmFd {
628         CrasShmFd { fd, size }
629     }
630 }
631 
632 impl AsRawFd for CrasShmFd {
as_raw_fd(&self) -> RawFd633     fn as_raw_fd(&self) -> RawFd {
634         self.fd
635     }
636 }
637 
638 impl Drop for CrasShmFd {
drop(&mut self)639     fn drop(&mut self) {
640         // It's safe here if we make sure
641         // - the input fd is valid and
642         // - `CrasShmFd` is the only owner
643         // in `new` function
644         unsafe {
645             libc::close(self.fd);
646         }
647     }
648 }
649 
650 /// A structure wrapping a fd which contains a shared `cras_server_state`.
651 /// * `shm_fd` - A shared memory fd contains a `cras_server_state`
652 pub struct CrasServerStateShmFd {
653     #[allow(dead_code)]
654     shm_fd: CrasShmFd,
655 }
656 
657 impl CrasServerStateShmFd {
658     /// Creates a `CrasServerStateShmFd` by shared memory fd
659     /// # Arguments
660     /// * `fd` - A shared memory file descriptor, which will be owned by the resulting structure and
661     /// the fd will be closed on drop.
662     ///
663     /// # Returns
664     /// A structure wrapping a `CrasShmFd` with the input fd and `size` which equals to
665     /// the size of `cras_server_sate`.
666     ///
667     /// To use this function safely, we need to make sure
668     /// - The input fd is a valid shared memory fd.
669     /// - The input shared memory fd won't be used by others.
670     /// - The shared memory area in the input fd contains a `cras_server_state`.
new(fd: libc::c_int) -> Self671     pub unsafe fn new(fd: libc::c_int) -> Self {
672         Self {
673             shm_fd: CrasShmFd::new(fd, mem::size_of::<cras_server_state>()),
674         }
675     }
676 }
677 
678 #[cfg(test)]
679 mod tests {
680     use super::*;
681     use std::fs::File;
682     use std::os::unix::io::IntoRawFd;
683     use sys_util::{kernel_has_memfd, SharedMemory};
684 
685     #[test]
cras_audio_header_switch_test()686     fn cras_audio_header_switch_test() {
687         if !kernel_has_memfd() {
688             return;
689         }
690         let mut header = create_cras_audio_header(20);
691         assert_eq!(0, header.get_write_buf_idx());
692         header.switch_write_buf_idx();
693         assert_eq!(1, header.get_write_buf_idx());
694     }
695 
696     #[test]
cras_audio_header_write_offset_test()697     fn cras_audio_header_write_offset_test() {
698         if !kernel_has_memfd() {
699             return;
700         }
701         let mut header = create_cras_audio_header(20);
702         header.frame_size.store(2);
703         header.used_size.store(5);
704         header.set_buffer_offset(0, 12).unwrap();
705 
706         assert_eq!(0, header.write_offset[0].load());
707         // Index out of bound
708         assert!(header.set_write_offset(2, 5).is_err());
709         // Offset out of bound
710         // Buffer length is 4, since that's the largest multiple of frame_size
711         // less than used_size.
712         assert!(header.set_write_offset(0, 6).is_err());
713         assert_eq!(0, header.write_offset[0].load());
714         assert!(header.set_write_offset(0, 5).is_err());
715         assert_eq!(0, header.write_offset[0].load());
716         assert!(header.set_write_offset(0, 4).is_ok());
717         assert_eq!(4, header.write_offset[0].load());
718     }
719 
720     #[test]
cras_audio_header_read_offset_test()721     fn cras_audio_header_read_offset_test() {
722         if !kernel_has_memfd() {
723             return;
724         }
725         let mut header = create_cras_audio_header(20);
726         header.frame_size.store(2);
727         header.used_size.store(5);
728         header.set_buffer_offset(0, 12).unwrap();
729 
730         assert_eq!(0, header.read_offset[0].load());
731         // Index out of bound
732         assert!(header.set_read_offset(2, 5).is_err());
733         // Offset out of bound
734         // Buffer length is 4, since that's the largest multiple of frame_size
735         // less than used_size.
736         assert!(header.set_read_offset(0, 6).is_err());
737         assert_eq!(0, header.read_offset[0].load());
738         assert!(header.set_read_offset(0, 5).is_err());
739         assert_eq!(0, header.read_offset[0].load());
740         assert!(header.set_read_offset(0, 4).is_ok());
741         assert_eq!(4, header.read_offset[0].load());
742     }
743 
744     #[test]
cras_audio_header_commit_written_frame_test()745     fn cras_audio_header_commit_written_frame_test() {
746         if !kernel_has_memfd() {
747             return;
748         }
749         let mut header = create_cras_audio_header(20);
750         header.frame_size.store(2);
751         header.used_size.store(10);
752         header.read_offset[0].store(10);
753         header.set_buffer_offset(0, 10).unwrap();
754 
755         assert!(header.commit_written_frames(5).is_ok());
756         assert_eq!(header.write_offset[0].load(), 10);
757         assert_eq!(header.read_offset[0].load(), 0);
758         assert_eq!(header.write_buf_idx.load(), 1);
759     }
760 
761     #[test]
cras_audio_header_get_readable_frames_test()762     fn cras_audio_header_get_readable_frames_test() {
763         if !kernel_has_memfd() {
764             return;
765         }
766         let header = create_cras_audio_header(20);
767         header.frame_size.store(2);
768         header.used_size.store(10);
769         header.read_offset[0].store(2);
770         header.write_offset[0].store(10);
771         let frames = header
772             .get_readable_frames()
773             .expect("Failed to get readable frames.");
774         assert_eq!(frames, 4);
775     }
776 
777     #[test]
cras_audio_header_commit_read_frames_test()778     fn cras_audio_header_commit_read_frames_test() {
779         if !kernel_has_memfd() {
780             return;
781         }
782         let mut header = create_cras_audio_header(20);
783         header.frame_size.store(2);
784         header.used_size.store(10);
785         header.read_offset[0].store(2);
786         header.write_offset[0].store(10);
787         header
788             .commit_read_frames(3)
789             .expect("Failed to commit read frames.");
790         assert_eq!(header.get_read_buf_idx(), 0);
791         assert_eq!(header.read_offset[0].load(), 8);
792 
793         header
794             .commit_read_frames(1)
795             .expect("Failed to commit read frames.");
796         // Read buffer should be switched
797         assert_eq!(header.get_read_buf_idx(), 1);
798         assert_eq!(header.read_offset[0].load(), 0);
799         assert_eq!(header.read_offset[0].load(), 0);
800     }
801 
802     #[test]
cras_audio_header_get_write_offset_and_len()803     fn cras_audio_header_get_write_offset_and_len() {
804         if !kernel_has_memfd() {
805             return;
806         }
807         let header = create_cras_audio_header(30);
808         header.frame_size.store(2);
809         header.used_size.store(10);
810         header.write_buf_idx.store(0);
811         header.read_offset[0].store(0);
812         header.write_offset[0].store(0);
813         header.buffer_offset[0].store(0);
814 
815         header.read_buf_idx.store(1);
816         header.read_offset[1].store(0);
817         header.write_offset[1].store(0);
818         header.buffer_offset[1].store(10);
819 
820         // standard offsets and lens
821         let (offset, len) = header.get_write_offset_and_len().unwrap();
822         assert_eq!(offset, 0);
823         assert_eq!(len, 10);
824 
825         header.write_buf_idx.store(1);
826         header.read_buf_idx.store(0);
827         let (offset, len) = header.get_write_offset_and_len().unwrap();
828         assert_eq!(offset, 10);
829         assert_eq!(len, 10);
830 
831         // relocate buffer offsets
832         header.buffer_offset[1].store(16);
833         let (offset, len) = header.get_write_offset_and_len().unwrap();
834         assert_eq!(offset, 16);
835         assert_eq!(len, 10);
836 
837         header.buffer_offset[0].store(5);
838         header.write_buf_idx.store(0);
839         let (offset, len) = header.get_write_offset_and_len().unwrap();
840         assert_eq!(offset, 5);
841         assert_eq!(len, 10);
842 
843         header.write_buf_idx.store(0);
844         header.buffer_offset[0].store(2);
845         header.read_buf_idx.store(1);
846         header.buffer_offset[1].store(10);
847         let result = header.get_write_offset_and_len();
848         // Should be an error as write buffer would overrun into other buffer.
849         assert!(result.is_err());
850 
851         header.buffer_offset[0].store(24);
852         header.buffer_offset[1].store(10);
853         let (offset, len) = header.get_write_offset_and_len().unwrap();
854         // Should be ok since we're only running up against the end of samples.
855         assert_eq!(offset, 24);
856         assert_eq!(len, 6);
857 
858         header.buffer_offset[0].store(25);
859         let (offset, len) = header.get_write_offset_and_len().unwrap();
860         // Should be ok, but we'll truncate len to frame_size.
861         assert_eq!(offset, 25);
862         assert_eq!(len, 4);
863 
864         header.buffer_offset[0].store(29);
865         let result = header.get_write_offset_and_len();
866         // Should be an error as buffer is smaller than frame_size.
867         assert!(result.is_err());
868     }
869 
870     #[test]
cras_audio_header_set_buffer_offset()871     fn cras_audio_header_set_buffer_offset() {
872         if !kernel_has_memfd() {
873             return;
874         }
875         let mut header = create_cras_audio_header(30);
876         header.frame_size.store(2);
877         header.used_size.store(10);
878         header.write_buf_idx.store(0);
879         header.read_offset[0].store(0);
880         header.write_offset[0].store(0);
881         header.buffer_offset[0].store(0);
882 
883         header.read_buf_idx.store(1);
884         header.read_offset[1].store(0);
885         header.write_offset[1].store(0);
886         header.buffer_offset[1].store(10);
887 
888         // Setting buffer_offset to overlap with other buffer is not okay
889         assert!(header.set_buffer_offset(0, 10).is_err());
890 
891         header.buffer_offset[0].store(0);
892         header.write_offset[1].store(8);
893         // With samples, it's still an error.
894         assert!(header.set_buffer_offset(0, 10).is_err());
895 
896         // Setting the offset past the end of the other buffer is okay
897         assert!(header.set_buffer_offset(0, 20).is_ok());
898 
899         // Setting buffer offset such that buffer length is less than used_size
900         // is okay, but only at the end of the samples area.
901         assert!(header.set_buffer_offset(0, 21).is_ok());
902         assert!(header.set_buffer_offset(0, 27).is_ok());
903 
904         // It's not okay if we get a buffer with length less than frame_size.
905         assert!(header.set_buffer_offset(0, 29).is_err());
906         assert!(header.set_buffer_offset(0, 30).is_err());
907 
908         // If we try to overlap another buffer with that other buffer at the end,
909         // it's not okay.
910         assert!(header.set_buffer_offset(1, 25).is_err());
911         assert!(header.set_buffer_offset(1, 27).is_err());
912         assert!(header.set_buffer_offset(1, 28).is_err());
913 
914         // Setting buffer offset past the end of samples is an error.
915         assert!(header.set_buffer_offset(0, 33).is_err());
916     }
917 
918     #[test]
create_header_and_buffers_test()919     fn create_header_and_buffers_test() {
920         if !kernel_has_memfd() {
921             return;
922         }
923         let header_fd = cras_audio_header_fd();
924         let samples_fd = cras_audio_samples_fd(20);
925         let res = create_header_and_buffers(header_fd, samples_fd);
926         res.expect("Failed to create header and buffer.");
927     }
928 
create_shm(size: usize) -> File929     fn create_shm(size: usize) -> File {
930         let mut shm = SharedMemory::new(None).expect("failed to create shm");
931         shm.set_size(size as u64).expect("failed to set shm size");
932         shm.into()
933     }
934 
create_cras_audio_header<'a>(samples_len: usize) -> CrasAudioHeader<'a>935     fn create_cras_audio_header<'a>(samples_len: usize) -> CrasAudioHeader<'a> {
936         CrasAudioHeader::new(cras_audio_header_fd(), samples_len).unwrap()
937     }
938 
cras_audio_header_fd() -> CrasAudioShmHeaderFd939     fn cras_audio_header_fd() -> CrasAudioShmHeaderFd {
940         let size = mem::size_of::<cras_audio_shm_header>();
941         let shm = create_shm(size);
942         unsafe { CrasAudioShmHeaderFd::new(shm.into_raw_fd()) }
943     }
944 
cras_audio_samples_fd(size: usize) -> CrasShmFd945     fn cras_audio_samples_fd(size: usize) -> CrasShmFd {
946         let shm = create_shm(size);
947         unsafe { CrasShmFd::new(shm.into_raw_fd(), size) }
948     }
949 
950     #[test]
cras_mmap_pass()951     fn cras_mmap_pass() {
952         if !kernel_has_memfd() {
953             return;
954         }
955         let shm = create_shm(100);
956         let rc = unsafe { cras_mmap(10, libc::PROT_READ, shm.as_raw_fd()) };
957         assert!(rc.is_ok());
958         unsafe { libc::munmap(rc.unwrap(), 10) };
959     }
960 
961     #[test]
cras_mmap_failed()962     fn cras_mmap_failed() {
963         if !kernel_has_memfd() {
964             return;
965         }
966         let rc = unsafe { cras_mmap(10, libc::PROT_READ, -1) };
967         assert!(rc.is_err());
968     }
969 }
970