1use fuchsia_inspect as inspect;
6use fuchsia_inspect_derive::{AttachError, Inspect};
7use fuchsia_sync::Mutex;
8use futures::stream::FusedStream;
9use futures::task::{Context, Poll};
10use futures::{FutureExt, Stream};
11use log::info;
12use std::pin::Pin;
13use std::sync::Arc;
14
15use crate::frame_vmo::{self, FrameReadResult};
16use crate::stream_config::{SoftStreamConfig, StreamConfigOrTask};
17use crate::types::{AudioStreamItem, Error, Result};
18
19pub struct AudioFrameStream {
23 frame_vmo: Arc<Mutex<frame_vmo::FrameVmo>>,
25 next_frame: usize,
27 packet_frames: usize,
29 next_packet: std::cell::RefCell<Vec<u8>>,
32 stream_task: StreamConfigOrTask,
34 inspect: inspect::Node,
36}
37
38impl AudioFrameStream {
39 pub fn new(stream: SoftStreamConfig) -> AudioFrameStream {
40 AudioFrameStream {
41 frame_vmo: stream.frame_vmo(),
42 next_frame: 0,
43 packet_frames: stream.packet_frames(),
44 next_packet: Vec::new().into(),
45 stream_task: StreamConfigOrTask::StreamConfig(Box::new(stream)),
46 inspect: Default::default(),
47 }
48 }
49
50 fn poll_task(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
52 if let StreamConfigOrTask::Complete = &self.stream_task {
53 return Poll::Ready(Err(Error::InvalidState));
54 }
55 if let StreamConfigOrTask::Task(task) = &mut self.stream_task {
56 return task.poll_unpin(cx);
57 }
58 self.stream_task.start();
59 self.poll_task(cx)
60 }
61
62 pub fn poll_active_channels(&self, cx: &mut Context<'_>) -> Poll<bool> {
65 self.frame_vmo.lock().poll_active_channels(cx)
66 }
67
68 pub fn watch_active_channels(&self) -> impl Future<Output = bool> + 'static {
70 let frame_vmo = self.frame_vmo.clone();
71 async move { futures::future::poll_fn(|cx| frame_vmo.lock().poll_active_channels(cx)).await }
72 }
73}
74
75impl Stream for AudioFrameStream {
76 type Item = Result<AudioStreamItem>;
77
78 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
79 if let Poll::Ready(r) = self.poll_task(cx) {
80 self.stream_task = StreamConfigOrTask::Complete;
81 return Poll::Ready(r.err().map(Result::Err));
82 }
83 if self.next_packet.borrow().len() == 0 {
84 if let Some(new_len) = self.frame_vmo.lock().bytecount_frames(self.packet_frames) {
85 self.next_packet.borrow_mut().resize(new_len, 0);
86 }
87 }
88 let result = {
89 let mut lock = self.frame_vmo.lock();
90 futures::ready!(lock.poll_read(
91 self.next_frame,
92 self.next_packet.borrow_mut().as_mut_slice(),
93 cx
94 ))
95 };
96
97 match result {
98 Ok(FrameReadResult::Frames { next_frame, missed }) => {
99 if missed > 0 && self.next_frame != 0 {
100 info!("Missed {missed} frames due to slow polling");
101 }
102 self.next_frame = next_frame;
103 let vec_mut = self.next_packet.get_mut();
104 let bytes = vec_mut.len();
105 let frames = std::mem::replace(vec_mut, vec![0; bytes]);
106 Poll::Ready(Some(Ok(AudioStreamItem::Data(frames))))
107 }
108 Ok(FrameReadResult::AudioDisabled) => {
109 self.next_frame = 0;
111 Poll::Ready(Some(Ok(AudioStreamItem::AudioDisabled)))
112 }
113 Err(e) => Poll::Ready(Some(Err(e))),
114 }
115 }
116}
117
118impl FusedStream for AudioFrameStream {
119 fn is_terminated(&self) -> bool {
120 match self.stream_task {
121 StreamConfigOrTask::Complete => true,
122 _ => false,
123 }
124 }
125}
126
127impl Inspect for &mut AudioFrameStream {
128 fn iattach(
129 self,
130 parent: &fuchsia_inspect::Node,
131 name: impl AsRef<str>,
132 ) -> core::result::Result<(), AttachError> {
133 self.inspect = parent.create_child(name.as_ref());
134 if let StreamConfigOrTask::StreamConfig(o) = &mut self.stream_task {
135 return o.iattach(&self.inspect, "stream_config");
136 }
137 Ok(())
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 use async_utils::PollExt;
146 use fidl_fuchsia_hardware_audio::*;
147 use fixture::fixture;
148 use fuchsia_async as fasync;
149 use futures::StreamExt;
150
151 use crate::stream_config::tests::with_audio_frame_stream;
152
153 const TEST_UNIQUE_ID: &[u8; 16] = &[5; 16];
154 const TEST_CLOCK_DOMAIN: u32 = 0x00010203;
155
156 #[fixture(with_audio_frame_stream)]
157 #[fuchsia::test]
158 #[rustfmt::skip]
159 fn soft_audio_out(mut exec: fasync::TestExecutor, stream_config: StreamConfigProxy, mut frame_stream: AudioFrameStream) {
160 let mut frame_fut = frame_stream.next();
161 exec.run_until_stalled(&mut frame_fut).expect_pending("no frames yet");
163
164 let result = exec.run_until_stalled(&mut stream_config.get_properties());
165 assert!(result.is_ready());
166 let props1 = match result {
167 Poll::Ready(Ok(v)) => v,
168 _ => panic!("stream config get properties error"),
169 };
170
171 assert_eq!(props1.unique_id.unwrap(), *TEST_UNIQUE_ID);
172 assert_eq!(props1.is_input.unwrap(), false);
173 assert_eq!(props1.can_mute.unwrap(), false);
174 assert_eq!(props1.can_agc.unwrap(), false);
175 assert_eq!(props1.min_gain_db.unwrap(), 0f32);
176 assert_eq!(props1.max_gain_db.unwrap(), 0f32);
177 assert_eq!(props1.gain_step_db.unwrap(), 0f32);
178 assert_eq!(props1.plug_detect_capabilities.unwrap(), PlugDetectCapabilities::Hardwired);
179 assert_eq!(props1.manufacturer.unwrap(), "Google");
180 assert_eq!(props1.product.unwrap(), "UnitTest");
181 assert_eq!(props1.clock_domain.unwrap(), TEST_CLOCK_DOMAIN);
182
183 let result = exec.run_until_stalled(&mut stream_config.get_supported_formats());
184 assert!(result.is_ready());
185
186 let formats = match result {
187 Poll::Ready(Ok(v)) => v,
188 _ => panic!("get supported formats error"),
189 };
190
191 let first = formats.first().to_owned().expect("supported formats to be present");
192 let pcm = first.pcm_supported_formats.to_owned().expect("pcm format to be present");
193 assert_eq!(pcm.channel_sets.unwrap()[0].attributes.as_ref().unwrap().len(), 2usize);
194 assert_eq!(pcm.sample_formats.unwrap()[0], SampleFormat::PcmSigned);
195 assert_eq!(pcm.bytes_per_sample.unwrap()[0], 2u8);
196 assert_eq!(pcm.valid_bits_per_sample.unwrap()[0], 16u8);
197 assert_eq!(pcm.frame_rates.unwrap()[0], 44100);
198
199 let (ring_buffer, server) = fidl::endpoints::create_proxy::<RingBufferMarker>();
200
201 let format = Format {
202 pcm_format: Some(fidl_fuchsia_hardware_audio::PcmFormat {
203 number_of_channels: 2u8,
204 sample_format: SampleFormat::PcmSigned,
205 bytes_per_sample: 2u8,
206 valid_bits_per_sample: 16u8,
207 frame_rate: 44100,
208 }),
209 ..Default::default()
210 };
211
212 stream_config.create_ring_buffer(&format, server).expect("ring buffer error");
213
214 let props2 = match exec.run_until_stalled(&mut ring_buffer.get_properties()) {
215 Poll::Ready(Ok(v)) => v,
216 x => panic!("expected Ready Ok from get_properties, got {:?}", x),
217 };
218 assert_eq!(props2.needs_cache_flush_or_invalidate, Some(false));
219 assert!(props2.driver_transfer_bytes.unwrap() > 0);
220
221 let result = exec.run_until_stalled(&mut ring_buffer.get_vmo(88200, 0)); assert!(result.is_ready());
223 let reply = match result {
224 Poll::Ready(Ok(Ok(v))) => v,
225 _ => panic!("ring buffer get vmo error"),
226 };
227 let audio_vmo = reply.1;
228
229 let bytes_per_second: usize = 44100 * 2 * 2;
231 let vmo_size = audio_vmo.get_size().expect("size after getbuffer");
232 assert!(bytes_per_second <= vmo_size as usize);
233
234 let mut sent_audio = Vec::new();
236 let mut x: u8 = 0x01;
237 sent_audio.resize_with(bytes_per_second, || {
238 x = x.wrapping_add(2);
239 x
240 });
241
242 assert_eq!(Ok(()), audio_vmo.write(&sent_audio, 0));
243
244 exec.set_fake_time(fasync::MonotonicInstant::from_nanos(42));
245 let _ = exec.wake_expired_timers();
246 let start_time = exec.run_until_stalled(&mut ring_buffer.start());
247 if let Poll::Ready(s) = start_time {
248 assert_eq!(s.expect("start time error"), 42);
249 } else {
250 panic!("start error");
251 }
252
253 exec.run_until_stalled(&mut frame_fut).expect_pending("no frames until time passes");
254
255 exec.set_fake_time(fasync::MonotonicInstant::after(zx::MonotonicDuration::from_millis(500)));
257 let _ = exec.wake_expired_timers();
258
259 let result = exec.run_until_stalled(&mut frame_fut);
260 assert!(result.is_ready());
261 let audio_recv = match result {
262 Poll::Ready(Some(Ok(AudioStreamItem::Data(v)))) => v,
263 x => panic!("expected Ready Ok from frame stream, got {:?}", x),
264 };
265
266 let expect_recv_bytes = bytes_per_second / 10;
268 assert_eq!(expect_recv_bytes, audio_recv.len());
269 assert_eq!(&sent_audio[0..expect_recv_bytes], &audio_recv);
270
271 let result = exec.run_until_stalled(&mut frame_fut);
272 assert!(result.is_ready());
273 let audio_recv = match result {
274 Poll::Ready(Some(Ok(AudioStreamItem::Data(v)))) => v,
275 x => panic!("expected Ready Ok from frame stream, got {:?}", x),
276 };
277
278 let expect_recv_bytes = bytes_per_second / 10;
280 assert_eq!(expect_recv_bytes, audio_recv.len());
281 assert_eq!(&sent_audio[expect_recv_bytes..expect_recv_bytes*2], &audio_recv);
282
283
284 let result = exec.run_until_stalled(&mut ring_buffer.stop());
285 assert!(result.is_ready());
286
287 let result = exec.run_until_stalled(&mut stream_config.watch_gain_state());
289 assert!(result.is_ready());
290 let result = exec.run_until_stalled(&mut stream_config.watch_gain_state());
291 assert!(!result.is_ready());
292
293 let result = exec.run_until_stalled(&mut stream_config.watch_plug_state());
295 assert!(result.is_ready());
296 let result = exec.run_until_stalled(&mut stream_config.watch_plug_state());
297 assert!(!result.is_ready());
298 }
299
300 #[fixture(with_audio_frame_stream)]
301 #[fuchsia::test]
302 fn soft_audio_out_active_channels(
303 mut exec: fasync::TestExecutor,
304 stream_config: StreamConfigProxy,
305 mut frame_stream: AudioFrameStream,
306 ) {
307 let (ring_buffer, server) = fidl::endpoints::create_proxy::<RingBufferMarker>();
308 let format = Format {
309 pcm_format: Some(fidl_fuchsia_hardware_audio::PcmFormat {
310 number_of_channels: 2u8,
311 sample_format: SampleFormat::PcmSigned,
312 bytes_per_sample: 2u8,
313 valid_bits_per_sample: 16u8,
314 frame_rate: 44100,
315 }),
316 ..Default::default()
317 };
318
319 exec.run_until_stalled(&mut frame_stream.next()).expect_pending("no frames yet");
321
322 stream_config.create_ring_buffer(&format, server).expect("ring buffer error");
323
324 let mut active_fut = Box::pin(frame_stream.watch_active_channels());
326 let res = exec.run_until_stalled(&mut active_fut);
327 assert_eq!(res, Poll::Ready(true));
328
329 let mut active_fut = Box::pin(frame_stream.watch_active_channels());
330 let res = exec.run_until_stalled(&mut active_fut);
331 assert_eq!(res, Poll::Pending);
332
333 let res = exec.run_until_stalled(&mut ring_buffer.set_active_channels(0));
336 assert!(res.is_ready());
337
338 let res = exec.run_until_stalled(&mut active_fut);
340 assert_eq!(res, Poll::Ready(false));
341
342 assert!(res.is_ready());
343 let result = exec.run_until_stalled(&mut ring_buffer.get_vmo(88200, 0));
344 assert!(result.is_ready());
345 let reply = match result {
346 Poll::Ready(Ok(Ok(v))) => v,
347 x => panic!("ring buffer get vmo error: {x:?}"),
348 };
349 let audio_vmo = reply.1;
350
351 exec.set_fake_time(fasync::MonotonicInstant::from_nanos(42));
352 let _ = exec.wake_expired_timers();
353 let start_time = exec.run_until_stalled(&mut ring_buffer.start());
354 assert!(start_time.is_ready());
355
356 let mut active_fut = Box::pin(frame_stream.watch_active_channels());
358 let res = exec.run_until_stalled(&mut active_fut);
359 assert_eq!(res, Poll::Pending);
360
361 let mut frame_fut = frame_stream.next();
363 let res = exec.run_until_stalled(&mut frame_fut);
364 assert!(matches!(res, Poll::Ready(Some(Ok(AudioStreamItem::AudioDisabled)))));
365
366 let mut frame_fut = frame_stream.next();
368 exec.set_fake_time(fasync::MonotonicInstant::after(zx::MonotonicDuration::from_millis(
369 500,
370 )));
371 let _ = exec.wake_expired_timers();
372 let res = exec.run_until_stalled(&mut frame_fut);
373 assert!(res.is_pending());
374
375 let bytes_per_second: usize = 44100 * 2 * 2;
377 let sent_audio = vec![0x12; bytes_per_second];
378 assert_eq!(Ok(()), audio_vmo.write(&sent_audio, 0));
379
380 let res = exec.run_until_stalled(&mut ring_buffer.set_active_channels(3));
382 assert!(res.is_ready());
383
384 let res = exec.run_until_stalled(&mut active_fut);
386 assert_eq!(res, Poll::Ready(true));
387
388 let res = exec.run_until_stalled(&mut frame_fut);
390 assert!(matches!(res, Poll::Ready(Some(Ok(AudioStreamItem::Data(_))))));
391 }
392}