Skip to main content

settings_audio/
audio_fidl_handler.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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// Clippy warns about all variants starting with the same prefix `No`.
161#[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        // Error used by Debug impl for inspect logs.
322        #[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    // Verifies that an entirely empty settings request results in an appropriate error.
466    #[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    // Verifies that an entirely empty settings request2 results in an appropriate error.
475    #[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    // Verifies that a settings request missing user volume info results in an appropriate error.
484    #[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    // Verifies that a settings request2 missing user volume info results in an appropriate error.
498    #[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    // Verifies that a settings request missing the stream type results in an appropriate error.
512    #[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    // Verifies that a settings request2 missing the stream type results in an appropriate error.
526    #[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    // Verifies that a settings request missing the source results in an appropriate error.
540    #[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    // Verifies that a settings request2 missing the source results in an appropriate error.
554    #[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    // Verifies that a settings request missing both the user volume level and mute state results in
568    // an appropriate error.
569    #[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    // Verifies that a settings request2 missing both the user volume level and mute state results in
583    // an appropriate error.
584    #[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}