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