xref: /aosp_15_r20/external/crosvm/audio_util/src/file_streams.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Error as IOError;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::slice;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicUsize;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant;
13*bb4ee6a4SAndroid Build Coastguard Worker 
14*bb4ee6a4SAndroid Build Coastguard Worker use async_trait::async_trait;
15*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::AsyncBufferCommit;
16*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::AsyncPlaybackBuffer;
17*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::AsyncPlaybackBufferStream;
18*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::AudioStreamsExecutor;
19*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::BoxError;
20*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::NoopStreamControl;
21*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::SampleFormat;
22*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::StreamControl;
23*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::StreamSource;
24*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::StreamSourceGenerator;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
26*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion;
27*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMapping;
28*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder;
29*bb4ee6a4SAndroid Build Coastguard Worker use base::MmapError;
30*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
31*bb4ee6a4SAndroid Build Coastguard Worker 
32*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
33*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
34*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Failed to build memory mapping: {0}")]
35*bb4ee6a4SAndroid Build Coastguard Worker     BuildMemoryMapping(MmapError),
36*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Failed to clone file descriptor: {0}")]
37*bb4ee6a4SAndroid Build Coastguard Worker     Clone(IOError),
38*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Not implemented")]
39*bb4ee6a4SAndroid Build Coastguard Worker     Unimplemented,
40*bb4ee6a4SAndroid Build Coastguard Worker }
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker /// An Audio Stream that can be used to write playback buffer to a file.
43*bb4ee6a4SAndroid Build Coastguard Worker /// `FileStream` doesn't directly open and write to file. It receives
44*bb4ee6a4SAndroid Build Coastguard Worker /// an mmap of a file instead.
45*bb4ee6a4SAndroid Build Coastguard Worker ///
46*bb4ee6a4SAndroid Build Coastguard Worker /// Note that `FileStream` also needs the mmap-ed file has allocated some spaces
47*bb4ee6a4SAndroid Build Coastguard Worker /// to be written. If the playback buffer exceeds the allocated spaces,
48*bb4ee6a4SAndroid Build Coastguard Worker /// it will invoke `panic!`
49*bb4ee6a4SAndroid Build Coastguard Worker pub struct FileStream {
50*bb4ee6a4SAndroid Build Coastguard Worker     /// A MemoryMapping that will hold the copy of the playback buffer.
51*bb4ee6a4SAndroid Build Coastguard Worker     memory_mapping: AudioMemoryMapping,
52*bb4ee6a4SAndroid Build Coastguard Worker     /// Number of bytes that has been written.
53*bb4ee6a4SAndroid Build Coastguard Worker     offset: Arc<AtomicUsize>,
54*bb4ee6a4SAndroid Build Coastguard Worker     /// Number of bytes in a single audio frame.
55*bb4ee6a4SAndroid Build Coastguard Worker     frame_size: usize,
56*bb4ee6a4SAndroid Build Coastguard Worker     /// Length of the current playback buffer in bytes.
57*bb4ee6a4SAndroid Build Coastguard Worker     buffer_mem_length: usize,
58*bb4ee6a4SAndroid Build Coastguard Worker 
59*bb4ee6a4SAndroid Build Coastguard Worker     /// Duration of an audio in milliseconds for the current `buffer_size`.
60*bb4ee6a4SAndroid Build Coastguard Worker     interval_ms: Duration,
61*bb4ee6a4SAndroid Build Coastguard Worker     /// Time marker of correct time to return next buffer.
62*bb4ee6a4SAndroid Build Coastguard Worker     next_frame: Duration,
63*bb4ee6a4SAndroid Build Coastguard Worker     /// Timestamp that records when the stream starts.
64*bb4ee6a4SAndroid Build Coastguard Worker     start_time: Option<Instant>,
65*bb4ee6a4SAndroid Build Coastguard Worker     /// Type that will be called before the buffer is dropped.
66*bb4ee6a4SAndroid Build Coastguard Worker     buffer_drop: FileStreamBufferCommit,
67*bb4ee6a4SAndroid Build Coastguard Worker }
68*bb4ee6a4SAndroid Build Coastguard Worker 
69*bb4ee6a4SAndroid Build Coastguard Worker impl FileStream {
new( memory_mapping: AudioMemoryMapping, offset: Arc<AtomicUsize>, frame_size: usize, buffer_mem_length: usize, interval_ms: Duration, ) -> Self70*bb4ee6a4SAndroid Build Coastguard Worker     fn new(
71*bb4ee6a4SAndroid Build Coastguard Worker         memory_mapping: AudioMemoryMapping,
72*bb4ee6a4SAndroid Build Coastguard Worker         offset: Arc<AtomicUsize>,
73*bb4ee6a4SAndroid Build Coastguard Worker         frame_size: usize,
74*bb4ee6a4SAndroid Build Coastguard Worker         buffer_mem_length: usize,
75*bb4ee6a4SAndroid Build Coastguard Worker         interval_ms: Duration,
76*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Self {
77*bb4ee6a4SAndroid Build Coastguard Worker         let max_offset = memory_mapping.size();
78*bb4ee6a4SAndroid Build Coastguard Worker         FileStream {
79*bb4ee6a4SAndroid Build Coastguard Worker             memory_mapping,
80*bb4ee6a4SAndroid Build Coastguard Worker             offset: offset.clone(),
81*bb4ee6a4SAndroid Build Coastguard Worker             frame_size,
82*bb4ee6a4SAndroid Build Coastguard Worker             buffer_mem_length,
83*bb4ee6a4SAndroid Build Coastguard Worker 
84*bb4ee6a4SAndroid Build Coastguard Worker             interval_ms,
85*bb4ee6a4SAndroid Build Coastguard Worker             next_frame: interval_ms,
86*bb4ee6a4SAndroid Build Coastguard Worker             start_time: None,
87*bb4ee6a4SAndroid Build Coastguard Worker             buffer_drop: FileStreamBufferCommit {
88*bb4ee6a4SAndroid Build Coastguard Worker                 frame_size,
89*bb4ee6a4SAndroid Build Coastguard Worker                 offset,
90*bb4ee6a4SAndroid Build Coastguard Worker                 max_offset,
91*bb4ee6a4SAndroid Build Coastguard Worker             },
92*bb4ee6a4SAndroid Build Coastguard Worker         }
93*bb4ee6a4SAndroid Build Coastguard Worker     }
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker 
96*bb4ee6a4SAndroid Build Coastguard Worker #[async_trait(?Send)]
97*bb4ee6a4SAndroid Build Coastguard Worker impl AsyncPlaybackBufferStream for FileStream {
next_playback_buffer<'a>( &'a mut self, ex: &dyn AudioStreamsExecutor, ) -> Result<AsyncPlaybackBuffer<'a>, BoxError>98*bb4ee6a4SAndroid Build Coastguard Worker     async fn next_playback_buffer<'a>(
99*bb4ee6a4SAndroid Build Coastguard Worker         &'a mut self,
100*bb4ee6a4SAndroid Build Coastguard Worker         ex: &dyn AudioStreamsExecutor,
101*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<AsyncPlaybackBuffer<'a>, BoxError> {
102*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(start_time) = self.start_time {
103*bb4ee6a4SAndroid Build Coastguard Worker             let elapsed = start_time.elapsed();
104*bb4ee6a4SAndroid Build Coastguard Worker             if elapsed < self.next_frame {
105*bb4ee6a4SAndroid Build Coastguard Worker                 ex.delay(self.next_frame - elapsed).await?;
106*bb4ee6a4SAndroid Build Coastguard Worker             }
107*bb4ee6a4SAndroid Build Coastguard Worker             self.next_frame += self.interval_ms;
108*bb4ee6a4SAndroid Build Coastguard Worker         } else {
109*bb4ee6a4SAndroid Build Coastguard Worker             self.start_time = Some(Instant::now());
110*bb4ee6a4SAndroid Build Coastguard Worker             self.next_frame = self.interval_ms;
111*bb4ee6a4SAndroid Build Coastguard Worker         }
112*bb4ee6a4SAndroid Build Coastguard Worker 
113*bb4ee6a4SAndroid Build Coastguard Worker         let offset = self.offset.load(Ordering::Relaxed);
114*bb4ee6a4SAndroid Build Coastguard Worker         let buffer = self
115*bb4ee6a4SAndroid Build Coastguard Worker             .memory_mapping
116*bb4ee6a4SAndroid Build Coastguard Worker             .get_slice_mut(offset, self.buffer_mem_length);
117*bb4ee6a4SAndroid Build Coastguard Worker 
118*bb4ee6a4SAndroid Build Coastguard Worker         Ok(AsyncPlaybackBuffer::new(
119*bb4ee6a4SAndroid Build Coastguard Worker             self.frame_size,
120*bb4ee6a4SAndroid Build Coastguard Worker             buffer,
121*bb4ee6a4SAndroid Build Coastguard Worker             &mut self.buffer_drop,
122*bb4ee6a4SAndroid Build Coastguard Worker         )?)
123*bb4ee6a4SAndroid Build Coastguard Worker     }
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker 
126*bb4ee6a4SAndroid Build Coastguard Worker struct FileStreamSource {
127*bb4ee6a4SAndroid Build Coastguard Worker     file: File,
128*bb4ee6a4SAndroid Build Coastguard Worker     file_size: usize,
129*bb4ee6a4SAndroid Build Coastguard Worker     offset: Arc<AtomicUsize>,
130*bb4ee6a4SAndroid Build Coastguard Worker }
131*bb4ee6a4SAndroid Build Coastguard Worker 
132*bb4ee6a4SAndroid Build Coastguard Worker impl FileStreamSource {
new(file: File, file_size: usize, offset: Arc<AtomicUsize>) -> Self133*bb4ee6a4SAndroid Build Coastguard Worker     fn new(file: File, file_size: usize, offset: Arc<AtomicUsize>) -> Self {
134*bb4ee6a4SAndroid Build Coastguard Worker         FileStreamSource {
135*bb4ee6a4SAndroid Build Coastguard Worker             file,
136*bb4ee6a4SAndroid Build Coastguard Worker             file_size,
137*bb4ee6a4SAndroid Build Coastguard Worker             offset,
138*bb4ee6a4SAndroid Build Coastguard Worker         }
139*bb4ee6a4SAndroid Build Coastguard Worker     }
140*bb4ee6a4SAndroid Build Coastguard Worker }
141*bb4ee6a4SAndroid Build Coastguard Worker 
142*bb4ee6a4SAndroid Build Coastguard Worker impl StreamSource for FileStreamSource {
new_async_playback_stream( &mut self, num_channels: usize, format: SampleFormat, frame_rate: u32, buffer_size: usize, _ex: &dyn AudioStreamsExecutor, ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError>143*bb4ee6a4SAndroid Build Coastguard Worker     fn new_async_playback_stream(
144*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
145*bb4ee6a4SAndroid Build Coastguard Worker         num_channels: usize,
146*bb4ee6a4SAndroid Build Coastguard Worker         format: SampleFormat,
147*bb4ee6a4SAndroid Build Coastguard Worker         frame_rate: u32,
148*bb4ee6a4SAndroid Build Coastguard Worker         buffer_size: usize,
149*bb4ee6a4SAndroid Build Coastguard Worker         _ex: &dyn AudioStreamsExecutor,
150*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<(Box<dyn StreamControl>, Box<dyn AsyncPlaybackBufferStream>), BoxError> {
151*bb4ee6a4SAndroid Build Coastguard Worker         let memory_mapping = MemoryMappingBuilder::new(self.file_size)
152*bb4ee6a4SAndroid Build Coastguard Worker             .from_file(&self.file)
153*bb4ee6a4SAndroid Build Coastguard Worker             .build()
154*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::BuildMemoryMapping)?;
155*bb4ee6a4SAndroid Build Coastguard Worker 
156*bb4ee6a4SAndroid Build Coastguard Worker         let frame_size = format.sample_bytes() * num_channels;
157*bb4ee6a4SAndroid Build Coastguard Worker         let buffer_mem_length = buffer_size * frame_size;
158*bb4ee6a4SAndroid Build Coastguard Worker         let memory_mapping = AudioMemoryMapping::new(memory_mapping, buffer_mem_length);
159*bb4ee6a4SAndroid Build Coastguard Worker         let interval_ms = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);
160*bb4ee6a4SAndroid Build Coastguard Worker         Ok((
161*bb4ee6a4SAndroid Build Coastguard Worker             Box::new(NoopStreamControl::new()),
162*bb4ee6a4SAndroid Build Coastguard Worker             Box::new(FileStream::new(
163*bb4ee6a4SAndroid Build Coastguard Worker                 memory_mapping,
164*bb4ee6a4SAndroid Build Coastguard Worker                 self.offset.clone(),
165*bb4ee6a4SAndroid Build Coastguard Worker                 frame_size,
166*bb4ee6a4SAndroid Build Coastguard Worker                 buffer_mem_length,
167*bb4ee6a4SAndroid Build Coastguard Worker                 interval_ms,
168*bb4ee6a4SAndroid Build Coastguard Worker             )),
169*bb4ee6a4SAndroid Build Coastguard Worker         ))
170*bb4ee6a4SAndroid Build Coastguard Worker     }
171*bb4ee6a4SAndroid Build Coastguard Worker 
new_playback_stream( &mut self, _num_channels: usize, _format: SampleFormat, _frame_rate: u32, _buffer_size: usize, ) -> Result< ( Box<dyn StreamControl>, Box<dyn audio_streams::PlaybackBufferStream>, ), BoxError, >172*bb4ee6a4SAndroid Build Coastguard Worker     fn new_playback_stream(
173*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
174*bb4ee6a4SAndroid Build Coastguard Worker         _num_channels: usize,
175*bb4ee6a4SAndroid Build Coastguard Worker         _format: SampleFormat,
176*bb4ee6a4SAndroid Build Coastguard Worker         _frame_rate: u32,
177*bb4ee6a4SAndroid Build Coastguard Worker         _buffer_size: usize,
178*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<
179*bb4ee6a4SAndroid Build Coastguard Worker         (
180*bb4ee6a4SAndroid Build Coastguard Worker             Box<dyn StreamControl>,
181*bb4ee6a4SAndroid Build Coastguard Worker             Box<dyn audio_streams::PlaybackBufferStream>,
182*bb4ee6a4SAndroid Build Coastguard Worker         ),
183*bb4ee6a4SAndroid Build Coastguard Worker         BoxError,
184*bb4ee6a4SAndroid Build Coastguard Worker     > {
185*bb4ee6a4SAndroid Build Coastguard Worker         Err(Box::new(Error::Unimplemented))
186*bb4ee6a4SAndroid Build Coastguard Worker     }
187*bb4ee6a4SAndroid Build Coastguard Worker }
188*bb4ee6a4SAndroid Build Coastguard Worker 
189*bb4ee6a4SAndroid Build Coastguard Worker /// `FileStreamSourceGenerator` is a struct that implements [`StreamSourceGenerator`]
190*bb4ee6a4SAndroid Build Coastguard Worker /// for `FileStreamSource`.
191*bb4ee6a4SAndroid Build Coastguard Worker pub struct FileStreamSourceGenerator {
192*bb4ee6a4SAndroid Build Coastguard Worker     /// File descriptor which will be used to write playback buffer.
193*bb4ee6a4SAndroid Build Coastguard Worker     file: File,
194*bb4ee6a4SAndroid Build Coastguard Worker     /// Size of the output file in bytes.
195*bb4ee6a4SAndroid Build Coastguard Worker     file_size: usize,
196*bb4ee6a4SAndroid Build Coastguard Worker     /// Number of bytes that has been written to the file.
197*bb4ee6a4SAndroid Build Coastguard Worker     offset: Arc<AtomicUsize>,
198*bb4ee6a4SAndroid Build Coastguard Worker }
199*bb4ee6a4SAndroid Build Coastguard Worker 
200*bb4ee6a4SAndroid Build Coastguard Worker impl FileStreamSourceGenerator {
201*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new `FileStreamSourceGenerator` by given arguments.
202*bb4ee6a4SAndroid Build Coastguard Worker     /// It expects `file` has `file_size` of bytes allocated spaces.
203*bb4ee6a4SAndroid Build Coastguard Worker     ///
204*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
205*bb4ee6a4SAndroid Build Coastguard Worker     ///
206*bb4ee6a4SAndroid Build Coastguard Worker     /// * `file` - The file where audio playback buffer will be written.
207*bb4ee6a4SAndroid Build Coastguard Worker     /// * `file_size` - The size of bytes allocated for playback_file.
new(file: File, file_size: usize) -> Self208*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(file: File, file_size: usize) -> Self {
209*bb4ee6a4SAndroid Build Coastguard Worker         FileStreamSourceGenerator {
210*bb4ee6a4SAndroid Build Coastguard Worker             file,
211*bb4ee6a4SAndroid Build Coastguard Worker             file_size,
212*bb4ee6a4SAndroid Build Coastguard Worker             offset: Arc::new(AtomicUsize::new(0)),
213*bb4ee6a4SAndroid Build Coastguard Worker         }
214*bb4ee6a4SAndroid Build Coastguard Worker     }
215*bb4ee6a4SAndroid Build Coastguard Worker }
216*bb4ee6a4SAndroid Build Coastguard Worker 
217*bb4ee6a4SAndroid Build Coastguard Worker impl StreamSourceGenerator for FileStreamSourceGenerator {
generate(&self) -> Result<Box<dyn StreamSource>, BoxError>218*bb4ee6a4SAndroid Build Coastguard Worker     fn generate(&self) -> Result<Box<dyn StreamSource>, BoxError> {
219*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(FileStreamSource::new(
220*bb4ee6a4SAndroid Build Coastguard Worker             self.file.try_clone().map_err(Error::Clone)?,
221*bb4ee6a4SAndroid Build Coastguard Worker             self.file_size,
222*bb4ee6a4SAndroid Build Coastguard Worker             self.offset.clone(),
223*bb4ee6a4SAndroid Build Coastguard Worker         )))
224*bb4ee6a4SAndroid Build Coastguard Worker     }
225*bb4ee6a4SAndroid Build Coastguard Worker }
226*bb4ee6a4SAndroid Build Coastguard Worker 
227*bb4ee6a4SAndroid Build Coastguard Worker struct FileStreamBufferCommit {
228*bb4ee6a4SAndroid Build Coastguard Worker     frame_size: usize,
229*bb4ee6a4SAndroid Build Coastguard Worker     offset: Arc<AtomicUsize>,
230*bb4ee6a4SAndroid Build Coastguard Worker     max_offset: usize,
231*bb4ee6a4SAndroid Build Coastguard Worker }
232*bb4ee6a4SAndroid Build Coastguard Worker 
233*bb4ee6a4SAndroid Build Coastguard Worker #[async_trait(?Send)]
234*bb4ee6a4SAndroid Build Coastguard Worker impl AsyncBufferCommit for FileStreamBufferCommit {
commit(&mut self, nwritten: usize)235*bb4ee6a4SAndroid Build Coastguard Worker     async fn commit(&mut self, nwritten: usize) {
236*bb4ee6a4SAndroid Build Coastguard Worker         let written_bytes = nwritten * self.frame_size;
237*bb4ee6a4SAndroid Build Coastguard Worker         if self.offset.load(Ordering::Relaxed) + written_bytes < self.max_offset {
238*bb4ee6a4SAndroid Build Coastguard Worker             self.offset.fetch_add(written_bytes, Ordering::Relaxed);
239*bb4ee6a4SAndroid Build Coastguard Worker         }
240*bb4ee6a4SAndroid Build Coastguard Worker     }
241*bb4ee6a4SAndroid Build Coastguard Worker }
242*bb4ee6a4SAndroid Build Coastguard Worker 
243*bb4ee6a4SAndroid Build Coastguard Worker struct AudioMemoryMapping {
244*bb4ee6a4SAndroid Build Coastguard Worker     memory_mapping: MemoryMapping,
245*bb4ee6a4SAndroid Build Coastguard Worker     zero_buffer: Vec<u8>,
246*bb4ee6a4SAndroid Build Coastguard Worker }
247*bb4ee6a4SAndroid Build Coastguard Worker 
248*bb4ee6a4SAndroid Build Coastguard Worker impl AudioMemoryMapping {
new(memory_mapping: MemoryMapping, buffer_mem_length: usize) -> Self249*bb4ee6a4SAndroid Build Coastguard Worker     fn new(memory_mapping: MemoryMapping, buffer_mem_length: usize) -> Self {
250*bb4ee6a4SAndroid Build Coastguard Worker         AudioMemoryMapping {
251*bb4ee6a4SAndroid Build Coastguard Worker             memory_mapping,
252*bb4ee6a4SAndroid Build Coastguard Worker             zero_buffer: vec![0; buffer_mem_length],
253*bb4ee6a4SAndroid Build Coastguard Worker         }
254*bb4ee6a4SAndroid Build Coastguard Worker     }
255*bb4ee6a4SAndroid Build Coastguard Worker 
get_slice_mut(&mut self, offset: usize, len: usize) -> &mut [u8]256*bb4ee6a4SAndroid Build Coastguard Worker     fn get_slice_mut(&mut self, offset: usize, len: usize) -> &mut [u8] {
257*bb4ee6a4SAndroid Build Coastguard Worker         if offset + len >= self.memory_mapping.size() {
258*bb4ee6a4SAndroid Build Coastguard Worker             warn!("Accessing unallocated region");
259*bb4ee6a4SAndroid Build Coastguard Worker             return &mut self.zero_buffer;
260*bb4ee6a4SAndroid Build Coastguard Worker         }
261*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
262*bb4ee6a4SAndroid Build Coastguard Worker         // safe because the region returned is owned by self.memory_mapping
263*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { slice::from_raw_parts_mut(self.memory_mapping.as_ptr().add(offset), len) }
264*bb4ee6a4SAndroid Build Coastguard Worker     }
265*bb4ee6a4SAndroid Build Coastguard Worker 
size(&self) -> usize266*bb4ee6a4SAndroid Build Coastguard Worker     fn size(&self) -> usize {
267*bb4ee6a4SAndroid Build Coastguard Worker         self.memory_mapping.size()
268*bb4ee6a4SAndroid Build Coastguard Worker     }
269*bb4ee6a4SAndroid Build Coastguard Worker }
270