settings_audio/
audio_default_settings.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::types::{
6    AUDIO_STREAM_TYPE_COUNT, AudioInfo, AudioSettingSource, AudioStream, AudioStreamType,
7};
8use settings_common::config::default_settings::DefaultSetting;
9use settings_common::inspect::config_logger::InspectConfigLogger;
10use settings_storage::storage_factory::DefaultLoader;
11use std::collections::HashMap;
12use std::rc::Rc;
13use std::sync::Mutex;
14
15const DEFAULT_VOLUME_LEVEL: f32 = 0.5;
16const DEFAULT_VOLUME_MUTED: bool = false;
17
18const DEFAULT_STREAMS: [AudioStream; AUDIO_STREAM_TYPE_COUNT] = [
19    create_default_audio_stream(AudioStreamType::Background),
20    create_default_audio_stream(AudioStreamType::Media),
21    create_default_audio_stream(AudioStreamType::Interruption),
22    create_default_audio_stream(AudioStreamType::SystemAgent),
23    create_default_audio_stream(AudioStreamType::Communication),
24    create_default_audio_stream(AudioStreamType::Accessibility),
25];
26
27const DEFAULT_AUDIO_INFO: AudioInfo =
28    AudioInfo { streams: DEFAULT_STREAMS, modified_counters: None };
29
30/// A mapping from stream type to an arbitrary numerical value. This number will
31/// change from the number sent in the previous update if the stream type's
32/// volume has changed.
33pub type ModifiedCounters = HashMap<AudioStreamType, usize>;
34
35pub fn create_default_modified_counters() -> ModifiedCounters {
36    IntoIterator::into_iter([
37        AudioStreamType::Background,
38        AudioStreamType::Media,
39        AudioStreamType::Interruption,
40        AudioStreamType::SystemAgent,
41        AudioStreamType::Communication,
42        AudioStreamType::Accessibility,
43    ])
44    .map(|stream_type| (stream_type, 0))
45    .collect()
46}
47
48pub const fn create_default_audio_stream(stream_type: AudioStreamType) -> AudioStream {
49    AudioStream {
50        stream_type,
51        source: AudioSettingSource::User,
52        user_volume_level: DEFAULT_VOLUME_LEVEL,
53        user_volume_muted: DEFAULT_VOLUME_MUTED,
54    }
55}
56
57pub fn build_audio_default_settings(
58    config_logger: Rc<Mutex<InspectConfigLogger>>,
59) -> DefaultSetting<AudioInfo, &'static str> {
60    DefaultSetting::new(
61        Some(DEFAULT_AUDIO_INFO),
62        "/config/data/audio_config_data.json",
63        config_logger,
64    )
65}
66
67/// Returns a default audio [`AudioInfo`] that is derived from
68/// [`DEFAULT_AUDIO_INFO`] with any fields specified in the
69/// audio configuration set.
70///
71/// [`DEFAULT_AUDIO_INFO`]: static@DEFAULT_AUDIO_INFO
72#[derive(Clone)]
73pub struct AudioInfoLoader {
74    audio_default_settings: Rc<Mutex<DefaultSetting<AudioInfo, &'static str>>>,
75}
76
77impl AudioInfoLoader {
78    pub fn new(audio_default_settings: DefaultSetting<AudioInfo, &'static str>) -> Self {
79        Self { audio_default_settings: Rc::new(Mutex::new(audio_default_settings)) }
80    }
81}
82
83impl DefaultLoader for AudioInfoLoader {
84    type Result = AudioInfo;
85
86    fn default_value(&self) -> Self::Result {
87        let mut default_audio_info: AudioInfo = DEFAULT_AUDIO_INFO.clone();
88
89        if let Ok(Some(audio_configuration)) =
90            self.audio_default_settings.lock().unwrap().get_cached_value()
91        {
92            default_audio_info.streams = audio_configuration.streams;
93        }
94        default_audio_info
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    // assert_eq!(..., false) is easier to read than assert!(!...).
101    #![allow(clippy::bool_assert_comparison)]
102
103    use super::*;
104    use crate::types::{AudioInfoV1, AudioInfoV2, AudioInfoV3};
105    use fuchsia_async::TestExecutor;
106    use fuchsia_inspect::component;
107    use settings_storage::device_storage::DeviceStorageCompatible;
108    use settings_test_common::helpers::move_executor_forward_and_get;
109
110    const CONFIG_AUDIO_INFO: AudioInfo = AudioInfo {
111        streams: [
112            AudioStream {
113                stream_type: AudioStreamType::Background,
114                source: AudioSettingSource::System,
115                user_volume_level: 0.6,
116                user_volume_muted: true,
117            },
118            AudioStream {
119                stream_type: AudioStreamType::Media,
120                source: AudioSettingSource::System,
121                user_volume_level: 0.7,
122                user_volume_muted: true,
123            },
124            AudioStream {
125                stream_type: AudioStreamType::Interruption,
126                source: AudioSettingSource::System,
127                user_volume_level: 0.2,
128                user_volume_muted: true,
129            },
130            AudioStream {
131                stream_type: AudioStreamType::SystemAgent,
132                source: AudioSettingSource::User,
133                user_volume_level: 0.3,
134                user_volume_muted: true,
135            },
136            AudioStream {
137                stream_type: AudioStreamType::Communication,
138                source: AudioSettingSource::User,
139                user_volume_level: 0.4,
140                user_volume_muted: false,
141            },
142            AudioStream {
143                stream_type: AudioStreamType::Accessibility,
144                source: AudioSettingSource::User,
145                user_volume_level: 0.35,
146                user_volume_muted: false,
147            },
148        ],
149        modified_counters: None,
150    };
151
152    /// Construct default audio settings and its dependencies.
153    fn make_default_settings() -> DefaultSetting<AudioInfo, &'static str> {
154        let config_logger =
155            Rc::new(Mutex::new(InspectConfigLogger::new(component::inspector().root())));
156        build_audio_default_settings(config_logger)
157    }
158
159    /// Load default settings from disk.
160    fn load_default_settings(
161        default_settings: &mut DefaultSetting<AudioInfo, &'static str>,
162    ) -> AudioInfo {
163        default_settings
164            .load_default_value()
165            .expect("if config exists, it should be parseable")
166            .expect("default value should always exist")
167    }
168
169    #[fuchsia::test(allow_stalls = false)]
170    async fn test_audio_config() {
171        let mut default_settings = make_default_settings();
172        let current_from_storage = load_default_settings(&mut default_settings);
173        // Ensure that settings are read from storage.
174        assert_eq!(CONFIG_AUDIO_INFO, current_from_storage);
175    }
176
177    #[fuchsia::test(allow_stalls = false)]
178    async fn test_audio_info_migration_v1_to_v2() {
179        let mut default_settings = make_default_settings();
180        let mut v1_settings =
181            AudioInfoV1::default_value(load_default_settings(&mut default_settings));
182        let updated_mic_mute_val = !v1_settings.input.mic_mute;
183        v1_settings.input.mic_mute = updated_mic_mute_val;
184        v1_settings.streams[0].user_volume_level = 0.9;
185        v1_settings.streams[0].user_volume_muted = false;
186
187        let serialized_v1 = serde_json::to_string(&v1_settings).expect("default should serialize");
188        let v2_from_v1 = AudioInfoV2::try_deserialize_from(&serialized_v1)
189            .expect("deserialization should succeed");
190
191        // Ensure that changes made in v1 are migrated to v2.
192        assert_eq!(v2_from_v1.input.mic_mute, updated_mic_mute_val);
193        assert_eq!(v2_from_v1.streams[0].user_volume_level, 0.9);
194        assert_eq!(v2_from_v1.streams[0].user_volume_muted, false);
195    }
196
197    #[fuchsia::test(allow_stalls = false)]
198    async fn test_audio_info_migration_v2_to_v3() {
199        let mut default_settings = make_default_settings();
200        let mut v2_settings =
201            AudioInfoV1::default_value(load_default_settings(&mut default_settings));
202        v2_settings.streams[0].user_volume_level = 0.9;
203        v2_settings.streams[0].user_volume_muted = false;
204
205        let serialized_v2 = serde_json::to_string(&v2_settings).expect("default should serialize");
206        let v3_from_v2 = AudioInfoV3::try_deserialize_from(&serialized_v2)
207            .expect("deserialization should succeed");
208
209        // Ensure that changes made in v2 are migrated to v3.
210        assert_eq!(v3_from_v2.streams[0].user_volume_level, 0.9);
211        assert_eq!(v3_from_v2.streams[0].user_volume_muted, false);
212    }
213
214    #[fuchsia::test]
215    fn test_audio_info_migration_v3_to_current() {
216        let mut executor = TestExecutor::new_with_fake_time();
217        let mut default_settings = make_default_settings();
218        let current_defaults = load_default_settings(&mut default_settings);
219
220        let mut v3_settings = move_executor_forward_and_get(
221            &mut executor,
222            async { AudioInfoV3::default_value(current_defaults) },
223            "Unable to get V3 default value",
224        );
225        v3_settings.streams[0].user_volume_level = 0.9;
226        v3_settings.streams[0].user_volume_muted = false;
227
228        let serialized_v3 = serde_json::to_string(&v3_settings).expect("default should serialize");
229        let current_from_v3 = AudioInfo::try_deserialize_from(&serialized_v3)
230            .expect("deserialization should succeed");
231
232        // Ensure that changes made in v3 are migrated to current.
233        assert_eq!(current_from_v3.streams[0].user_volume_level, 0.9);
234        assert_eq!(current_from_v3.streams[0].user_volume_muted, false);
235        // Ensure that migrating from v3 picks up a default for the new stream type.
236        assert_eq!(current_from_v3.streams[5], DEFAULT_AUDIO_INFO.streams[5]);
237    }
238
239    #[fuchsia::test]
240    fn test_audio_info_migration_v2_to_current() {
241        let mut executor = TestExecutor::new_with_fake_time();
242        let mut default_settings = make_default_settings();
243        let current_defaults = load_default_settings(&mut default_settings);
244
245        let mut v2_settings = move_executor_forward_and_get(
246            &mut executor,
247            async { AudioInfoV2::default_value(current_defaults) },
248            "Unable to get V2 default value",
249        );
250        let updated_mic_mute_val = !v2_settings.input.mic_mute;
251        v2_settings.input.mic_mute = updated_mic_mute_val;
252        v2_settings.streams[0].user_volume_level = 0.9;
253        v2_settings.streams[0].user_volume_muted = false;
254
255        let serialized_v2 = serde_json::to_string(&v2_settings).expect("default should serialize");
256        let current_from_v2 = AudioInfo::try_deserialize_from(&serialized_v2)
257            .expect("deserialization should succeed");
258
259        // Ensure that changes made in v2 are migrated to current.
260        assert_eq!(current_from_v2.streams[0].user_volume_level, 0.9);
261        assert_eq!(current_from_v2.streams[0].user_volume_muted, false);
262        // Ensure that migrating from v2 picks up a default for the new stream type.
263        assert_eq!(current_from_v2.streams[5], DEFAULT_AUDIO_INFO.streams[5]);
264    }
265
266    #[fuchsia::test]
267    fn test_audio_info_migration_v1_to_current() {
268        let mut executor = TestExecutor::new_with_fake_time();
269        let mut default_settings = make_default_settings();
270        let current_defaults = load_default_settings(&mut default_settings);
271
272        let mut v1_settings = move_executor_forward_and_get(
273            &mut executor,
274            async { AudioInfoV1::default_value(current_defaults) },
275            "Unable to get V1 default value",
276        );
277        let updated_mic_mute_val = !v1_settings.input.mic_mute;
278        v1_settings.input.mic_mute = updated_mic_mute_val;
279        v1_settings.streams[0].user_volume_level = 0.9;
280        v1_settings.streams[0].user_volume_muted = false;
281
282        let serialized_v1 = serde_json::to_string(&v1_settings).expect("default should serialize");
283        let current_from_v1 = AudioInfo::try_deserialize_from(&serialized_v1)
284            .expect("deserialization should succeed");
285
286        // Ensure that changes made in v1 are migrated to current.
287        assert_eq!(current_from_v1.streams[0].user_volume_level, 0.9);
288        assert_eq!(current_from_v1.streams[0].user_volume_muted, false);
289        // Ensure that migrating from v1 picks up a default for the new stream type.
290        assert_eq!(current_from_v1.streams[5], DEFAULT_AUDIO_INFO.streams[5]);
291    }
292}