| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| crate::switchboard::base::{AudioStream, AudioStreamType}, |
| fidl::{self, endpoints::create_proxy}, |
| fidl_fuchsia_media::{AudioRenderUsage, Usage}, |
| fidl_fuchsia_media_audio::VolumeControlProxy, |
| fuchsia_async as fasync, |
| fuchsia_syslog::fx_log_err, |
| futures::{FutureExt, TryFutureExt, TryStreamExt}, |
| }; |
| |
| // Stores an AudioStream and a VolumeControl proxy bound to the AudioCore |
| // service for |stored_stream|'s stream type. |proxy| is set to None if it |
| // fails to bind to the AudioCore service. |
| pub struct StreamVolumeControl { |
| pub stored_stream: AudioStream, |
| proxy: Option<VolumeControlProxy>, |
| audio_service: fidl_fuchsia_media::AudioCoreProxy, |
| } |
| |
| // TODO(fxb/37777): Listen for volume changes from Volume Control. |
| impl StreamVolumeControl { |
| pub fn create(audio_service: &fidl_fuchsia_media::AudioCoreProxy, stream: AudioStream) -> Self { |
| StreamVolumeControl { |
| stored_stream: stream, |
| proxy: bind_volume_control(&audio_service, stream.stream_type), |
| audio_service: audio_service.clone(), |
| } |
| } |
| |
| pub async fn set_volume(&mut self, stream: AudioStream) { |
| assert_eq!(self.stored_stream.stream_type, stream.stream_type); |
| |
| // If |proxy| is set to None, then try to create and bind a new VolumeControl. If it |
| // fails, log an error and don't set the volume. |
| if self.proxy.is_none() { |
| self.proxy = bind_volume_control(&self.audio_service, stream.stream_type); |
| if self.proxy.is_none() { |
| fx_log_err!("failed to bind volume control"); |
| return; |
| } |
| } |
| |
| let proxy = self.proxy.as_ref().unwrap(); |
| |
| if self.stored_stream.user_volume_level != stream.user_volume_level { |
| proxy.set_volume(stream.user_volume_level).unwrap_or_else(move |e| { |
| fx_log_err!("failed to set the volume level, {}", e); |
| }); |
| } |
| |
| if self.stored_stream.user_volume_muted != stream.user_volume_muted { |
| proxy.set_mute(stream.user_volume_muted).unwrap_or_else(move |e| { |
| fx_log_err!("failed to mute the volume, {}", e); |
| }); |
| } |
| |
| self.stored_stream = stream; |
| } |
| } |
| |
| fn bind_volume_control( |
| audio_service: &fidl_fuchsia_media::AudioCoreProxy, |
| stream_type: AudioStreamType, |
| ) -> Option<VolumeControlProxy> { |
| let (vol_control_proxy, server_end) = create_proxy().unwrap(); |
| let mut usage = Usage::RenderUsage(AudioRenderUsage::from(stream_type)); |
| |
| if let Err(err) = audio_service.bind_usage_volume_control(&mut usage, server_end) { |
| fx_log_err!("failed to bind volume control for usage, {}", err); |
| return None; |
| } |
| |
| // TODO(fxb/37777): Update |stored_stream| in StreamVolumeControl and send a notification |
| // when we receive an update. |
| let proxy_clone = vol_control_proxy.clone(); |
| let consume_volume_events = async move { |
| let mut volume_events = proxy_clone.take_event_stream(); |
| while let Some(_) = volume_events.try_next().await? {} |
| |
| Ok(()) |
| }; |
| fasync::spawn( |
| consume_volume_events |
| .map_err(|e: fidl::Error| fx_log_err!("Volume event stream failed: {}", e)) |
| .map(|_| ()), |
| ); |
| |
| Some(vol_control_proxy) |
| } |