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    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// 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 = (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        // Error used by Debug impl for inspect logs.
320        #[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    // Verifies that an entirely empty settings request results in an appropriate error.
464    #[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    // Verifies that an entirely empty settings request2 results in an appropriate error.
473    #[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    // Verifies that a settings request missing user volume info results in an appropriate error.
482    #[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    // Verifies that a settings request2 missing user volume info results in an appropriate error.
496    #[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    // Verifies that a settings request missing the stream type results in an appropriate error.
510    #[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    // Verifies that a settings request2 missing the stream type results in an appropriate error.
524    #[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    // Verifies that a settings request missing the source results in an appropriate error.
538    #[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    // Verifies that a settings request2 missing the source results in an appropriate error.
552    #[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    // Verifies that a settings request missing both the user volume level and mute state results in
566    // an appropriate error.
567    #[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    // Verifies that a settings request2 missing both the user volume level and mute state results in
581    // an appropriate error.
582    #[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}