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