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