settings/audio/
stream_volume_control.rs1use crate::audio::types::AudioStream;
6use crate::audio::utils::round_volume_level;
7use crate::base::SettingType;
8use crate::event::{Event, Publisher};
9use crate::handler::setting_handler::ControllerError;
10use crate::service_context::ExternalServiceProxy;
11use crate::{clock, trace, trace_guard};
12use fidl::endpoints::create_proxy;
13use fidl_fuchsia_media::Usage2;
14use fidl_fuchsia_media_audio::VolumeControlProxy;
15use futures::channel::oneshot::Sender;
16use futures::TryStreamExt;
17use settings_common::call;
18use settings_common::service_context::ExternalServiceEvent;
19use std::rc::Rc;
20use {fuchsia_async as fasync, fuchsia_trace as ftrace};
21
22const PUBLISHER_EVENT_NAME: &str = "volume_control_events";
23const CONTROLLER_ERROR_DEPENDENCY: &str = "fuchsia.media.audio";
24const UNKNOWN_INSPECT_STRING: &str = "unknown";
25
26pub(crate) type ExitAction = Rc<dyn Fn()>;
28
29pub struct StreamVolumeControl {
34 pub stored_stream: AudioStream,
35 proxy: Option<VolumeControlProxy>,
36 audio_service: ExternalServiceProxy<fidl_fuchsia_media::AudioCoreProxy>,
37 publisher: Option<Publisher>,
38 early_exit_action: Option<ExitAction>,
39 listen_exit_tx: Option<Sender<()>>,
40}
41
42impl Drop for StreamVolumeControl {
43 fn drop(&mut self) {
44 if let Some(exit_tx) = self.listen_exit_tx.take() {
45 if exit_tx.is_canceled() {
47 return;
48 }
49
50 exit_tx.send(()).unwrap_or_else(|_| {
53 log::warn!("StreamVolumeControl::drop, exit_tx failed to send exit signal")
54 });
55 }
56 }
57}
58
59impl StreamVolumeControl {
60 pub(crate) async fn create(
61 id: ftrace::Id,
62 audio_service: &ExternalServiceProxy<fidl_fuchsia_media::AudioCoreProxy>,
63 stream: AudioStream,
64 early_exit_action: Option<ExitAction>,
65 publisher: Option<Publisher>,
66 ) -> Result<Self, ControllerError> {
67 assert!(stream.has_valid_volume_level());
70
71 trace!(id, c"StreamVolumeControl ctor");
72 let mut control = StreamVolumeControl {
73 stored_stream: stream,
74 proxy: None,
75 audio_service: audio_service.clone(),
76 publisher,
77 listen_exit_tx: None,
78 early_exit_action,
79 };
80
81 control.bind_volume_control(id).await?;
82 Ok(control)
83 }
84
85 pub(crate) async fn set_volume(
86 &mut self,
87 id: ftrace::Id,
88 stream: AudioStream,
89 ) -> Result<(), ControllerError> {
90 assert_eq!(self.stored_stream.stream_type, stream.stream_type);
91 assert!(stream.has_valid_volume_level());
94
95 if self.proxy.is_none() {
97 self.bind_volume_control(id).await?;
98 }
99
100 let mut new_stream_value = stream;
102 new_stream_value.user_volume_level = round_volume_level(stream.user_volume_level);
103
104 let proxy = self.proxy.as_ref().expect("no volume control proxy");
105
106 if (self.stored_stream.user_volume_level - new_stream_value.user_volume_level).abs()
107 > f32::EPSILON
108 {
109 if let Err(e) = proxy.set_volume(new_stream_value.user_volume_level) {
110 self.stored_stream = new_stream_value;
111 return Err(ControllerError::ExternalFailure(
112 SettingType::Audio,
113 CONTROLLER_ERROR_DEPENDENCY.into(),
114 "set volume".into(),
115 format!("{e:?}").into(),
116 ));
117 }
118 }
119
120 if self.stored_stream.user_volume_muted != new_stream_value.user_volume_muted {
121 if let Err(e) = proxy.set_mute(stream.user_volume_muted) {
122 self.stored_stream = new_stream_value;
123 return Err(ControllerError::ExternalFailure(
124 SettingType::Audio,
125 CONTROLLER_ERROR_DEPENDENCY.into(),
126 "set mute".into(),
127 format!("{e:?}").into(),
128 ));
129 }
130 }
131
132 self.stored_stream = new_stream_value;
133 Ok(())
134 }
135
136 async fn bind_volume_control(&mut self, id: ftrace::Id) -> Result<(), ControllerError> {
137 trace!(id, c"bind volume control");
138 if self.proxy.is_some() {
139 return Ok(());
140 }
141
142 let (vol_control_proxy, server_end) = create_proxy();
143 let stream_type = self.stored_stream.stream_type;
144 let usage = Usage2::RenderUsage(stream_type.into());
145
146 let guard = trace_guard!(id, c"bind usage volume control");
147 if let Err(e) = call!(self.audio_service => bind_usage_volume_control2(&usage, server_end))
148 {
149 return Err(ControllerError::ExternalFailure(
150 SettingType::Audio,
151 CONTROLLER_ERROR_DEPENDENCY.into(),
152 format!("bind_usage_volume_control2 for audio_core {usage:?}").into(),
153 format!("{e:?}").into(),
154 ));
155 }
156 drop(guard);
157
158 let guard = trace_guard!(id, c"set values");
159 if let Err(e) = vol_control_proxy.set_volume(self.stored_stream.user_volume_level) {
161 return Err(ControllerError::ExternalFailure(
162 SettingType::Audio,
163 CONTROLLER_ERROR_DEPENDENCY.into(),
164 format!("set_volume for vol_control {stream_type:?}").into(),
165 format!("{e:?}").into(),
166 ));
167 }
168
169 if let Err(e) = vol_control_proxy.set_mute(self.stored_stream.user_volume_muted) {
170 return Err(ControllerError::ExternalFailure(
171 SettingType::Audio,
172 CONTROLLER_ERROR_DEPENDENCY.into(),
173 "set_mute for vol_control".into(),
174 format!("{e:?}").into(),
175 ));
176 }
177 drop(guard);
178
179 if let Some(exit_tx) = self.listen_exit_tx.take() {
180 exit_tx.send(()).expect(
182 "StreamVolumeControl::bind_volume_control, listen_exit_tx failed to send exit \
183 signal",
184 );
185 }
186
187 trace!(id, c"setup listener");
188
189 let (exit_tx, mut exit_rx) = futures::channel::oneshot::channel::<()>();
190 let publisher_clone = self.publisher.clone();
191 let mut volume_events = vol_control_proxy.take_event_stream();
192 let early_exit_action = self.early_exit_action.clone();
193 fasync::Task::local(async move {
194 let id = ftrace::Id::new();
195 trace!(id, c"bind volume handler");
196 loop {
197 futures::select! {
198 _ = exit_rx => {
199 trace!(id, c"exit");
200 if let Some(publisher) = publisher_clone {
201 publisher.send_event(
204 Event::ExternalServiceEvent(
205 ExternalServiceEvent::Closed(
206 PUBLISHER_EVENT_NAME,
207 UNKNOWN_INSPECT_STRING.into(),
208 UNKNOWN_INSPECT_STRING.into(),
209 clock::inspect_format_now().into(),
210 )
211 )
212 );
213 }
214 return;
215 }
216 volume_event = volume_events.try_next() => {
217 trace!(id, c"volume_event");
218 if volume_event.is_err() ||
219 volume_event.expect("should not be error").is_none()
220 {
221 if let Some(action) = early_exit_action {
222 (action)();
223 }
224 return;
225 }
226 }
227
228 }
229 }
230 })
231 .detach();
232
233 self.listen_exit_tx = Some(exit_tx);
234 self.proxy = Some(vol_control_proxy);
235 Ok(())
236 }
237}