Skip to content

Commit

Permalink
audio_diagnostics: Include input/ouput preference set JSON
Browse files Browse the repository at this point in the history
BUG=b:365985920
TEST=None

Change-Id: I60054109c7d9781ccb506b1c23fc72e6f83c3ca9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/adhd/+/5867118
Reviewed-by: Li-Yu Yu <aaronyu@google.com>
Tested-by: chromeos-cop-builder@chromeos-cop.iam.gserviceaccount.com <chromeos-cop-builder@chromeos-cop.iam.gserviceaccount.com>
Commit-Queue: Gavin Williams <gavinwill@chromium.org>
  • Loading branch information
Gavin Williams authored and Chromeos LUCI committed Sep 20, 2024
1 parent 680ed1e commit 6b65a41
Showing 1 changed file with 186 additions and 13 deletions.
199 changes: 186 additions & 13 deletions cras/client/audio_diagnostics/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::collections::BTreeSet;
use std::collections::HashMap;

use anyhow::Context;
Expand All @@ -26,11 +27,13 @@ struct Audio {
devices: Option<Devices>,
input_user_priority: Option<HashMap<AudioNode, i32>>,
output_user_priority: Option<HashMap<AudioNode, i32>>,
input_preference_set: Option<HashMap<AudioNodeSet, AudioNode>>,
output_preference_set: Option<HashMap<AudioNodeSet, AudioNode>>,
// The last_seen field is intentionally dropped to avoid
// joining feedback reports. See b/279545748#comment11.
}

#[derive(PartialEq, Eq, Hash, Debug)]
#[derive(PartialEq, Eq, Hash, Debug, Ord, PartialOrd)]
struct AudioNode {
stable_id: u32,
is_input: bool,
Expand All @@ -42,6 +45,16 @@ enum AudioNodeParseError {
InvalidIsInput,
}

impl AudioNodeParseError {
fn as_str(&self) -> &'static str {
match self {
AudioNodeParseError::MissingDelimiter => "missing delimiter",
AudioNodeParseError::StableIdNotU32 => "stable id is not u32",
AudioNodeParseError::InvalidIsInput => "invalid is_input",
}
}
}

impl AudioNode {
fn try_from_str(v: &str) -> Result<Self, AudioNodeParseError> {
let (stable_id_str, is_input_str) = v
Expand All @@ -62,16 +75,20 @@ impl AudioNode {
}
}

fn format_audio_node(node: &AudioNode) -> String {
format!(
"0x{:x} : {}",
Salt::instance().pseudonymize_stable_id(node.stable_id),
node.is_input as i32
)
}

impl Serialize for AudioNode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&format!(
"0x{:x} : {}",
Salt::instance().pseudonymize_stable_id(self.stable_id),
self.is_input as i32
))
serializer.serialize_str(&format_audio_node(self))
}
}

Expand All @@ -88,14 +105,9 @@ impl<'de> Visitor<'de> for AudioNodeVisitor {
where
E: serde::de::Error,
{
use AudioNodeParseError::*;
match AudioNode::try_from_str(v) {
Ok(node) => Ok(node),
Err(err) => Err(match err {
MissingDelimiter => E::custom("missing delimiter"),
StableIdNotU32 => E::custom("stable id is not u32"),
InvalidIsInput => E::custom("invalid is_input"),
}),
Err(err) => Err(E::custom(err.as_str())),
}
}
}
Expand All @@ -109,6 +121,43 @@ impl<'de> Deserialize<'de> for AudioNode {
}
}

#[derive(PartialEq, Eq, Hash, Debug)]
struct AudioNodeSet {
audio_nodes: BTreeSet<AudioNode>,
}

impl<'de> Deserialize<'de> for AudioNodeSet {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut audio_nodes = BTreeSet::new();
let audio_nodes_string = String::deserialize(deserializer)?;
for part in audio_nodes_string.split(',') {
let audio_node = AudioNode::try_from_str(part.trim())
.map_err(|err| serde::de::Error::custom(err.as_str()))?;
audio_nodes.insert(audio_node);
}
Ok(AudioNodeSet { audio_nodes })
}
}

impl Serialize for AudioNodeSet {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut audio_nodes_string = String::new();
for (i, node) in self.audio_nodes.iter().enumerate() {
if i > 0 {
audio_nodes_string.push_str(", ");
}
audio_nodes_string.push_str(&format_audio_node(node));
}
serializer.serialize_str(&audio_nodes_string)
}
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct DeviceState {
activate_by_user: Option<bool>,
Expand Down Expand Up @@ -140,9 +189,12 @@ pub fn print_salted_audio_settings(path: &str) {

#[cfg(test)]
mod tests {
use std::collections::BTreeSet;

use cras_common::pseudonymization::Salt;

use super::AudioNode;
use super::AudioNodeSet;
use super::DeviceState;
use super::LocalState;

Expand All @@ -169,6 +221,67 @@ mod tests {
assert_eq!(serde_json::from_str::<AudioNode>(b_json).unwrap(), b);
}

#[test]
fn audio_node_set() {
let stable_id1 = 1;
let stable_id2 = 2;
let input_set = AudioNodeSet {
audio_nodes: BTreeSet::from([
AudioNode {
stable_id: stable_id1,
is_input: true,
},
AudioNode {
stable_id: stable_id2,
is_input: true,
},
]),
};
let input_set_json = format!("\"{:x} : 1, {:x} : 1\"", stable_id1, stable_id2);
let input_set_json_salted = format!(
"\"0x{:x} : 1, 0x{:x} : 1\"",
Salt::instance().pseudonymize_stable_id(stable_id1),
Salt::instance().pseudonymize_stable_id(stable_id2)
);
assert_eq!(
serde_json::to_string(&input_set).unwrap(),
input_set_json_salted
);
assert_eq!(
serde_json::from_str::<AudioNodeSet>(&input_set_json).unwrap(),
input_set
);

let stable_id3 = 3;
let stable_id4 = 4;
let output_set = AudioNodeSet {
audio_nodes: BTreeSet::from([
AudioNode {
stable_id: stable_id3,
is_input: false,
},
AudioNode {
stable_id: stable_id4,
is_input: false,
},
]),
};
let output_set_json = format!("\"{:x} : 0, {:x} : 0\"", stable_id3, stable_id4);
let output_set_json_salted = format!(
"\"0x{:x} : 0, 0x{:x} : 0\"",
Salt::instance().pseudonymize_stable_id(stable_id3),
Salt::instance().pseudonymize_stable_id(stable_id4)
);
assert_eq!(
serde_json::to_string(&output_set).unwrap(),
output_set_json_salted
);
assert_eq!(
serde_json::from_str::<AudioNodeSet>(&output_set_json).unwrap(),
output_set
);
}

#[test]
fn deserialize() {
let audio_settings_str = r#"{
Expand Down Expand Up @@ -198,6 +311,9 @@ mod tests {
"input_user_priority": {
"3787040 : 1": 1
},
"input_preference_set": {
"3787040 : 1, 2315562897 : 1, 3962083865 : 1": "2315562897 : 1"
},
"last_seen": {
"1923447123 : 0": 1687158819.326577,
"2315562897 : 1": 1687158819.326577,
Expand All @@ -207,6 +323,9 @@ mod tests {
},
"output_user_priority": {
"1923447123 : 0": 1
},
"output_preference_set": {
"2356475750 : 0, 1923447123 : 0, 2315562897 : 0": "1923447123 : 0"
}
}"#;
let local_state_string = r#"{"settings":{"audio":@AUDIO_SETTINGS@}}"#
Expand Down Expand Up @@ -302,6 +421,33 @@ mod tests {
.unwrap(),
1
);
assert_eq!(
*audio
.input_preference_set
.as_ref()
.unwrap()
.get(&AudioNodeSet {
audio_nodes: BTreeSet::from([
AudioNode {
stable_id: 3962083865,
is_input: true,
},
AudioNode {
stable_id: 3787040,
is_input: true,
},
AudioNode {
stable_id: 2315562897,
is_input: true,
},
])
})
.unwrap(),
AudioNode {
stable_id: 2315562897,
is_input: true
}
);
assert_eq!(
*audio
.output_user_priority
Expand All @@ -313,6 +459,33 @@ mod tests {
})
.unwrap(),
1
)
);
assert_eq!(
*audio
.output_preference_set
.as_ref()
.unwrap()
.get(&AudioNodeSet {
audio_nodes: BTreeSet::from([
AudioNode {
stable_id: 2315562897,
is_input: false,
},
AudioNode {
stable_id: 2356475750,
is_input: false,
},
AudioNode {
stable_id: 1923447123,
is_input: false,
},
])
})
.unwrap(),
AudioNode {
stable_id: 1923447123,
is_input: false
}
);
}
}

0 comments on commit 6b65a41

Please sign in to comment.