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 RequestType, ResponseType, UsagePublisher, UsageResponsePublisher,
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 = (UsageResponsePublisher<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 = (UsageResponsePublisher<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, (usage_responder, responder): SubscriberObject) -> bool {
278 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
279 if let Err(e) = responder.send(&AudioSettings::from(info)) {
280 log::warn!("Failed to respond to watch request: {e:?}");
281 return false;
282 }
283 true
284 }
285
286 fn hanging_get2(info: &AudioInfo, (usage_responder, responder): SubscriberObject2) -> bool {
287 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
288 if let Err(e) = responder.send(&AudioSettings2::from(info)) {
289 log::warn!("Failed to respond to watch request: {e:?}");
290 return false;
291 }
292 true
293 }
294
295 pub fn handle_stream(&mut self, mut stream: AudioRequestStream) {
296 let request_handler = std::rc::Rc::new(RequestHandler {
297 subscriber: self.hanging_get.new_subscriber(),
298 subscriber2: self.hanging_get2.new_subscriber(),
299 controller_tx: self.controller_tx.clone(),
300 usage_publisher: self.usage_publisher.clone(),
301 });
302 fasync::Task::local(async move {
303 while let Some(Ok(request)) = stream.next().await {
304 let request_handler = std::rc::Rc::clone(&request_handler);
305 fasync::Task::local(async move {
306 request_handler.handle_request(request).await;
307 })
308 .detach();
309 }
310 })
311 .detach();
312 }
313}
314
315#[derive(Debug)]
316enum HandlerError {
317 AlreadySubscribed,
318 InvalidArgument(
319 #[allow(dead_code)] Error,
321 ),
322 ControllerStopped,
323 Controller(AudioError),
324}
325
326impl From<&HandlerError> for ResponseType {
327 fn from(error: &HandlerError) -> Self {
328 match error {
329 HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
330 HandlerError::InvalidArgument(_) => ResponseType::InvalidArgument,
331 HandlerError::ControllerStopped => ResponseType::UnexpectedError,
332 HandlerError::Controller(e) => ResponseType::from(e),
333 }
334 }
335}
336
337struct RequestHandler {
338 subscriber: Subscriber,
339 subscriber2: Subscriber2,
340 controller_tx: UnboundedSender<Request>,
341 usage_publisher: UsagePublisher<AudioInfo>,
342}
343
344impl RequestHandler {
345 async fn handle_request(&self, request: AudioRequest) {
346 match request {
347 AudioRequest::Watch { responder } => {
348 let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
349 if let Err((usage_res, responder)) =
350 self.subscriber.register2((usage_res, responder))
351 {
352 let e = HandlerError::AlreadySubscribed;
353 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
354 drop(responder);
355 }
356 }
357 AudioRequest::Watch2 { responder } => {
358 let usage_res =
359 self.usage_publisher.request("Watch2".to_string(), RequestType::Get);
360 if let Err((usage_res, responder)) =
361 self.subscriber2.register2((usage_res, responder))
362 {
363 let e = HandlerError::AlreadySubscribed;
364 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
365 drop(responder);
366 }
367 }
368 AudioRequest::Set { settings, responder } => {
369 let trace_id = ftrace::Id::new();
370 let _guard = trace_guard!(trace_id, c"audio fidl handler set");
371 let usage_res = self
372 .usage_publisher
373 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
374 if let Err(e) = self.set(settings, trace_id).await {
375 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
376 let _ = responder.send(Err(SettingsError::Failed));
377 } else {
378 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
379 let _ = responder.send(Ok(()));
380 }
381 }
382 AudioRequest::Set2 { settings, responder } => {
383 let trace_id = ftrace::Id::new();
384 let _guard = trace_guard!(trace_id, c"audio fidl handler set2");
385 let usage_res = self
386 .usage_publisher
387 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
388 if let Err(e) = self.set2(settings, trace_id).await {
389 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
390 let _ = responder.send(Err(SettingsError::Failed));
391 } else {
392 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
393 let _ = responder.send(Ok(()));
394 }
395 }
396 _ => {
397 log::error!("Unknown audio request");
398 }
399 }
400 }
401
402 async fn set(&self, settings: AudioSettings, trace_id: ftrace::Id) -> Result<(), HandlerError> {
403 let (set_tx, set_rx) = oneshot::channel();
404 let input_devices =
405 to_request(settings, trace_id).map_err(HandlerError::InvalidArgument)?;
406 self.controller_tx
407 .unbounded_send(Request::Set(input_devices, trace_id, set_tx))
408 .map_err(|_| HandlerError::ControllerStopped)?;
409 set_rx
410 .await
411 .map_err(|_| HandlerError::ControllerStopped)
412 .and_then(|res| res.map_err(HandlerError::Controller))
413 }
414
415 async fn set2(
416 &self,
417 settings: AudioSettings2,
418 trace_id: ftrace::Id,
419 ) -> Result<(), HandlerError> {
420 let (set_tx, set_rx) = oneshot::channel();
421 let input_devices =
422 to_request2(settings, trace_id).map_err(HandlerError::InvalidArgument)?;
423 self.controller_tx
424 .unbounded_send(Request::Set(input_devices, trace_id, set_tx))
425 .map_err(|_| HandlerError::ControllerStopped)?;
426 set_rx
427 .await
428 .map_err(|_| HandlerError::ControllerStopped)
429 .and_then(|res| res.map_err(HandlerError::Controller))
430 }
431}
432
433#[cfg(test)]
434mod tests {
435 use super::*;
436
437 fn test_stream() -> AudioStreamSettings {
438 AudioStreamSettings {
439 stream: Some(fidl_fuchsia_media::AudioRenderUsage::Media),
440 source: Some(AudioStreamSettingSource::User),
441 user_volume: Some(Volume {
442 level: Some(0.6),
443 muted: Some(false),
444 ..Default::default()
445 }),
446 ..Default::default()
447 }
448 }
449
450 fn test_stream2() -> AudioStreamSettings2 {
451 AudioStreamSettings2 {
452 stream: Some(fidl_fuchsia_media::AudioRenderUsage2::Media),
453 source: Some(AudioStreamSettingSource::User),
454 user_volume: Some(Volume {
455 level: Some(0.6),
456 muted: Some(false),
457 ..Default::default()
458 }),
459 ..Default::default()
460 }
461 }
462
463 #[fuchsia::test]
465 fn test_request_from_settings_empty() {
466 let id = ftrace::Id::new();
467 let request = to_request(AudioSettings::default(), id);
468
469 assert_eq!(request, Err(Error::NoStreams));
470 }
471
472 #[fuchsia::test]
474 fn test_request2_from_settings_empty() {
475 let id = ftrace::Id::new();
476 let request = to_request2(AudioSettings2::default(), id);
477
478 assert_eq!(request, Err(Error::NoStreams));
479 }
480
481 #[fuchsia::test]
483 fn test_request_missing_user_volume() {
484 let mut stream = test_stream();
485 stream.user_volume = None;
486
487 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
488
489 let id = ftrace::Id::new();
490 let request = to_request(audio_settings, id);
491
492 assert_eq!(request, Err(Error::NoUserVolume(0)));
493 }
494
495 #[fuchsia::test]
497 fn test_request2_missing_user_volume() {
498 let mut stream = test_stream2();
499 stream.user_volume = None;
500
501 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
502
503 let id = ftrace::Id::new();
504 let request = to_request2(audio_settings, id);
505
506 assert_eq!(request, Err(Error::NoUserVolume(0)));
507 }
508
509 #[fuchsia::test]
511 fn test_request_missing_stream_type() {
512 let mut stream = test_stream();
513 stream.stream = None;
514
515 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
516
517 let id = ftrace::Id::new();
518 let request = to_request(audio_settings, id);
519
520 assert_eq!(request, Err(Error::NoStreamType(0)));
521 }
522
523 #[fuchsia::test]
525 fn test_request2_missing_stream_type() {
526 let mut stream = test_stream2();
527 stream.stream = None;
528
529 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
530
531 let id = ftrace::Id::new();
532 let request = to_request2(audio_settings, id);
533
534 assert_eq!(request, Err(Error::NoStreamType(0)));
535 }
536
537 #[fuchsia::test]
539 fn test_request_missing_source() {
540 let mut stream = test_stream();
541 stream.source = None;
542
543 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
544
545 let id = ftrace::Id::new();
546 let request = to_request(audio_settings, id);
547
548 assert_eq!(request, Err(Error::NoSource(0)));
549 }
550
551 #[fuchsia::test]
553 fn test_request2_missing_source() {
554 let mut stream = test_stream2();
555 stream.source = None;
556
557 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
558
559 let id = ftrace::Id::new();
560 let request = to_request2(audio_settings, id);
561
562 assert_eq!(request, Err(Error::NoSource(0)));
563 }
564
565 #[fuchsia::test]
568 fn test_request_missing_user_volume_level_and_muted() {
569 let mut stream = test_stream();
570 stream.user_volume = Some(Volume { level: None, muted: None, ..Default::default() });
571
572 let audio_settings = AudioSettings { streams: Some(vec![stream]), ..Default::default() };
573
574 let id = ftrace::Id::new();
575 let request = to_request(audio_settings, id);
576
577 assert_eq!(request, Err(Error::MissingVolumeAndMuted(0)));
578 }
579
580 #[fuchsia::test]
583 fn test_request2_missing_user_volume_level_and_muted() {
584 let mut stream = test_stream2();
585 stream.user_volume = Some(Volume { level: None, muted: None, ..Default::default() });
586
587 let audio_settings = AudioSettings2 { streams: Some(vec![stream]), ..Default::default() };
588
589 let id = ftrace::Id::new();
590 let request = to_request2(audio_settings, id);
591
592 assert_eq!(request, Err(Error::MissingVolumeAndMuted(0)));
593 }
594}