1use crate::audio::audio_default_settings::{create_default_audio_stream, AudioInfoLoader};
6use crate::audio::{create_default_modified_counters, ModifiedCounters};
7use crate::base::SettingType;
8use anyhow::{anyhow, Error};
9use serde::{Deserialize, Serialize};
10use settings_storage::device_storage::DeviceStorageCompatible;
11use std::collections::HashMap;
12use std::ops::RangeInclusive;
13
14const RANGE: RangeInclusive<f32> = 0.0..=1.0;
15
16#[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
17pub enum AudioSettingSource {
18 User,
19 System,
20 SystemWithFeedback,
21}
22
23#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq)]
24pub enum AudioStreamType {
25 Background,
26 Media,
27 Interruption,
28 SystemAgent,
29 Communication,
30 Accessibility,
31}
32
33pub(crate) const AUDIO_STREAM_TYPE_COUNT: usize = 6;
34pub const LEGACY_AUDIO_STREAM_TYPE_COUNT: usize = 5;
35
36impl AudioStreamType {
37 pub fn is_legacy(&self) -> bool {
45 match *self {
46 AudioStreamType::Background
47 | AudioStreamType::Communication
48 | AudioStreamType::Interruption
49 | AudioStreamType::Media
50 | AudioStreamType::SystemAgent => true,
51 _ => false,
52 }
53 }
54}
55
56#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
57pub struct AudioStream {
58 pub stream_type: AudioStreamType,
59 pub source: AudioSettingSource,
60 pub user_volume_level: f32,
61 pub user_volume_muted: bool,
62}
63
64impl AudioStream {
65 pub(crate) fn has_valid_volume_level(&self) -> bool {
66 RANGE.contains(&self.user_volume_level)
67 }
68}
69
70#[derive(PartialEq, Debug, Clone, Copy)]
71pub struct SetAudioStream {
72 pub stream_type: AudioStreamType,
73 pub source: AudioSettingSource,
74 pub user_volume_level: Option<f32>,
75 pub user_volume_muted: Option<bool>,
76}
77
78impl SetAudioStream {
79 pub(crate) fn has_valid_volume_level(&self) -> bool {
80 self.user_volume_level.map(|v| RANGE.contains(&v)).unwrap_or(true)
81 }
82
83 pub(crate) fn is_valid_payload(&self) -> bool {
84 self.user_volume_level.is_some() || self.user_volume_muted.is_some()
85 }
86}
87
88impl From<AudioStream> for SetAudioStream {
89 fn from(stream: AudioStream) -> Self {
90 Self {
91 stream_type: stream.stream_type,
92 source: stream.source,
93 user_volume_level: Some(stream.user_volume_level),
94 user_volume_muted: Some(stream.user_volume_muted),
95 }
96 }
97}
98
99#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
100pub struct AudioInfo {
101 pub streams: [AudioStream; AUDIO_STREAM_TYPE_COUNT],
102 pub modified_counters: Option<ModifiedCounters>,
103}
104
105impl From<&AudioInfo> for SettingType {
106 fn from(_: &AudioInfo) -> SettingType {
107 SettingType::Audio
108 }
109}
110
111impl DeviceStorageCompatible for AudioInfo {
112 type Loader = AudioInfoLoader;
113 const KEY: &'static str = "audio_info";
114
115 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
116 Self::extract(value).or_else(|_| AudioInfoV3::try_deserialize_from(value).map(Self::from))
117 }
118}
119
120#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
127pub struct AudioInfoV3 {
128 pub streams: [AudioStream; LEGACY_AUDIO_STREAM_TYPE_COUNT],
129 pub modified_counters: Option<ModifiedCounters>,
130}
131
132impl AudioInfoV3 {
133 pub(super) fn try_deserialize_from(value: &str) -> Result<Self, Error> {
134 serde_json::from_str(value)
135 .map_err(|e| anyhow!("could not deserialize: {e:?}"))
136 .or_else(|_| AudioInfoV2::try_deserialize_from(value).map(Self::from))
137 }
138
139 #[cfg(test)]
140 pub(super) fn default_value(default_setting: AudioInfo) -> Self {
141 AudioInfoV3 {
142 streams: default_setting.streams[0..LEGACY_AUDIO_STREAM_TYPE_COUNT].try_into().unwrap(),
143 modified_counters: None,
144 }
145 }
146}
147
148impl From<AudioInfoV3> for AudioInfo {
149 fn from(v3: AudioInfoV3) -> AudioInfo {
150 let mut stream_vec = v3.streams.to_vec();
151 stream_vec.push(create_default_audio_stream(AudioStreamType::Accessibility));
152
153 AudioInfo {
154 streams: stream_vec.try_into().unwrap(),
155 modified_counters: v3.modified_counters,
156 }
157 }
158}
159
160#[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
161pub struct AudioInputInfo {
162 pub mic_mute: bool,
163}
164
165#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
168pub struct AudioInfoV2 {
169 pub streams: [AudioStream; LEGACY_AUDIO_STREAM_TYPE_COUNT],
170 pub input: AudioInputInfo,
171 pub modified_counters: Option<ModifiedCounters>,
172}
173
174impl AudioInfoV2 {
175 pub(super) fn try_deserialize_from(value: &str) -> Result<Self, Error> {
176 serde_json::from_str(value)
177 .map_err(|e| anyhow!("could not deserialize: {e:?}"))
178 .or_else(|_| AudioInfoV1::try_deserialize_from(value).map(Self::from))
179 }
180
181 #[cfg(test)]
182 pub(super) fn default_value(default_setting: AudioInfo) -> Self {
183 AudioInfoV2 {
184 streams: default_setting.streams[0..LEGACY_AUDIO_STREAM_TYPE_COUNT].try_into().unwrap(),
185 input: AudioInputInfo { mic_mute: false },
186 modified_counters: None,
187 }
188 }
189}
190
191impl From<AudioInfoV2> for AudioInfoV3 {
192 fn from(v2: AudioInfoV2) -> AudioInfoV3 {
193 AudioInfoV3 { streams: v2.streams, modified_counters: v2.modified_counters }
194 }
195}
196
197#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
200pub struct AudioInfoV1 {
201 pub streams: [AudioStream; LEGACY_AUDIO_STREAM_TYPE_COUNT],
202 pub input: AudioInputInfo,
203 pub modified_timestamps: Option<HashMap<AudioStreamType, String>>,
204}
205
206impl AudioInfoV1 {
207 pub(super) fn try_deserialize_from(value: &str) -> Result<Self, Error> {
208 serde_json::from_str(value)
209 .map_err(|e| anyhow!("could not deserialize: {e:?}"))
210 .or_else(|_| AudioInfoV1::try_deserialize_from(value).map(Self::from))
211 }
212
213 #[cfg(test)]
214 pub(super) fn default_value(default_setting: AudioInfo) -> Self {
215 AudioInfoV1 {
216 streams: default_setting.streams[0..LEGACY_AUDIO_STREAM_TYPE_COUNT].try_into().unwrap(),
217 input: AudioInputInfo { mic_mute: false },
218 modified_timestamps: None,
219 }
220 }
221}
222
223impl From<AudioInfoV1> for AudioInfoV2 {
224 fn from(v1: AudioInfoV1) -> Self {
225 AudioInfoV2 {
226 streams: v1.streams,
227 input: v1.input,
228 modified_counters: Some(create_default_modified_counters()),
229 }
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 const VALID_AUDIO_STREAM: AudioStream = AudioStream {
238 stream_type: AudioStreamType::Background,
239 source: AudioSettingSource::User,
240 user_volume_level: 0.5,
241 user_volume_muted: false,
242 };
243 const INVALID_NEGATIVE_AUDIO_STREAM: AudioStream =
244 AudioStream { user_volume_level: -0.1, ..VALID_AUDIO_STREAM };
245 const INVALID_GREATER_THAN_ONE_AUDIO_STREAM: AudioStream =
246 AudioStream { user_volume_level: 1.1, ..VALID_AUDIO_STREAM };
247
248 #[fuchsia::test]
249 fn test_volume_level_validation() {
250 assert!(VALID_AUDIO_STREAM.has_valid_volume_level());
251 assert!(!INVALID_NEGATIVE_AUDIO_STREAM.has_valid_volume_level());
252 assert!(!INVALID_GREATER_THAN_ONE_AUDIO_STREAM.has_valid_volume_level());
253 }
254
255 #[fuchsia::test]
256 fn test_set_audio_stream_validation() {
257 let valid_set_audio_stream = SetAudioStream::from(VALID_AUDIO_STREAM);
258 assert!(valid_set_audio_stream.has_valid_volume_level());
259 let invalid_set_audio_stream = SetAudioStream::from(INVALID_NEGATIVE_AUDIO_STREAM);
260 assert!(!invalid_set_audio_stream.has_valid_volume_level());
261 let invalid_set_audio_stream = SetAudioStream::from(INVALID_GREATER_THAN_ONE_AUDIO_STREAM);
262 assert!(!invalid_set_audio_stream.has_valid_volume_level());
263 }
264}