1use super::AudioInfoLoader;
5use crate::audio::types::{
6 AudioInfo, AudioStream, AudioStreamType, SetAudioStream, AUDIO_STREAM_TYPE_COUNT,
7};
8use crate::audio::{create_default_modified_counters, ModifiedCounters, StreamVolumeControl};
9use crate::base::SettingType;
10use crate::handler::base::Request;
11use crate::handler::setting_handler::persist::{
12 controller as data_controller, ClientProxy, WriteResult,
13};
14use crate::handler::setting_handler::{
15 controller, ControllerError, ControllerStateResult, Event, SettingHandlerResult, State,
16};
17use crate::{trace, trace_guard};
18use async_trait::async_trait;
19use futures::lock::Mutex;
20use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
21use settings_storage::storage_factory::{DefaultLoader, StorageAccess};
22use std::collections::HashMap;
23use std::rc::Rc;
24use {fuchsia_async as fasync, fuchsia_trace as ftrace};
25
26type VolumeControllerHandle = Rc<Mutex<VolumeController>>;
27
28pub(crate) struct VolumeController {
29 client: ClientProxy,
30 audio_service_connected: bool,
31 stream_volume_controls: HashMap<AudioStreamType, StreamVolumeControl>,
32 modified_counters: ModifiedCounters,
33 audio_info_loader: AudioInfoLoader,
34}
35
36enum UpdateFrom {
37 AudioInfo(AudioInfo),
38 NewStreams(Vec<SetAudioStream>),
39}
40
41impl VolumeController {
42 fn create_with(
43 client: ClientProxy,
44 audio_info_loader: AudioInfoLoader,
45 ) -> VolumeControllerHandle {
46 Rc::new(Mutex::new(Self {
47 client,
48 stream_volume_controls: HashMap::new(),
49 audio_service_connected: false,
50 modified_counters: create_default_modified_counters(),
51 audio_info_loader,
52 }))
53 }
54
55 async fn restore(&mut self, id: ftrace::Id) -> ControllerStateResult {
57 self.restore_volume_state(true, id).await
58 }
59
60 async fn restore_volume_state(
64 &mut self,
65 push_to_audio_core: bool,
66 id: ftrace::Id,
67 ) -> ControllerStateResult {
68 let audio_info = self.client.read_setting::<AudioInfo>(id).await;
69 let _ = self
71 .update_volume_streams(UpdateFrom::AudioInfo(audio_info), push_to_audio_core, id)
72 .await?;
73 Ok(())
74 }
75
76 async fn get_info(&self, id: ftrace::Id) -> Result<AudioInfo, ControllerError> {
77 let mut audio_info = self.client.read_setting::<AudioInfo>(id).await;
78
79 audio_info.modified_counters = Some(self.modified_counters.clone());
80 Ok(audio_info)
81 }
82
83 async fn set_volume(
84 &mut self,
85 volume: Vec<SetAudioStream>,
86 id: ftrace::Id,
87 ) -> SettingHandlerResult {
88 let guard = trace_guard!(id, c"set volume updating counters");
89 for stream in &volume {
91 let _ = self.modified_counters.insert(
94 stream.stream_type,
95 self.modified_counters
96 .get(&stream.stream_type)
97 .map_or(0, |flag| flag.wrapping_add(1)),
98 );
99 }
100 drop(guard);
101
102 if !(self.update_volume_streams(UpdateFrom::NewStreams(volume), true, id).await?) {
103 trace!(id, c"set volume notifying");
104 let info = self.get_info(id).await?.into();
105 self.client.notify(Event::Changed(info)).await;
106 }
107
108 Ok(None)
109 }
110
111 async fn get_streams_array_from_map(
112 &self,
113 stream_map: &HashMap<AudioStreamType, StreamVolumeControl>,
114 ) -> [AudioStream; AUDIO_STREAM_TYPE_COUNT] {
115 let mut streams: [AudioStream; AUDIO_STREAM_TYPE_COUNT] =
116 self.audio_info_loader.default_value().streams;
117 for stream in &mut streams {
118 if let Some(volume_control) = stream_map.get(&stream.stream_type) {
119 *stream = volume_control.stored_stream;
120 }
121 }
122
123 streams
124 }
125
126 async fn update_volume_streams(
133 &mut self,
134 update_from: UpdateFrom,
135 push_to_audio_core: bool,
136 id: ftrace::Id,
137 ) -> Result<bool, ControllerError> {
138 let mut new_vec = vec![];
139 trace!(id, c"update volume streams");
140 let calculating_guard = trace_guard!(id, c"check and bind");
141 let (stored_value, new_streams) = match &update_from {
142 UpdateFrom::AudioInfo(audio_info) => (None, audio_info.streams.iter()),
143 UpdateFrom::NewStreams(streams) => {
144 trace!(id, c"reading setting");
145 let stored_value = self.client.read_setting::<AudioInfo>(id).await;
146 for set_stream in streams.iter() {
147 let stored_stream = stored_value
148 .streams
149 .iter()
150 .find(|stream| stream.stream_type == set_stream.stream_type)
151 .ok_or_else(|| {
152 ControllerError::InvalidArgument(
153 SettingType::Audio,
154 "stream".into(),
155 format!("{set_stream:?}").into(),
156 )
157 })?;
158 new_vec.push(AudioStream {
159 stream_type: stored_stream.stream_type,
160 source: set_stream.source,
161 user_volume_level: set_stream
162 .user_volume_level
163 .unwrap_or(stored_stream.user_volume_level),
164 user_volume_muted: set_stream
165 .user_volume_muted
166 .unwrap_or(stored_stream.user_volume_muted),
167 });
168 }
169 (Some(stored_value), new_vec.iter())
170 }
171 };
172
173 if push_to_audio_core {
174 let guard = trace_guard!(id, c"push to core");
175 self.check_and_bind_volume_controls(
176 id,
177 self.audio_info_loader.default_value().streams.iter(),
178 )
179 .await?;
180 drop(guard);
181
182 trace!(id, c"setting core");
183 for stream in new_streams {
184 if let Some(volume_control) =
185 self.stream_volume_controls.get_mut(&stream.stream_type)
186 {
187 volume_control.set_volume(id, *stream).await?;
188 }
189 }
190 } else {
191 trace!(id, c"without push to core");
192 self.check_and_bind_volume_controls(id, new_streams).await?;
193 }
194 drop(calculating_guard);
195
196 if let Some(mut stored_value) = stored_value {
197 let guard = trace_guard!(id, c"updating streams and counters");
198 stored_value.streams =
199 self.get_streams_array_from_map(&self.stream_volume_controls).await;
200 stored_value.modified_counters = Some(self.modified_counters.clone());
201 drop(guard);
202
203 let guard = trace_guard!(id, c"writing setting");
204 let write_result = self.client.write_setting(stored_value.into(), id).await;
205 drop(guard);
206 Ok(write_result.notified())
207 } else {
208 Ok(false)
209 }
210 }
211
212 async fn check_and_bind_volume_controls(
214 &mut self,
215 id: ftrace::Id,
216 streams: impl Iterator<Item = &AudioStream>,
217 ) -> ControllerStateResult {
218 trace!(id, c"check and bind fn");
219 if self.audio_service_connected {
220 return Ok(());
221 }
222
223 let guard = trace_guard!(id, c"connecting to service");
224 let service_result = self
225 .client
226 .get_service_context()
227 .connect::<fidl_fuchsia_media::AudioCoreMarker>()
228 .await;
229
230 let audio_service = service_result.map_err(|e| {
231 ControllerError::ExternalFailure(
232 SettingType::Audio,
233 "fuchsia.media.audio".into(),
234 "connect for audio_core".into(),
235 format!("{e:?}").into(),
236 )
237 })?;
238
239 drop(guard);
243 let mut stream_tuples = Vec::new();
244 for stream in streams {
245 trace!(id, c"create stream volume control");
246 let client = self.client.clone();
247
248 stream_tuples.push((
250 stream.stream_type,
251 StreamVolumeControl::create(
252 id,
253 &audio_service,
254 *stream,
255 Some(Rc::new(move || {
256 let client = client.clone();
260 fasync::Task::local(async move {
261 trace!(id, c"stream exit");
262 client
263 .notify(Event::Exited(Err(ControllerError::UnexpectedError(
264 "stream_volume_control exit".into(),
265 ))))
266 .await;
267 })
268 .detach();
269 })),
270 None,
271 )
272 .await?,
273 ));
274 }
275
276 stream_tuples.into_iter().for_each(|(stream_type, stream_volume_control)| {
277 let _ = self.stream_volume_controls.insert(stream_type, stream_volume_control);
279 });
280 self.audio_service_connected = true;
281
282 Ok(())
283 }
284}
285
286pub(crate) struct AudioController {
287 volume: VolumeControllerHandle,
288}
289
290impl StorageAccess for AudioController {
291 type Storage = DeviceStorage;
292 type Data = AudioInfo;
293 const STORAGE_KEY: &'static str = AudioInfo::KEY;
294}
295
296impl data_controller::CreateWith for AudioController {
297 type Data = AudioInfoLoader;
298 fn create_with(client: ClientProxy, data: Self::Data) -> Result<Self, ControllerError> {
299 Ok(AudioController { volume: VolumeController::create_with(client, data) })
300 }
301}
302
303#[async_trait(?Send)]
304impl controller::Handle for AudioController {
305 async fn handle(&self, request: Request) -> Option<SettingHandlerResult> {
306 match request {
307 Request::Restore => Some({
308 let id = ftrace::Id::new();
309 trace!(id, c"controller restore");
310 self.volume.lock().await.restore(id).await.map(|_| None)
311 }),
312 Request::SetVolume(volume, id) => {
313 trace!(id, c"controller set");
314 for audio_stream in &volume {
316 if !audio_stream.has_valid_volume_level() {
317 return Some(Err(ControllerError::InvalidArgument(
318 SettingType::Audio,
319 "stream".into(),
320 format!("{audio_stream:?}").into(),
321 )));
322 }
323 }
324 Some(self.volume.lock().await.set_volume(volume, id).await)
325 }
326 Request::Get => {
327 let id = ftrace::Id::new();
328 Some(self.volume.lock().await.get_info(id).await.map(|info| Some(info.into())))
329 }
330 _ => None,
331 }
332 }
333
334 async fn change_state(&mut self, state: State) -> Option<ControllerStateResult> {
335 match state {
336 State::Startup => {
337 Some({
339 let id = ftrace::Id::new();
340 trace!(id, c"controller startup");
341 self.volume.lock().await.restore_volume_state(false, id).await
342 })
343 }
344 _ => None,
345 }
346 }
347}