1use crate::audio_controller::{AudioController, Request};
6use crate::types::{
7 AudioError, AudioInfo, AudioSettingSource, AudioStream, AudioStreamType, SetAudioStream,
8};
9use async_utils::hanging_get::server;
10use fidl_fuchsia_media::{AudioRenderUsage, AudioRenderUsage2};
11use fidl_fuchsia_settings::{
12 AudioRequest, AudioRequestStream, AudioSettings, AudioSettings2, AudioStreamSettingSource,
13 AudioStreamSettings, AudioStreamSettings2, AudioWatch2Responder, AudioWatchResponder,
14 Error as SettingsError, Volume,
15};
16use futures::StreamExt;
17use futures::channel::mpsc::UnboundedSender;
18use futures::channel::oneshot;
19use settings_common::inspect::event::{
20 RequestType, ResponseType, UsagePublisher, UsageResponsePublisher,
21};
22use settings_common::{trace, trace_guard};
23use {fuchsia_async as fasync, fuchsia_trace as ftrace};
24
25impl From<&AudioInfo> for AudioSettings {
26 fn from(info: &AudioInfo) -> Self {
27 let mut streams = Vec::new();
28 for stream in &info.streams {
29 let stream_settings = AudioStreamSettings::try_from(*stream);
30 if let Ok(stream_settings) = stream_settings {
31 streams.push(stream_settings);
32 }
33 }
34
35 AudioSettings { streams: Some(streams), ..Default::default() }
36 }
37}
38
39impl From<&AudioInfo> for AudioSettings2 {
40 fn from(info: &AudioInfo) -> Self {
41 let mut streams = Vec::new();
42 for stream in &info.streams {
43 streams.push(AudioStreamSettings2::from(*stream));
44 }
45
46 AudioSettings2 { streams: Some(streams), ..Default::default() }
47 }
48}
49
50impl TryFrom<AudioStream> for AudioStreamSettings {
51 type Error = ();
52
53 fn try_from(stream: AudioStream) -> Result<Self, ()> {
54 match AudioRenderUsage::try_from(stream.stream_type) {
55 Err(_) => Err(()),
56 Ok(stream_type) => Ok(AudioStreamSettings {
57 stream: Some(stream_type),
58 source: Some(AudioStreamSettingSource::from(stream.source)),
59 user_volume: Some(Volume {
60 level: Some(stream.user_volume_level),
61 muted: Some(stream.user_volume_muted),
62 ..Default::default()
63 }),
64 ..Default::default()
65 }),
66 }
67 }
68}
69
70impl From<AudioStream> for AudioStreamSettings2 {
71 fn from(stream: AudioStream) -> Self {
72 AudioStreamSettings2 {
73 stream: Some(AudioRenderUsage2::from(stream.stream_type)),
74 source: Some(AudioStreamSettingSource::from(stream.source)),
75 user_volume: Some(Volume {
76 level: Some(stream.user_volume_level),
77 muted: Some(stream.user_volume_muted),
78 ..Default::default()
79 }),
80 ..Default::default()
81 }
82 }
83}
84
85impl From<AudioRenderUsage> for AudioStreamType {
86 fn from(usage: AudioRenderUsage) -> Self {
87 match usage {
88 AudioRenderUsage::Background => AudioStreamType::Background,
89 AudioRenderUsage::Communication => AudioStreamType::Communication,
90 AudioRenderUsage::Interruption => AudioStreamType::Interruption,
91 AudioRenderUsage::Media => AudioStreamType::Media,
92 AudioRenderUsage::SystemAgent => AudioStreamType::SystemAgent,
93 }
94 }
95}
96
97impl TryFrom<AudioStreamType> for AudioRenderUsage {
98 type Error = ();
99 fn try_from(usage: AudioStreamType) -> Result<Self, Self::Error> {
100 match usage {
101 AudioStreamType::Accessibility => Err(()),
102 AudioStreamType::Background => Ok(AudioRenderUsage::Background),
103 AudioStreamType::Communication => Ok(AudioRenderUsage::Communication),
104 AudioStreamType::Interruption => Ok(AudioRenderUsage::Interruption),
105 AudioStreamType::Media => Ok(AudioRenderUsage::Media),
106 AudioStreamType::SystemAgent => Ok(AudioRenderUsage::SystemAgent),
107 }
108 }
109}
110
111impl From<AudioStreamType> for AudioRenderUsage2 {
112 fn from(usage: AudioStreamType) -> Self {
113 match usage {
114 AudioStreamType::Accessibility => AudioRenderUsage2::Accessibility,
115 AudioStreamType::Background => AudioRenderUsage2::Background,
116 AudioStreamType::Communication => AudioRenderUsage2::Communication,
117 AudioStreamType::Interruption => AudioRenderUsage2::Interruption,
118 AudioStreamType::Media => AudioRenderUsage2::Media,
119 AudioStreamType::SystemAgent => AudioRenderUsage2::SystemAgent,
120 }
121 }
122}
123
124impl TryFrom<AudioRenderUsage2> for AudioStreamType {
125 type Error = ();
126 fn try_from(usage: AudioRenderUsage2) -> Result<Self, Self::Error> {
127 match usage {
128 AudioRenderUsage2::Accessibility => Ok(AudioStreamType::Accessibility),
129 AudioRenderUsage2::Background => Ok(AudioStreamType::Background),
130 AudioRenderUsage2::Communication => Ok(AudioStreamType::Communication),
131 AudioRenderUsage2::Interruption => Ok(AudioStreamType::Interruption),
132 AudioRenderUsage2::Media => Ok(AudioStreamType::Media),
133 AudioRenderUsage2::SystemAgent => Ok(AudioStreamType::SystemAgent),
134 _ => Err(()),
135 }
136 }
137}
138
139impl From<AudioStreamSettingSource> for AudioSettingSource {
140 fn from(source: AudioStreamSettingSource) -> Self {
141 match source {
142 AudioStreamSettingSource::User => AudioSettingSource::User,
143 AudioStreamSettingSource::System => AudioSettingSource::System,
144 AudioStreamSettingSource::SystemWithFeedback => AudioSettingSource::SystemWithFeedback,
145 }
146 }
147}
148
149impl From<AudioSettingSource> for AudioStreamSettingSource {
150 fn from(source: AudioSettingSource) -> Self {
151 match source {
152 AudioSettingSource::User => AudioStreamSettingSource::User,
153 AudioSettingSource::System => AudioStreamSettingSource::System,
154 AudioSettingSource::SystemWithFeedback => AudioStreamSettingSource::SystemWithFeedback,
155 }
156 }
157}
158
159#[allow(clippy::enum_variant_names)]
161#[derive(thiserror::Error, Debug, PartialEq)]
162enum Error {
163 #[error("request has no streams")]
164 NoStreams,
165 #[error("missing user_volume at stream {0}")]
166 NoUserVolume(usize),
167 #[error("missing user_volume.level and user_volume.muted at stream {0}")]
168 MissingVolumeAndMuted(usize),
169 #[error("missing stream at stream {0}")]
170 NoStreamType(usize),
171 #[error("missing source at stream {0}")]
172 NoSource(usize),
173 #[error("request has an unknown stream type")]
174 UnrecognizedStreamType,
175}
176
177fn to_request(settings: AudioSettings, id: ftrace::Id) -> Result<Vec<SetAudioStream>, Error> {
178 trace!(id, c"to_request");
179 settings
180 .streams
181 .map(|streams| {
182 streams
183 .into_iter()
184 .enumerate()
185 .map(|(i, stream)| {
186 let user_volume = stream.user_volume.ok_or(Error::NoUserVolume(i))?;
187 let user_volume_level = user_volume.level;
188 let user_volume_muted = user_volume.muted;
189 let stream_type = stream.stream.ok_or(Error::NoStreamType(i))?.into();
190 let source = stream.source.ok_or(Error::NoSource(i))?.into();
191 let request = SetAudioStream {
192 stream_type,
193 source,
194 user_volume_level,
195 user_volume_muted,
196 };
197 if request.is_valid_payload() {
198 Ok(request)
199 } else {
200 Err(Error::MissingVolumeAndMuted(i))
201 }
202 })
203 .collect::<Result<Vec<_>, _>>()
204 })
205 .unwrap_or(Err(Error::NoStreams))
206}
207
208fn to_request2(settings: AudioSettings2, id: ftrace::Id) -> Result<Vec<SetAudioStream>, Error> {
209 trace!(id, c"to_request2");
210 settings
211 .streams
212 .map(|streams| {
213 streams
214 .into_iter()
215 .enumerate()
216 .map(|(i, stream)| {
217 let user_volume = stream.user_volume.ok_or(Error::NoUserVolume(i))?;
218 let user_volume_level = user_volume.level;
219 let user_volume_muted = user_volume.muted;
220 let stream_type = match stream.stream.ok_or(Error::NoStreamType(i))?.try_into()
221 {
222 Ok(stream_type) => Ok(stream_type),
223 Err(_) => Err(Error::UnrecognizedStreamType),
224 }?;
225 let source = stream.source.ok_or(Error::NoSource(i))?.into();
226 let request = SetAudioStream {
227 stream_type,
228 source,
229 user_volume_level,
230 user_volume_muted,
231 };
232 if request.is_valid_payload() {
233 Ok(request)
234 } else {
235 Err(Error::MissingVolumeAndMuted(i))
236 }
237 })
238 .collect::<Result<Vec<_>, _>>()
239 })
240 .unwrap_or(Err(Error::NoStreams))
241}
242
243pub(crate) type SubscriberObject = (UsageResponsePublisher<AudioInfo>, AudioWatchResponder);
244type HangingGetFn = fn(&AudioInfo, SubscriberObject) -> bool;
245pub(crate) type HangingGet = server::HangingGet<AudioInfo, SubscriberObject, HangingGetFn>;
246pub(crate) type Publisher = server::Publisher<AudioInfo, SubscriberObject, HangingGetFn>;
247pub(crate) type Subscriber = server::Subscriber<AudioInfo, SubscriberObject, HangingGetFn>;
248
249pub(crate) type SubscriberObject2 = (UsageResponsePublisher<AudioInfo>, AudioWatch2Responder);
250type HangingGetFn2 = fn(&AudioInfo, SubscriberObject2) -> bool;
251pub(crate) type HangingGet2 = server::HangingGet<AudioInfo, SubscriberObject2, HangingGetFn2>;
252pub(crate) type Publisher2 = server::Publisher<AudioInfo, SubscriberObject2, HangingGetFn2>;
253pub(crate) type Subscriber2 = server::Subscriber<AudioInfo, SubscriberObject2, HangingGetFn2>;
254
255pub struct AudioFidlHandler {
256 hanging_get: HangingGet,
257 hanging_get2: HangingGet2,
258 controller_tx: UnboundedSender<Request>,
259 usage_publisher: UsagePublisher<AudioInfo>,
260}
261
262impl AudioFidlHandler {
263 pub(crate) fn new(
264 audio_controller: &mut AudioController,
265 usage_publisher: UsagePublisher<AudioInfo>,
266 controller_tx: UnboundedSender<Request>,
267 initial_value: AudioInfo,
268 ) -> Self {
269 let hanging_get = HangingGet::new(initial_value.clone(), Self::hanging_get);
270 let hanging_get2 = HangingGet2::new(initial_value, Self::hanging_get2);
271 audio_controller
272 .register_publishers(hanging_get.new_publisher(), hanging_get2.new_publisher());
273 Self { hanging_get, hanging_get2, controller_tx, usage_publisher }
274 }
275
276 fn hanging_get(info: &AudioInfo, (usage_responder, responder): SubscriberObject) -> bool {
277 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
278 if let Err(e) = responder.send(&AudioSettings::from(info)) {
279 log::warn!("Failed to respond to watch request: {e:?}");
280 return false;
281 }
282 true
283 }
284
285 fn hanging_get2(info: &AudioInfo, (usage_responder, responder): SubscriberObject2) -> bool {
286 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
287 if let Err(e) = responder.send(&AudioSettings2::from(info)) {
288 log::warn!("Failed to respond to watch request: {e:?}");
289 return false;
290 }
291 true
292 }
293
294 pub fn handle_stream(&mut self, mut stream: AudioRequestStream) {
295 let request_handler = RequestHandler {
296 subscriber: self.hanging_get.new_subscriber(),
297 subscriber2: self.hanging_get2.new_subscriber(),
298 controller_tx: self.controller_tx.clone(),
299 usage_publisher: self.usage_publisher.clone(),
300 };
301 fasync::Task::local(async move {
302 while let Some(Ok(request)) = stream.next().await {
303 request_handler.handle_request(request).await;
304 }
305 })
306 .detach();
307 }
308}
309
310#[derive(Debug)]
311enum HandlerError {
312 AlreadySubscribed,
313 InvalidArgument(
314 #[allow(dead_code)] Error,
316 ),
317 ControllerStopped,
318 Controller(AudioError),
319}
320
321impl From<&HandlerError> for ResponseType {
322 fn from(error: &HandlerError) -> Self {
323 match error {
324 HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
325 HandlerError::InvalidArgument(_) => ResponseType::InvalidArgument,
326 HandlerError::ControllerStopped => ResponseType::UnexpectedError,
327 HandlerError::Controller(e) => ResponseType::from(e),
328 }
329 }
330}
331
332struct RequestHandler {
333 subscriber: Subscriber,
334 subscriber2: Subscriber2,
335 controller_tx: UnboundedSender<Request>,
336 usage_publisher: UsagePublisher<AudioInfo>,
337}
338
339impl RequestHandler {
340 async fn handle_request(&self, request: AudioRequest) {
341 match request {
342 AudioRequest::Watch { responder } => {
343 let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
344 if let Err((usage_res, responder)) =
345 self.subscriber.register2((usage_res, responder))
346 {
347 let e = HandlerError::AlreadySubscribed;
348 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
349 drop(responder);
350 }
351 }
352 AudioRequest::Watch2 { responder } => {
353 let usage_res =
354 self.usage_publisher.request("Watch2".to_string(), RequestType::Get);
355 if let Err((usage_res, responder)) =
356 self.subscriber2.register2((usage_res, responder))
357 {
358 let e = HandlerError::AlreadySubscribed;
359 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
360 drop(responder);
361 }
362 }
363 AudioRequest::Set { settings, responder } => {
364 let trace_id = ftrace::Id::new();
365 let _guard = trace_guard!(trace_id, c"audio fidl handler set");
366 let usage_res = self
367 .usage_publisher
368 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
369 if let Err(e) = self.set(settings, trace_id).await {
370 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
371 let _ = responder.send(Err(SettingsError::Failed));
372 } else {
373 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
374 let _ = responder.send(Ok(()));
375 }
376 }
377 AudioRequest::Set2 { settings, responder } => {
378 let trace_id = ftrace::Id::new();
379 let _guard = trace_guard!(trace_id, c"audio fidl handler set2");
380 let usage_res = self
381 .usage_publisher
382 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
383 if let Err(e) = self.set2(settings, trace_id).await {
384 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
385 let _ = responder.send(Err(SettingsError::Failed));
386 } else {
387 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
388 let _ = responder.send(Ok(()));
389 }
390 }
391 _ => {
392 log::error!("Unknown audio request");
393 }
394 }
395 }
396
397 async fn set(&self, settings: AudioSettings, trace_id: ftrace::Id) -> Result<(), HandlerError> {
398 let (set_tx, set_rx) = oneshot::channel();
399 let input_devices =
400 to_request(settings, trace_id).map_err(HandlerError::InvalidArgument)?;
401 self.controller_tx
402 .unbounded_send(Request::Set(input_devices, trace_id, set_tx))
403 .map_err(|_| HandlerError::ControllerStopped)?;
404 set_rx
405 .await
406 .map_err(|_| HandlerError::ControllerStopped)
407 .and_then(|res| res.map_err(HandlerError::Controller))
408 }
409
410 async fn set2(
411 &self,
412 settings: AudioSettings2,
413 trace_id: ftrace::Id,
414 ) -> Result<(), HandlerError> {
415 let (set_tx, set_rx) = oneshot::channel();
416 let input_devices =
417 to_request2(settings, trace_id).map_err(HandlerError::InvalidArgument)?;
418 self.controller_tx
419 .unbounded_send(Request::Set(input_devices, trace_id, set_tx))
420 .map_err(|_| HandlerError::ControllerStopped)?;
421 set_rx
422 .await
423 .map_err(|_| HandlerError::ControllerStopped)
424 .and_then(|res| res.map_err(HandlerError::Controller))
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 fn test_stream() -> AudioStreamSettings {
433 AudioStreamSettings {
434 stream: Some(fidl_fuchsia_media::AudioRenderUsage::Media),
435 source: Some(AudioStreamSettingSource::User),
436 user_volume: Some(Volume {
437 level: Some(0.6),
438 muted: Some(false),
439 ..Default::default()
440 }),
441 ..Default::default()
442 }
443 }
444
445 fn test_stream2() -> AudioStreamSettings2 {
446 AudioStreamSettings2 {
447 stream: Some(fidl_fuchsia_media::AudioRenderUsage2::Media),
448 source: Some(AudioStreamSettingSource::User),
449 user_volume: Some(Volume {
450 level: Some(0.6),
451 muted: Some(false),
452 ..Default::default()
453 }),
454 ..Default::default()
455 }
456 }
457
458 #[fuchsia::test]
460 fn test_request_from_settings_empty() {
461 let id = ftrace::Id::new();
462 let request = to_request(AudioSettings::default(), id);
463
464 assert_eq!(request, Err(Error::NoStreams));
465 }
466
467 #[fuchsia::test]
469 fn test_request2_from_settings_empty() {
470 let id = ftrace::Id::new();
471 let request = to_request2(AudioSettings2::default(), id);
472
473 assert_eq!(request, Err(Error::NoStreams));
474 }
475
476 #[fuchsia::test]
478 fn test_request_missing_user_volume() {
479 let mut stream = test_stream();
480 stream.user_volume = None;
481
482 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
483
484 let id = ftrace::Id::new();
485 let request = to_request(audio_settings, id);
486
487 assert_eq!(request, Err(Error::NoUserVolume(0)));
488 }
489
490 #[fuchsia::test]
492 fn test_request2_missing_user_volume() {
493 let mut stream = test_stream2();
494 stream.user_volume = None;
495
496 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
497
498 let id = ftrace::Id::new();
499 let request = to_request2(audio_settings, id);
500
501 assert_eq!(request, Err(Error::NoUserVolume(0)));
502 }
503
504 #[fuchsia::test]
506 fn test_request_missing_stream_type() {
507 let mut stream = test_stream();
508 stream.stream = None;
509
510 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
511
512 let id = ftrace::Id::new();
513 let request = to_request(audio_settings, id);
514
515 assert_eq!(request, Err(Error::NoStreamType(0)));
516 }
517
518 #[fuchsia::test]
520 fn test_request2_missing_stream_type() {
521 let mut stream = test_stream2();
522 stream.stream = None;
523
524 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
525
526 let id = ftrace::Id::new();
527 let request = to_request2(audio_settings, id);
528
529 assert_eq!(request, Err(Error::NoStreamType(0)));
530 }
531
532 #[fuchsia::test]
534 fn test_request_missing_source() {
535 let mut stream = test_stream();
536 stream.source = None;
537
538 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
539
540 let id = ftrace::Id::new();
541 let request = to_request(audio_settings, id);
542
543 assert_eq!(request, Err(Error::NoSource(0)));
544 }
545
546 #[fuchsia::test]
548 fn test_request2_missing_source() {
549 let mut stream = test_stream2();
550 stream.source = None;
551
552 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
553
554 let id = ftrace::Id::new();
555 let request = to_request2(audio_settings, id);
556
557 assert_eq!(request, Err(Error::NoSource(0)));
558 }
559
560 #[fuchsia::test]
563 fn test_request_missing_user_volume_level_and_muted() {
564 let mut stream = test_stream();
565 stream.user_volume = Some(Volume { level: None, muted: None, ..Default::default() });
566
567 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
568
569 let id = ftrace::Id::new();
570 let request = to_request(audio_settings, id);
571
572 assert_eq!(request, Err(Error::MissingVolumeAndMuted(0)));
573 }
574
575 #[fuchsia::test]
578 fn test_request2_missing_user_volume_level_and_muted() {
579 let mut stream = test_stream2();
580 stream.user_volume = Some(Volume { level: None, muted: None, ..Default::default() });
581
582 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
583
584 let id = ftrace::Id::new();
585 let request = to_request2(audio_settings, id);
586
587 assert_eq!(request, Err(Error::MissingVolumeAndMuted(0)));
588 }
589}