blob: 4d511b43b717419c78fa7e1c47871330b963940c [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/media/audio/audio_core/test/virtual_audio_device_test.h"
#include <fuchsia/media/cpp/fidl.h>
#include <fuchsia/virtualaudio/cpp/fidl.h>
#include <cmath>
#include <cstring>
#include "gtest/gtest.h"
#include "lib/component/cpp/environment_services_helper.h"
#include "src/lib/fxl/logging.h"
namespace media::audio::test {
//
// VirtualAudioDeviceTest static members
//
AtomicDeviceId VirtualAudioDeviceTest::sequential_devices_;
// static
//
// Generate a unique id array for each virtual device created during the
// lifetime of this binary. In the MSB (byte [0]), place F0 for output device or
// F1 for input device. In bytes [8] thru [15], place a monotonically
// incrementing atomic value, split into bytes. Thus, the very first device, if
// an input, would have a unique_id of F1000000 00000000 00000000 00000001.
void VirtualAudioDeviceTest::PopulateUniqueIdArr(bool is_input,
uint8_t* unique_id_arr) {
uint64_t sequential_value = sequential_devices_.Next();
unique_id_arr[0] = (is_input ? 0xF1 : 0xF0);
unique_id_arr[8] = (sequential_value >> 56) & 0x0FF;
unique_id_arr[9] = (sequential_value >> 48) & 0x0FF;
unique_id_arr[10] = (sequential_value >> 40) & 0x0FF;
unique_id_arr[11] = (sequential_value >> 32) & 0x0FF;
unique_id_arr[12] = (sequential_value >> 24) & 0x0FF;
unique_id_arr[13] = (sequential_value >> 16) & 0x0FF;
unique_id_arr[14] = (sequential_value >> 8) & 0x0FF;
unique_id_arr[15] = sequential_value & 0x0FF;
}
//
// VirtualAudioDeviceTest implementation
//
// TODO(mpuryear): delete preexisting device-settings files, in SetUp?
void VirtualAudioDeviceTest::SetUp() {
ResetVirtualDevices();
AudioDeviceTest::SetUp();
auto err_handler = [this](zx_status_t error) { error_occurred_ = true; };
environment_services_->ConnectToService(input_.NewRequest());
environment_services_->ConnectToService(input_2_.NewRequest());
input_.set_error_handler(err_handler);
input_2_.set_error_handler(err_handler);
environment_services_->ConnectToService(output_.NewRequest());
environment_services_->ConnectToService(output_2_.NewRequest());
output_.set_error_handler(err_handler);
output_2_.set_error_handler(err_handler);
RetrievePreExistingDevices();
}
void VirtualAudioDeviceTest::TearDown() {
EXPECT_TRUE(input_.is_bound());
EXPECT_TRUE(input_2_.is_bound());
EXPECT_TRUE(output_.is_bound());
EXPECT_TRUE(output_2_.is_bound());
input_.set_error_handler(nullptr);
input_2_.set_error_handler(nullptr);
output_.set_error_handler(nullptr);
output_2_.set_error_handler(nullptr);
AudioDeviceTest::TearDown();
}
// Using virtualaudio, validate that device list matches what was added.
// Note: presently, just being Added doesn't necessarily make you the default!
void VirtualAudioDeviceTest::TestGetDevicesAfterAdd(bool is_input) {
std::string mfr = "Gemstone Testing";
std::string product = "Virtual Delight";
std::array<uint8_t, 16> unique_id{0};
char expected_unique_id[33];
for (uint8_t i = 0; i < 16; ++i) {
unique_id[i] = i * 0x11 + (is_input ? 1 : 0);
sprintf(expected_unique_id + i * 2, "%02hhx", unique_id[i]);
}
expected_unique_id[32] = 0;
float min_gain_db = -68.0f, max_gain_db = 1.0f, gain_step_db = 0.25f;
float cur_gain_db = -10.0f;
bool can_mute = false, cur_mute = true, can_agc = false, cur_agc = true;
SetOnDeviceAddedEvent();
if (is_input) {
input_->SetManufacturer(mfr);
input_->SetProduct(product);
input_->SetUniqueId(unique_id);
input_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
input_->Add();
} else {
output_->SetManufacturer(mfr);
output_->SetProduct(product);
output_->SetUniqueId(unique_id);
output_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
output_->Add();
// Output AGC is not supported on output devices; can_agc and cur_agc will
// always be false. System mute is enabled on all output devices, even those
// that don't support hardware-based mute. Finally, all new output devices
// (those without a settings file) are set to unmuted -12dB.
can_agc = false;
cur_agc = false;
can_mute = true;
cur_mute = false;
cur_gain_db = -12.0f;
}
ASSERT_TRUE(ExpectCallback());
uint64_t added_token = received_device_.token_id;
uint16_t num_devs = kInvalidDeviceCount;
audio_dev_enum_->GetDevices(
[this, added_token,
&num_devs](const std::vector<fuchsia::media::AudioDeviceInfo>& devices) {
received_callback_ = true;
num_devs = devices.size();
for (auto& dev : devices) {
if (added_token == dev.token_id) {
received_device_ = dev;
return;
}
}
});
EXPECT_TRUE(ExpectCallback());
// Compare every piece of the AudioDeviceInfo that we retrieved.
EXPECT_NE(received_device_.token_id, ZX_KOID_INVALID);
EXPECT_EQ(received_device_.name, mfr + " " + product);
EXPECT_EQ(strncmp(received_device_.unique_id.data(), expected_unique_id, 32),
0);
EXPECT_EQ(received_device_.is_input, is_input);
EXPECT_EQ(received_device_.gain_info.gain_db, cur_gain_db);
EXPECT_EQ(received_device_.gain_info.flags,
GainFlagsFromBools(can_mute, cur_mute, can_agc, cur_agc));
// We may have preexisting devices (real hardware), so we can't just assert
// that there is now one device in the list.
// Our device count should now be exactly one more than our initial count.
size_t preexisting_device_count =
AudioDeviceTest::initial_input_device_count_ +
AudioDeviceTest::initial_output_device_count_;
size_t expected_num_devs = preexisting_device_count + 1;
EXPECT_EQ(num_devs, expected_num_devs);
}
// Upon exit, received_default_token_ contains the newest device, and
// received_old_token_ contains the second-newest device.
void VirtualAudioDeviceTest::AddTwoDevices(bool is_input, bool is_plugged) {
std::array<uint8_t, 16> unique_id{0};
zx_time_t now = zx_clock_get_monotonic();
uint64_t old_token, new_token;
PopulateUniqueIdArr(is_input, unique_id.data());
// Add the devices
SetOnDeviceAddedEvent();
if (is_input) {
input_->SetUniqueId(unique_id);
input_->SetPlugProperties(now - 3, false, false, true);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->SetPlugProperties(now - 3, false, false, true);
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, ZX_KOID_INVALID);
// Save this for later
old_token = received_device_.token_id;
PopulateUniqueIdArr(is_input, unique_id.data());
if (is_input) {
input_2_->SetUniqueId(unique_id);
input_2_->SetPlugProperties(now - 2, false, false, true);
input_2_->Add();
} else {
output_2_->SetUniqueId(unique_id);
output_2_->SetPlugProperties(now - 2, false, false, true);
output_2_->Add();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, ZX_KOID_INVALID);
// Save this for later
new_token = received_device_.token_id;
if (is_plugged) {
// Make sure the default order is correct
SetOnDefaultDeviceChangedEvent();
if (is_input) {
input_->ChangePlugState(now - 1, true);
} else {
output_->ChangePlugState(now - 1, true);
}
ASSERT_TRUE(ExpectCallback());
ASSERT_EQ(received_default_token_, old_token);
if (is_input) {
input_2_->ChangePlugState(now, true);
} else {
output_2_->ChangePlugState(now, true);
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_default_token_, received_old_token_);
ASSERT_EQ(received_default_token_, new_token);
ASSERT_NE(received_old_token_, ZX_KOID_INVALID);
ASSERT_EQ(received_old_token_, old_token);
} else {
received_default_token_ = new_token;
received_old_token_ = old_token;
}
}
// To test GetDevices after a device removal, we first add two devices, then
// remove one (and see if GetDevices reflects the removal). Why? Certain error
// modes emerge when the removed-device is NOT the final remaining device.
void VirtualAudioDeviceTest::TestGetDevicesAfterRemove(bool is_input,
bool most_recent) {
AddTwoDevices(is_input);
uint64_t to_remove_token =
(most_recent ? received_default_token_ : received_old_token_);
uint64_t expect_default_token =
(most_recent ? received_old_token_ : received_default_token_);
if (most_recent) {
SetOnDefaultDeviceChangedEvent();
if (is_input) {
input_2_->Remove();
} else {
output_2_->Remove();
}
} else {
SetOnDeviceRemovedEvent();
if (is_input) {
input_->Remove();
} else {
output_->Remove();
}
}
// At this point, we've added two devices, then removed one.
ASSERT_TRUE(ExpectCallback());
if (most_recent) {
ASSERT_EQ(received_old_token_, to_remove_token);
ASSERT_EQ(expect_default_token, received_default_token_);
} else {
ASSERT_EQ(received_removed_token_, to_remove_token);
}
uint16_t num_devs = kInvalidDeviceCount;
audio_dev_enum_->GetDevices(
[this, to_remove_token,
&num_devs](const std::vector<fuchsia::media::AudioDeviceInfo>& devices) {
received_callback_ = true;
num_devs = devices.size();
for (auto& dev : devices) {
if (dev.is_default) {
received_default_token_ = dev.token_id;
}
// We should never enter this IF statement
if (to_remove_token == dev.token_id) {
received_device_ = dev;
return;
}
}
});
// We should receive GetDevices callback, but the device we just removed
// should not be in the list.
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_device_.token_id, kInvalidDeviceToken);
EXPECT_EQ(received_default_token_, expect_default_token);
// We may have preexisting devices (real hardware), so we can't just assert
// that there is now one device in the list.
// Our device count should now be exactly one more than our initial count.
size_t preexisting_device_count =
AudioDeviceTest::initial_input_device_count_ +
AudioDeviceTest::initial_output_device_count_;
size_t expected_num_devs = preexisting_device_count + 1;
EXPECT_EQ(num_devs, expected_num_devs);
}
void VirtualAudioDeviceTest::TestGetDevicesAfterUnplug(bool is_input,
bool most_recent) {
AddTwoDevices(is_input);
uint64_t to_unplug_token =
(most_recent ? received_default_token_ : received_old_token_);
uint64_t expect_default_token =
(most_recent ? received_old_token_ : received_default_token_);
SetOnDefaultDeviceChangedEvent();
zx_time_t now = zx_clock_get_monotonic();
if (most_recent) {
if (is_input) {
input_2_->ChangePlugState(now, false);
} else {
output_2_->ChangePlugState(now, false);
}
ASSERT_TRUE(ExpectCallback());
} else {
if (is_input) {
input_->ChangePlugState(now, false);
} else {
output_->ChangePlugState(now, false);
}
ASSERT_TRUE(ExpectTimeout());
}
// At this point, we've added two devices, then unplugged one.
uint16_t num_devs = kInvalidDeviceCount;
audio_dev_enum_->GetDevices(
[this, to_unplug_token,
&num_devs](const std::vector<fuchsia::media::AudioDeviceInfo>& devices) {
received_callback_ = true;
num_devs = devices.size();
for (auto& dev : devices) {
if (dev.is_default) {
received_default_token_ = dev.token_id;
}
if (to_unplug_token == dev.token_id) {
received_device_ = dev;
}
}
});
// We should receive callback, but device should not be default.
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_device_.token_id, to_unplug_token);
EXPECT_EQ(received_device_.is_input, is_input);
EXPECT_EQ(received_device_.is_default, false);
EXPECT_EQ(received_default_token_, expect_default_token);
// We may have preexisting devices (real hardware), so we can't just assert
// that there are now two devices in the list.
// Our device count should now be exactly two more than our initial count.
// Yes, the unplugged device should still show up in the list!
size_t preexisting_device_count =
AudioDeviceTest::initial_input_device_count_ +
AudioDeviceTest::initial_output_device_count_;
size_t expected_num_devs = preexisting_device_count + 2;
EXPECT_EQ(num_devs, expected_num_devs);
}
void VirtualAudioDeviceTest::TestGetDefaultDeviceUsingAddGetDevices(
bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
if (is_input) {
input_->SetUniqueId(unique_id);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, ZX_KOID_INVALID);
// uint64_t expected_token = received_device_.token_id;
RetrieveDefaultDevInfoUsingGetDevices(is_input);
// ASSERT_EQ(received_device_.token_id, expected_token);
uint64_t expected_token = received_device_.token_id;
RetrieveTokenUsingGetDefault(is_input);
EXPECT_EQ(received_default_token_, expected_token);
}
// validate callbacks received and default updated.
// TODO(mpuryear): test policy conditions: first Add, last Remove, subsequent
// Add, important Remove, unimportant Remove, Add(unplugged), plug change.
// Does plug status matter at all?
//
// From no-devices, GetDefault should recognize an added device as new default.
void VirtualAudioDeviceTest::TestGetDefaultDeviceAfterAdd(bool is_input) {
if (HasPreExistingDevices()) {
FXL_DLOG(INFO) << "Test case requires an environment with no audio devices";
return;
}
SetOnDefaultDeviceChangedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
if (is_input) {
input_->SetUniqueId(unique_id);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_default_token_, kInvalidDeviceToken);
uint64_t added_token = received_default_token_;
RetrieveTokenUsingGetDefault(is_input);
EXPECT_EQ(received_default_token_, added_token);
}
// From no-devices, adding an unplugged device should not make it the new
// default.
void VirtualAudioDeviceTest::TestGetDefaultDeviceAfterUnpluggedAdd(
bool is_input) {
if (HasPreExistingDevices()) {
FXL_DLOG(INFO) << "Test case requires an environment with no audio devices";
return;
}
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
zx_time_t now = zx_clock_get_monotonic();
if (is_input) {
input_->SetUniqueId(unique_id);
input_->SetPlugProperties(now, false, false, true);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->SetPlugProperties(now, false, false, true);
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_token = received_device_.token_id;
RetrieveTokenUsingGetDefault(is_input);
EXPECT_NE(received_default_token_, added_token);
EXPECT_EQ(received_default_token_, ZX_KOID_INVALID);
}
void VirtualAudioDeviceTest::TestGetDefaultDeviceAfterRemove(bool is_input,
bool most_recent) {
AddTwoDevices(is_input);
uint64_t to_remove_token =
(most_recent ? received_default_token_ : received_old_token_);
uint64_t expect_default_token =
(most_recent ? received_old_token_ : received_default_token_);
if (most_recent) {
SetOnDefaultDeviceChangedEvent();
if (is_input) {
input_2_->Remove();
} else {
output_2_->Remove();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_EQ(received_default_token_, expect_default_token);
ASSERT_EQ(received_old_token_, to_remove_token);
} else {
SetOnDeviceRemovedEvent();
if (is_input) {
input_->Remove();
} else {
output_->Remove();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_EQ(received_removed_token_, to_remove_token);
}
RetrieveTokenUsingGetDefault(is_input);
EXPECT_EQ(received_default_token_, expect_default_token);
}
void VirtualAudioDeviceTest::TestGetDefaultDeviceAfterUnplug(bool is_input,
bool most_recent) {
AddTwoDevices(is_input);
uint64_t expect_default_token =
(most_recent ? received_old_token_ : received_default_token_);
zx_time_t now = zx_clock_get_monotonic();
SetOnDefaultDeviceChangedEvent();
if (most_recent) {
if (is_input) {
input_2_->ChangePlugState(now, false);
} else {
output_2_->ChangePlugState(now, false);
}
ASSERT_TRUE(ExpectCallback());
} else {
if (is_input) {
input_->ChangePlugState(now, false);
} else {
output_->ChangePlugState(now, false);
}
ASSERT_TRUE(ExpectTimeout());
}
RetrieveTokenUsingGetDefault(is_input);
EXPECT_EQ(received_default_token_, expect_default_token);
}
// gain/mute/agc matches what was received by OnDeviceAdded?
void VirtualAudioDeviceTest::TestGetDeviceGainAfterAdd(bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
float min_gain_db, max_gain_db, gain_step_db, cur_gain_db;
bool can_mute, cur_mute, can_agc, cur_agc;
if (is_input) {
input_->SetUniqueId(unique_id);
min_gain_db = -24.0f;
max_gain_db = 0.0f;
gain_step_db = 0.5f;
cur_gain_db = -13.5f;
can_mute = true;
cur_mute = true;
can_agc = true;
cur_agc = false;
input_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
input_->Add();
// Our audio device manager allows input devices to expose AGC, and does not
// automatically add a Mute node, so we don't expect the can_agc or can_mute
// properties that we set here to be overridden (unlike with output
// devices). Also, unlike with output devices, there is no System Gain for
// input, so the device gain value that we set here will not be overridden
// with a value of -12 dB.
//
// Both types of devices (input and output devices), however, will have
// these values overridden by previously-cached values, if the unique ID
// matches to one of the settings files found.
} else {
output_->SetUniqueId(unique_id);
min_gain_db = -12.0f;
max_gain_db = 1.0f;
gain_step_db = 1.0f;
cur_gain_db = -6.0f;
can_mute = true;
cur_mute = true;
can_agc = false;
cur_agc = false;
output_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
output_->Add();
// Output AGC is not supported on output devices; can_agc and cur_agc will
// always be false. System mute is enabled on all output devices, even those
// that don't support hardware-based mute. Finally, all new output devices
// (those without a settings file) are set to unmuted -12dB.
can_agc = false;
cur_agc = false;
can_mute = true;
cur_mute = false;
cur_gain_db = -12.0f;
}
uint32_t gain_flags =
GainFlagsFromBools(can_mute, cur_mute, can_agc, cur_agc);
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_token = received_device_.token_id;
RetrieveGainInfoUsingGetDevices(added_token);
EXPECT_EQ(received_gain_info_.gain_db, cur_gain_db);
EXPECT_EQ(received_gain_info_.flags, gain_flags);
RetrieveGainInfoUsingGetDeviceGain(added_token);
EXPECT_EQ(received_gain_info_.gain_db, cur_gain_db);
EXPECT_EQ(received_gain_info_.flags, gain_flags);
}
// From GetDeviceGain, does gain/mute/agc matches what was set?
void VirtualAudioDeviceTest::TestGetDeviceGainAfterSetDeviceGain(
bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
float min_gain_db, max_gain_db, gain_step_db, cur_gain_db;
bool can_mute, cur_mute, can_agc, cur_agc;
uint32_t gain_flags, set_flags;
if (is_input) {
input_->SetUniqueId(unique_id);
min_gain_db = -24.0f;
max_gain_db = 0.0f;
gain_step_db = 0.5f;
cur_gain_db = -13.5f;
can_mute = true;
cur_mute = false;
can_agc = true;
cur_agc = false;
input_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
input_->Add();
// After Add, we'll set gain to -3.5 dB and enable AGC and Mute.
cur_gain_db = -3.5f;
cur_mute = true;
cur_agc = true;
set_flags = fuchsia::media::SetAudioGainFlag_GainValid |
fuchsia::media::SetAudioGainFlag_MuteValid |
fuchsia::media::SetAudioGainFlag_AgcValid;
} else {
output_->SetUniqueId(unique_id);
min_gain_db = -12.0f;
max_gain_db = 1.0f;
gain_step_db = 1.0f;
cur_gain_db = -6.0f;
can_mute = true;
cur_mute = false;
can_agc = false;
cur_agc = false;
output_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
output_->Add();
// After Add, we'll set gain to -7.0 dB and enable Mute.
cur_gain_db = -7.0f;
cur_mute = true;
set_flags = fuchsia::media::SetAudioGainFlag_GainValid |
fuchsia::media::SetAudioGainFlag_MuteValid;
}
gain_flags = GainFlagsFromBools(can_mute, cur_mute, can_agc, cur_agc);
// Receive the OnDeviceAdded callback
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_token = received_device_.token_id;
// SetDeviceGain to the new values
fuchsia::media::AudioGainInfo gain_info = {.gain_db = cur_gain_db,
.flags = gain_flags};
audio_dev_enum_->SetDeviceGain(added_token, gain_info, set_flags);
// Receive these changed values through GetDeviceGain
RetrieveGainInfoUsingGetDeviceGain(added_token);
EXPECT_EQ(received_gain_info_.gain_db, cur_gain_db);
EXPECT_EQ(received_gain_info_.flags, gain_flags);
}
// From GetDevices, does gain/mute/agc match what was set?
void VirtualAudioDeviceTest::TestGetDevicesAfterSetDeviceGain(bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
float min_gain_db, max_gain_db, gain_step_db, cur_gain_db;
bool can_mute, cur_mute, can_agc, cur_agc;
uint32_t gain_flags, set_flags;
if (is_input) {
input_->SetUniqueId(unique_id);
min_gain_db = -24.0f;
max_gain_db = 0.0f;
gain_step_db = 0.5f;
cur_gain_db = -13.5f;
can_mute = true;
cur_mute = true;
can_agc = true;
cur_agc = false;
input_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
input_->Add();
// After Add, we'll set gain to -23.5 dB and enable AGC and disable Mute.
cur_gain_db = -23.5f;
cur_mute = false;
cur_agc = true;
set_flags = fuchsia::media::SetAudioGainFlag_GainValid |
fuchsia::media::SetAudioGainFlag_MuteValid |
fuchsia::media::SetAudioGainFlag_AgcValid;
} else {
output_->SetUniqueId(unique_id);
min_gain_db = -22.0f;
max_gain_db = 1.0f;
gain_step_db = 1.0f;
cur_gain_db = -6.0f;
can_mute = true;
cur_mute = true;
can_agc = false;
cur_agc = false;
output_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
output_->Add();
// After Add, we'll set gain to -17.0 dB and disable Mute.
cur_gain_db = -17.0f;
cur_mute = false;
set_flags = fuchsia::media::SetAudioGainFlag_GainValid |
fuchsia::media::SetAudioGainFlag_MuteValid;
}
gain_flags = GainFlagsFromBools(can_mute, cur_mute, can_agc, cur_agc);
// Receive the OnDeviceAdded callback
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_token = received_device_.token_id;
// SetDeviceGain to the new values
fuchsia::media::AudioGainInfo gain_info = {.gain_db = cur_gain_db,
.flags = gain_flags};
audio_dev_enum_->SetDeviceGain(added_token, gain_info, set_flags);
// Receive these changed values through GetDevices
RetrieveGainInfoUsingGetDevices(added_token);
EXPECT_EQ(received_gain_info_.gain_db, cur_gain_db);
EXPECT_EQ(received_gain_info_.flags, gain_flags);
}
// Using virtual device, validate event is appropriately received/accurate.
// TODO(mpuryear): set (or reset) AGC when it isn't supported. Callback?
// ...also, do other requested changes succeed?
// gain_info (gain, flags) matches what we set? (all our changes, no more)
// Callback if no change?
// Callback if 1 invalid set_flag?
// Callback if partial success (1 valid and 1 invalid set flag, or NAN)?
// Only one callback even if multiple set_flags?
// Using virtual device, validate event is appropriately received and
// accurate. Info matches the virtual device we added? (name, id, token,
// input, gain, flags) is_default TRUE? (and does plug status matter at all?)
// Can Add only partially succeed -- if so, is callback received?
void VirtualAudioDeviceTest::TestOnDeviceAddedAfterAdd(bool is_input,
bool is_plugged) {
SetOnDeviceAddedEvent();
std::string mfr = "Royal Testing";
std::string product = "Frobazz";
std::string expected_name = mfr + " " + product;
float min_gain_db = -42.0f, max_gain_db = 2.5f, gain_step_db = 0.5f;
float cur_gain_db = -13.5f;
bool can_mute = true, cur_mute = true, can_agc = true, cur_agc = true;
uint32_t expect_flags =
GainFlagsFromBools(can_mute, cur_mute, can_agc, cur_agc);
std::array<uint8_t, 16> unique_id{0};
char expected_unique_id[33];
PopulateUniqueIdArr(is_input, unique_id.data());
for (uint8_t i = 0; i < 16; ++i) {
sprintf(expected_unique_id + i * 2, "%02hhx", unique_id[i]);
}
expected_unique_id[32] = 0;
if (is_input) {
input_->SetManufacturer(mfr);
input_->SetProduct(product);
input_->SetUniqueId(unique_id);
input_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
input_->SetPlugProperties(zx_clock_get_monotonic(), is_plugged, false,
true);
input_->Add();
} else {
output_->SetManufacturer(mfr);
output_->SetProduct(product);
output_->SetUniqueId(unique_id);
output_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
output_->SetPlugProperties(zx_clock_get_monotonic(), is_plugged, false,
true);
output_->Add();
}
EXPECT_TRUE(ExpectCallback());
// Compare every piece of AudioDeviceInfo retrieved.
EXPECT_EQ(received_device_.name, mfr + " " + product);
EXPECT_EQ(strncmp(received_device_.unique_id.data(), expected_unique_id, 32),
0);
EXPECT_NE(received_device_.token_id, kInvalidDeviceToken);
EXPECT_EQ(received_device_.is_input, is_input);
if (is_input) {
EXPECT_EQ(received_device_.gain_info.gain_db, cur_gain_db);
EXPECT_EQ(received_device_.gain_info.flags, expect_flags);
}
if (!is_plugged) {
EXPECT_EQ(received_device_.is_default, false);
}
}
void VirtualAudioDeviceTest::TestOnDeviceAddedAfterPlug(bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
zx_time_t now = zx_clock_get_monotonic();
if (is_input) {
input_->SetUniqueId(unique_id);
input_->SetPlugProperties(now - 1, false, false, true);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->SetPlugProperties(now - 1, false, false, true);
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
if (is_input) {
input_->ChangePlugState(now, true);
} else {
output_->ChangePlugState(now, true);
}
EXPECT_TRUE(ExpectTimeout());
}
void VirtualAudioDeviceTest::TestOnDeviceRemovedAfterRemove(bool is_input,
bool is_plugged) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
if (is_input) {
input_->SetUniqueId(unique_id);
if (!is_plugged) {
input_->SetPlugProperties(zx_clock_get_monotonic(), false, false, true);
}
input_->Add();
} else {
output_->SetUniqueId(unique_id);
if (!is_plugged) {
output_->SetPlugProperties(zx_clock_get_monotonic(), false, false, true);
}
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
uint64_t token = received_device_.token_id;
ASSERT_NE(token, ZX_KOID_INVALID);
SetOnDeviceRemovedEvent();
if (is_input) {
input_->Remove();
} else {
output_->Remove();
}
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_removed_token_, token);
}
void VirtualAudioDeviceTest::TestOnDeviceRemovedAfterUnplug(bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
if (is_input) {
input_->SetUniqueId(unique_id);
input_->SetPlugProperties(zx_clock_get_monotonic(), true, false, true);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->SetPlugProperties(zx_clock_get_monotonic(), true, false, true);
output_->Add();
}
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, ZX_KOID_INVALID);
SetOnDeviceRemovedEvent();
zx_time_t now = zx_clock_get_monotonic();
if (is_input) {
input_->ChangePlugState(now, false);
} else {
output_->ChangePlugState(now, false);
}
EXPECT_TRUE(ExpectTimeout());
}
// Using virtual device, validate event is appropriately received and
// accurate. Previous default matches what we did get from GetDevices Previous
// default matches what we did get from GetDefault New default matches what we
// now get from GetDevices New default matches what we now get from GetDefault
// Conditions: first Add, last Remove, subsequent Add, important Remove,
// unimportant Remove, Add(unplugged), plug change
void VirtualAudioDeviceTest::TestOnDefaultDeviceChangedAfterAdd(bool is_input) {
if (HasPreExistingDevices()) {
FXL_DLOG(INFO) << "Test case requires an environment with no audio devices";
return;
}
SetOnDeviceAddedEvent();
SetOnDefaultDeviceChangedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
if (is_input) {
input_->SetUniqueId(unique_id);
input_->Add();
} else {
output_->SetUniqueId(unique_id);
output_->Add();
}
EXPECT_TRUE(ExpectCallback());
// We need both callbacks to have happened!
if (received_device_.token_id == kInvalidDeviceToken ||
received_default_token_ == kInvalidDeviceToken) {
uint64_t new_token = received_default_token_;
uint64_t old_token = received_old_token_;
uint64_t add_token = received_device_.token_id;
EXPECT_TRUE(ExpectCallback());
if (add_token != kInvalidDeviceToken) {
received_device_.token_id = add_token;
}
if (new_token != kInvalidDeviceToken) {
received_default_token_ = new_token;
received_old_token_ = old_token;
}
}
EXPECT_EQ(received_device_.token_id, received_default_token_);
EXPECT_EQ((is_input ? AudioDeviceTest::initial_input_default_
: AudioDeviceTest::initial_output_default_),
received_old_token_);
}
// Test the OnDefaultDeviceChanged event, after a device is Plugged. We do this
// using two virtual devices -- after adding the first device (with a certain
// plugged-time), we Plug the second one and see how things change.
//
// The most_recent flag indicates whether the device to be plugged will report a
// plugged-time that makes it most-recently-plugged (and thus should become the
// new default). If most_recent is false, then we make the plugged-time for this
// second device _immediately_ before the plugged-time for the first device.
void VirtualAudioDeviceTest::TestOnDefaultDeviceChangedAfterPlug(
bool is_input, bool most_recent) {
AddTwoDevices(is_input, false);
uint64_t token1 = received_old_token_;
uint64_t token2 = received_default_token_;
RetrieveTokenUsingGetDefault(is_input);
uint64_t default_token = received_default_token_;
zx_time_t now = zx_clock_get_monotonic();
SetOnDefaultDeviceChangedEvent();
// We'll say that this first device was plugged just 1 ns ago...
if (is_input) {
input_->ChangePlugState(now - 1, true);
} else {
output_->ChangePlugState(now - 1, true);
}
if (default_token != token1) {
ASSERT_TRUE(ExpectCallback());
}
// If this second device is to be Most-Recently-Plugged, make its plugged-time
// 1 ns after the first -- otherwise make it 1 ns BEFORE the first.
zx_time_t plug_time = (most_recent ? now : (now - 2));
if (is_input) {
input_2_->ChangePlugState(plug_time, true);
} else {
output_2_->ChangePlugState(plug_time, true);
}
if (most_recent) {
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_old_token_, token1);
EXPECT_EQ(received_default_token_, token2);
} else {
EXPECT_TRUE(ExpectTimeout());
}
}
void VirtualAudioDeviceTest::TestOnDefaultDeviceChangedAfterRemove(
bool is_input, bool most_recent) {
AddTwoDevices(is_input);
uint64_t to_remove_token =
(most_recent ? received_default_token_ : received_old_token_);
uint64_t expect_default_token =
(most_recent ? received_old_token_ : received_default_token_);
SetOnDefaultDeviceChangedEvent();
if (most_recent) {
if (is_input) {
input_2_->Remove();
} else {
output_2_->Remove();
}
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_default_token_, expect_default_token);
EXPECT_EQ(received_old_token_, to_remove_token);
} else {
if (is_input) {
input_->Remove();
} else {
output_->Remove();
}
EXPECT_TRUE(ExpectTimeout());
}
}
void VirtualAudioDeviceTest::TestOnDefaultDeviceChangedAfterUnplug(
bool is_input, bool most_recent) {
AddTwoDevices(is_input);
uint64_t to_unplug_token =
(most_recent ? received_default_token_ : received_old_token_);
uint64_t expect_default_token =
(most_recent ? received_old_token_ : received_default_token_);
zx_time_t now = zx_clock_get_monotonic();
SetOnDefaultDeviceChangedEvent();
if (most_recent) {
if (is_input) {
input_2_->ChangePlugState(now, false);
} else {
output_2_->ChangePlugState(now, false);
}
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_default_token_, expect_default_token);
EXPECT_EQ(received_old_token_, to_unplug_token);
} else {
if (is_input) {
input_->ChangePlugState(now, false);
} else {
output_->ChangePlugState(now, false);
}
EXPECT_TRUE(ExpectTimeout());
}
}
// From GetDevices, does gain/mute/agc match what was set?
void VirtualAudioDeviceTest::TestOnDeviceGainChanged(bool is_input) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(is_input, unique_id.data());
float min_gain_db, max_gain_db, gain_step_db, cur_gain_db;
bool can_mute, cur_mute, can_agc, cur_agc;
uint32_t gain_flags, set_flags;
if (is_input) {
input_->SetUniqueId(unique_id);
min_gain_db = -24.0f;
max_gain_db = 0.0f;
gain_step_db = 0.5f;
cur_gain_db = -13.5f;
can_mute = true;
cur_mute = true;
can_agc = true;
cur_agc = false;
input_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
input_->Add();
// After Add, we'll set gain to -23.5 dB and enable AGC and disable Mute.
cur_gain_db = -23.5f;
cur_mute = false;
cur_agc = true;
set_flags = fuchsia::media::SetAudioGainFlag_GainValid |
fuchsia::media::SetAudioGainFlag_MuteValid |
fuchsia::media::SetAudioGainFlag_AgcValid;
} else {
output_->SetUniqueId(unique_id);
min_gain_db = -22.0f;
max_gain_db = 1.0f;
gain_step_db = 1.0f;
cur_gain_db = -6.0f;
can_mute = true;
cur_mute = true;
can_agc = false;
cur_agc = false;
output_->SetGainProperties(min_gain_db, max_gain_db, gain_step_db,
cur_gain_db, can_mute, cur_mute, can_agc,
cur_agc);
output_->Add();
// After Add, we'll set gain to -17.0 dB and disable Mute.
cur_gain_db = -17.0f;
cur_mute = false;
set_flags = fuchsia::media::SetAudioGainFlag_GainValid |
fuchsia::media::SetAudioGainFlag_MuteValid;
}
gain_flags = GainFlagsFromBools(can_mute, cur_mute, can_agc, cur_agc);
// Receive the OnDeviceAdded callback
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_token = received_device_.token_id;
// SetDeviceGain to the new values
fuchsia::media::AudioGainInfo gain_info = {.gain_db = cur_gain_db,
.flags = gain_flags};
SetOnDeviceGainChangedEvent();
audio_dev_enum_->SetDeviceGain(added_token, gain_info, set_flags);
// Receive the OnDeviceGainChanged callback
EXPECT_TRUE(ExpectCallback());
EXPECT_EQ(received_gain_info_.gain_db, cur_gain_db);
EXPECT_EQ(received_gain_info_.flags, gain_flags);
}
//
// VirtualAudioDeviceTest -- test cases that use the virtualaudio mechanism
//
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesAddInput) {
TestGetDevicesAfterAdd(true);
}
// Remove input (default changed) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesRemoveDefaultInput) {
TestGetDevicesAfterRemove(true, true);
}
// Remove input (default didn't change) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesRemoveNotDefaultInput) {
TestGetDevicesAfterRemove(true, false);
}
// Unplug input (default changed) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesUnplugDefaultInput) {
TestGetDevicesAfterUnplug(true, true);
}
// Unplug input (default didn't change) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesUnplugNotDefaultInput) {
TestGetDevicesAfterUnplug(true, false);
}
// After SetDeviceGain, GetDevices should reflect the gain change
// Do basic validation that we don't change more than set_flags specifies.
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesSetDeviceGainInput) {
TestGetDevicesAfterSetDeviceGain(true);
}
// Using virtualaudio, validate that device list matches what was added.
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesAddOutput) {
TestGetDevicesAfterAdd(false);
}
// Remove output (default changed) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesRemoveDefaultOutput) {
TestGetDevicesAfterRemove(false, true);
}
// Remove output (default didn't change) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesRemoveNotDefaultOutput) {
TestGetDevicesAfterRemove(false, false);
}
// Unplug output (default changed) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesUnplugDefaultOutput) {
TestGetDevicesAfterUnplug(false, true);
}
// Unplug output (default didn't change) then GetDevices
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesUnplugNotDefaultOutput) {
TestGetDevicesAfterUnplug(false, false);
}
// After SetDeviceGain, GetDevices should reflect the gain change
// Do basic validation that we don't change more than set_flags specifies.
TEST_F(VirtualAudioDeviceTest, GetDevicesMatchesSetDeviceGainOutput) {
TestGetDevicesAfterSetDeviceGain(false);
}
TEST_F(VirtualAudioDeviceTest, GetDefaultInputDeviceMatchesUnpluggedAdd) {
TestGetDefaultDeviceAfterUnpluggedAdd(true);
}
// Remove (default changed) then GetDefaultInputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultInputDeviceMatchesRemoveDefault) {
TestGetDefaultDeviceAfterRemove(true, true);
}
// Remove (default didn't change) then GetDefaultInputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultInputDeviceMatchesRemoveNotDefault) {
TestGetDefaultDeviceAfterRemove(true, false);
}
// Unplug (default changed) then GetDefaultInputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultInputDeviceMatchesUnplugDefault) {
TestGetDefaultDeviceAfterUnplug(true, true);
}
// Unplug (default didn't change) then GetDefaultInputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultInputDeviceMatchesUnplugNotDefault) {
TestGetDefaultDeviceAfterUnplug(true, false);
}
TEST_F(VirtualAudioDeviceTest, GetDefaultOutputDeviceMatchesUnpluggedAdd) {
TestGetDefaultDeviceAfterUnpluggedAdd(false);
}
// Remove (default changed) then GetDefaultOutputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultOutputDeviceMatchesRemoveDefault) {
TestGetDefaultDeviceAfterRemove(false, true);
}
// Remove (default didn't change) then GetDefaultOutputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultOutputDeviceMatchesRemoveNotDefault) {
TestGetDefaultDeviceAfterRemove(false, false);
}
// Unplug (default changed) then GetDefaultOutputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultOutputDeviceMatchesUnplugDefault) {
TestGetDefaultDeviceAfterUnplug(false, true);
}
// Unplug (default didn't change) then GetDefaultOutputDevice
TEST_F(VirtualAudioDeviceTest, GetDefaultOutputDeviceMatchesUnplugNotDefault) {
TestGetDefaultDeviceAfterUnplug(false, false);
}
// After SetDeviceGain, GetDeviceGain should reflect the gain change
TEST_F(VirtualAudioDeviceTest, GetDeviceGainMatchesInputSetDeviceGain) {
TestGetDeviceGainAfterSetDeviceGain(true);
}
// After SetDeviceGain, GetDeviceGain should reflect the gain change
TEST_F(VirtualAudioDeviceTest, GetDeviceGainMatchesOutputSetDeviceGain) {
TestGetDeviceGainAfterSetDeviceGain(false);
}
TEST_F(VirtualAudioDeviceTest, GetDeviceGainOfRemovedOutput) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(false, unique_id.data());
output_->SetUniqueId(unique_id);
output_->Add();
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_token = received_device_.token_id;
SetOnDeviceRemovedEvent();
output_->Remove();
ASSERT_TRUE(ExpectCallback());
ASSERT_EQ(received_removed_token_, added_token);
RetrieveGainInfoUsingGetDeviceGain(received_removed_token_, false);
}
// Given invalid params to SetDeviceGain, FIDL interface should not
// disconnect. These 4 params include device token_id, gain_db, gain flags,
// and set flags.
TEST_F(VirtualAudioDeviceTest, SetDeviceGainOfBadValues) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(false, unique_id.data());
output_->SetUniqueId(unique_id);
PopulateUniqueIdArr(true, unique_id.data());
input_->SetUniqueId(unique_id);
input_->Add();
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t in_token = received_device_.token_id;
output_->Add();
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t out_token = received_device_.token_id;
// The explicitly-invalid token_id
audio_dev_enum_->SetDeviceGain(
ZX_KOID_INVALID, {.gain_db = 0.0f, .flags = kGainFlagMask}, kSetFlagMask);
// A device token_id that does not correctly refer to a device
audio_dev_enum_->SetDeviceGain(kInvalidDeviceToken,
{.gain_db = 0.0f, .flags = kGainFlagMask},
kSetFlagMask);
// An invalid gain_db value
audio_dev_enum_->SetDeviceGain(
in_token, {.gain_db = NAN, .flags = kGainFlagMask}, kSetFlagMask);
audio_dev_enum_->SetDeviceGain(
out_token, {.gain_db = NAN, .flags = kGainFlagMask}, kSetFlagMask);
// Invalid gain flags (set bits outside the defined ones)
audio_dev_enum_->SetDeviceGain(
in_token, {.gain_db = 0.0f, .flags = ~kGainFlagMask}, kSetFlagMask);
audio_dev_enum_->SetDeviceGain(
out_token, {.gain_db = 0.0f, .flags = ~kGainFlagMask}, kSetFlagMask);
// Invalid set flags (set bits outside the defined ones)
audio_dev_enum_->SetDeviceGain(
in_token, {.gain_db = 0.0f, .flags = kGainFlagMask}, ~kSetFlagMask);
audio_dev_enum_->SetDeviceGain(
out_token, {.gain_db = 0.0f, .flags = kGainFlagMask}, ~kSetFlagMask);
// We should not disconnect.
EXPECT_TRUE(ExpectTimeout());
}
// SetDeviceGain of previously-valid, removed dev should silently do nothing.
TEST_F(VirtualAudioDeviceTest, SetDeviceGainOfRemovedInput) {
SetOnDeviceAddedEvent();
std::array<uint8_t, 16> unique_id{0};
PopulateUniqueIdArr(true, unique_id.data());
input_->SetUniqueId(unique_id);
input_->Add();
ASSERT_TRUE(ExpectCallback());
ASSERT_NE(received_device_.token_id, kInvalidDeviceToken);
uint64_t added_dev_token = received_device_.token_id;
SetOnDeviceRemovedEvent();
input_->Remove();
ASSERT_TRUE(ExpectCallback());
ASSERT_EQ(received_removed_token_, added_dev_token);
uint64_t removed_dev_token = received_removed_token_;
SetOnDeviceGainChangedEvent();
audio_dev_enum_->SetDeviceGain(removed_dev_token,
{.gain_db = 0.0f, .flags = 0}, kSetFlagMask);
// We should receive neither callback nor disconnect.
EXPECT_TRUE(ExpectTimeout());
}
TEST_F(VirtualAudioDeviceTest, OnDeviceAddedNotTriggeredByPlugInput) {
TestOnDeviceAddedAfterPlug(true);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceAddedMatchesAddPluggedOutput) {
// Add a plugged-in device
TestOnDeviceAddedAfterAdd(false, true);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceAddedMatchesAddUnpluggedOutput) {
// Add an unplugged device
TestOnDeviceAddedAfterAdd(false, false);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceAddedNotTriggeredByPlugOutput) {
TestOnDeviceAddedAfterPlug(false);
}
// Using virtual device, validate event is appropriately received and
// accurate. Token matches the virtual device we removed? Can Remove only
// partially succeed -- if so, is callback received? What if previous Add had
// only partially succeeded?
TEST_F(VirtualAudioDeviceTest, OnDeviceRemovedMatchesRemovePluggedInput) {
// Remove a plugged input device
TestOnDeviceRemovedAfterRemove(true, true);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceRemovedMatchesRemoveUnpluggedInput) {
// Remove an unplugged input device
TestOnDeviceRemovedAfterRemove(true, false);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceRemovedNotTriggeredByUnplugInput) {
TestOnDeviceRemovedAfterUnplug(true);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceRemovedMatchesRemovePluggedOutput) {
// Remove a plugged output device
TestOnDeviceRemovedAfterRemove(false, true);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceRemovedMatchesRemoveUnpluggedOutput) {
// Remove an unplugged output device
TestOnDeviceRemovedAfterRemove(false, false);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceRemovedNotTriggeredByUnplugOutput) {
TestOnDeviceRemovedAfterUnplug(false);
}
// Plug an input at most-recent-timestamp
//
// TODO(mpuryear): When we honor the plug-change timestamp (instead of merely
// treating all plug changes as NOW), test the not-most-recent scenario.
TEST_F(VirtualAudioDeviceTest, OnDefaultDeviceChangedMatchesPlugDefaultInput) {
TestOnDefaultDeviceChangedAfterPlug(true, true);
}
// Remove (default changed) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesRemoveDefaultInput) {
TestOnDefaultDeviceChangedAfterRemove(true, true);
}
// Remove (default didn't change) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesRemoveNotDefaultInput) {
TestOnDefaultDeviceChangedAfterRemove(true, false);
}
// Unplug (default changed) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesUnplugDefaultInput) {
TestOnDefaultDeviceChangedAfterUnplug(true, true);
}
// Unplug (default didn't change) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesUnplugNotDefaultInput) {
TestOnDefaultDeviceChangedAfterUnplug(true, false);
}
// Plug an output at most-recent-timestamp
//
// TODO(mpuryear): When we honor the plug-change timestamp (instead of merely
// treating all plug changes as NOW), test the not-most-recent scenario.
TEST_F(VirtualAudioDeviceTest, OnDefaultDeviceChangedMatchesPlugDefaultOutput) {
TestOnDefaultDeviceChangedAfterPlug(false, true);
}
// Remove (default changed) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesRemoveDefaultOutput) {
TestOnDefaultDeviceChangedAfterRemove(false, true);
}
// Remove (default didn't change) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesRemoveNotDefaultOutput) {
TestOnDefaultDeviceChangedAfterRemove(false, false);
}
// Unplug (default changed) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesUnplugDefaultOutput) {
TestOnDefaultDeviceChangedAfterUnplug(false, true);
}
// Unplug (default didn't change) -> OnDefaultDeviceChanged
TEST_F(VirtualAudioDeviceTest,
OnDefaultDeviceChangedMatchesUnplugNotDefaultOutput) {
TestOnDefaultDeviceChangedAfterUnplug(false, false);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceGainChangedMatchesSetDeviceGainInput) {
TestOnDeviceGainChanged(true);
}
TEST_F(VirtualAudioDeviceTest, OnDeviceGainChangedMatchesSetDeviceGainOutput) {
TestOnDeviceGainChanged(false);
}
} // namespace media::audio::test