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