// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/audio/audio_device_id.h"
#include <cstdint>
#include "chromeos/ash/components/audio/audio_device.h"
#include "chromeos/ash/components/audio/audio_device_selection_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
const uint32_t kInputMaxSupportedChannels = 1;
const uint32_t kOutputMaxSupportedChannels = 2;
const uint32_t kInputAudioEffect = 1;
const uint32_t kOutputAudioEffect = 0;
const int32_t kInputNumberOfVolumeSteps = 0;
const int32_t kOutputNumberOfVolumeSteps = 25;
const uint64_t kHeadphoneId = 10002;
const uint64_t kInternalMicId = 10003;
const uint64_t kUsbMicId = 10005;
struct AudioNodeInfo {
bool is_input;
uint64_t id;
const char* const device_name;
const char* const type;
const char* const name;
};
const AudioNodeInfo kInternalMic = {true, kInternalMicId, "Fake Mic",
"INTERNAL_MIC", "Internal Mic"};
const AudioNodeInfo kHeadphone = {false, kHeadphoneId, "Fake Headphone",
"HEADPHONE", "Headphone"};
const AudioNodeInfo kUSBMic = {true, kUsbMicId, "Fake USB Mic", "USB",
"USB Microphone"};
AudioDevice CreateAudioDevice(const AudioNodeInfo& info, int version) {
return AudioDevice(AudioNode(
info.is_input, info.id, /*has_v2_stable_device_id=*/version == 2,
/*stable_device_id_v1=*/info.id,
/*stable_device_id_v2=*/version == 1 ? 0 : info.id ^ 0xFF,
info.device_name, info.type, info.name, false, 0,
info.is_input ? kInputMaxSupportedChannels : kOutputMaxSupportedChannels,
info.is_input ? kInputAudioEffect : kOutputAudioEffect,
info.is_input ? kInputNumberOfVolumeSteps : kOutputNumberOfVolumeSteps));
}
} // namespace
class AudioDeviceIdTest : public AudioDeviceSelectionTestBase {};
TEST_F(AudioDeviceIdTest, GetDeviceIdString) {
struct {
const AudioNodeInfo audio_node_info;
int version;
const std::string expected_id;
} items[] = {
{kInternalMic, 1, "10003 : 1"}, {kInternalMic, 2, "2 : 10220 : 1"},
{kHeadphone, 1, "10002 : 0"}, {kHeadphone, 2, "2 : 10221 : 0"},
{kUSBMic, 1, "10005 : 1"}, {kUSBMic, 2, "2 : 10218 : 1"}};
for (const auto& item : items) {
EXPECT_EQ(GetDeviceIdString(
CreateAudioDevice(item.audio_node_info, item.version)),
item.expected_id);
}
}
// Verify GetDeviceSetIdString() can convert AudioDeviceList
// to string containing comma separated set of versioned device IDs.
TEST_F(AudioDeviceIdTest, GetDeviceSetIdString) {
struct {
const AudioDeviceList audio_device_list;
const std::string expected_id;
} items[] = {
{{}, ""},
{{CreateAudioDevice(kInternalMic, 1)}, "10003 : 1"},
{{CreateAudioDevice(kInternalMic, 1), CreateAudioDevice(kInternalMic, 1)},
"10003 : 1"},
{{CreateAudioDevice(kInternalMic, 1), CreateAudioDevice(kHeadphone, 1)},
"10002 : 0,10003 : 1"},
{{CreateAudioDevice(kInternalMic, 1), CreateAudioDevice(kHeadphone, 1),
CreateAudioDevice(kUSBMic, 1)},
"10002 : 0,10003 : 1,10005 : 1"},
{{CreateAudioDevice(kHeadphone, 1), CreateAudioDevice(kInternalMic, 1),
CreateAudioDevice(kUSBMic, 1)},
"10002 : 0,10003 : 1,10005 : 1"},
{{CreateAudioDevice(kUSBMic, 1), CreateAudioDevice(kHeadphone, 1),
CreateAudioDevice(kInternalMic, 1)},
"10002 : 0,10003 : 1,10005 : 1"}};
for (const auto& item : items) {
EXPECT_EQ(GetDeviceSetIdString(item.audio_device_list), item.expected_id);
}
}
TEST_F(AudioDeviceIdTest, ParseDeviceId) {
struct {
const std::string id_string;
const std::optional<uint64_t> expected_id;
} items[] = {
{"", std::nullopt}, {"2", 2}, {"10003 : 1", 10003},
{"2 : 10220 : 1", 10220}, {"10220", 10220}, {"a120000", std::nullopt},
{"2 : a120000", std::nullopt}};
for (const auto& item : items) {
EXPECT_EQ(ParseDeviceId(item.id_string), item.expected_id);
}
}
} // namespace ash