| Index: chromeos/audio/cras_audio_handler_unittest.cc
|
| diff --git a/chromeos/audio/cras_audio_handler_unittest.cc b/chromeos/audio/cras_audio_handler_unittest.cc
|
| index de2c1e48b172f700b3a328b0811ddcdaa0e8750f..95660658f5a15621d91d0e664dadcc4d9aaa4cdd 100644
|
| --- a/chromeos/audio/cras_audio_handler_unittest.cc
|
| +++ b/chromeos/audio/cras_audio_handler_unittest.cc
|
| @@ -15,6 +15,7 @@
|
| #include "base/run_loop.h"
|
| #include "base/thread_task_runner_handle.h"
|
| #include "base/values.h"
|
| +#include "chromeos/audio/audio_devices_pref_handler.h"
|
| #include "chromeos/audio/audio_devices_pref_handler_stub.h"
|
| #include "chromeos/dbus/audio_node.h"
|
| #include "chromeos/dbus/dbus_thread_manager.h"
|
| @@ -324,6 +325,40 @@ class CrasAudioHandlerTest : public testing::Test {
|
| message_loop_.RunUntilIdle();
|
| }
|
|
|
| + // Set up cras audio handlers with |audio_nodes| and set the active state of
|
| + // |active_device_in_pref| as active and |activate_by_user| in the pref,
|
| + // and rest of nodes in |audio_nodes_in_pref| as inactive.
|
| + void SetupCrasAudioHandlerWithActiveNodeInPref(
|
| + const AudioNodeList& audio_nodes,
|
| + const AudioNodeList& audio_nodes_in_pref,
|
| + const AudioDevice& active_device_in_pref,
|
| + bool activate_by_user) {
|
| + DBusThreadManager::Initialize();
|
| + fake_cras_audio_client_ = static_cast<FakeCrasAudioClient*>(
|
| + DBusThreadManager::Get()->GetCrasAudioClient());
|
| + audio_pref_handler_ = new AudioDevicesPrefHandlerStub();
|
| + bool active;
|
| + for (const AudioNode& node : audio_nodes_in_pref) {
|
| + active = node.id == active_device_in_pref.id;
|
| + audio_pref_handler_->SetDeviceActive(AudioDevice(node), active,
|
| + activate_by_user);
|
| + }
|
| +
|
| + bool activate_by;
|
| + EXPECT_TRUE(audio_pref_handler_->GetDeviceActive(active_device_in_pref,
|
| + &active, &activate_by));
|
| + EXPECT_TRUE(active);
|
| + EXPECT_EQ(activate_by, activate_by_user);
|
| +
|
| + fake_cras_audio_client_->SetAudioNodesForTesting(audio_nodes);
|
| + CrasAudioHandler::Initialize(audio_pref_handler_);
|
| +
|
| + cras_audio_handler_ = CrasAudioHandler::Get();
|
| + test_observer_.reset(new TestObserver);
|
| + cras_audio_handler_->AddAudioObserver(test_observer_.get());
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| void SetUpCrasAudioHandlerWithPrimaryActiveNode(
|
| const AudioNodeList& audio_nodes,
|
| const AudioNode& primary_active_node) {
|
| @@ -559,7 +594,8 @@ TEST_F(CrasAudioHandlerTest, SwitchActiveOutputDevice) {
|
|
|
| // Switch the active output to internal speaker.
|
| AudioDevice internal_speaker(kInternalSpeaker);
|
| - cras_audio_handler_->SwitchToDevice(internal_speaker, true);
|
| + cras_audio_handler_->SwitchToDevice(internal_speaker, true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
|
|
| // Verify the active output is switched to internal speaker, and the
|
| // ActiveOutputNodeChanged event is fired.
|
| @@ -586,7 +622,8 @@ TEST_F(CrasAudioHandlerTest, SwitchActiveInputDevice) {
|
|
|
| // Switch the active input to internal mic.
|
| AudioDevice internal_mic(kInternalMic);
|
| - cras_audio_handler_->SwitchToDevice(internal_mic, true);
|
| + cras_audio_handler_->SwitchToDevice(internal_mic, true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
|
|
| // Verify the active output is switched to internal speaker, and the active
|
| // ActiveInputNodeChanged event is fired.
|
| @@ -1140,7 +1177,8 @@ TEST_F(CrasAudioHandlerTest, UnplugUSBHeadphonesWithActiveSpeaker) {
|
|
|
| // Select the speaker to be the active output device.
|
| AudioDevice internal_speaker(kInternalSpeaker);
|
| - cras_audio_handler_->SwitchToDevice(internal_speaker, true);
|
| + cras_audio_handler_->SwitchToDevice(internal_speaker, true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
|
|
| // Verify the active output is switched to internal speaker, and the
|
| // ActiveOutputNodeChanged event is fired.
|
| @@ -1371,7 +1409,8 @@ TEST_F(CrasAudioHandlerTest, PlugUSBMicNotAffectActiveOutput) {
|
|
|
| // Switch the active output to internal speaker.
|
| AudioDevice internal_speaker(kInternalSpeaker);
|
| - cras_audio_handler_->SwitchToDevice(internal_speaker, true);
|
| + cras_audio_handler_->SwitchToDevice(internal_speaker, true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
|
|
| // Verify the active output is switched to internal speaker, and the
|
| // ActiveOutputNodeChanged event is fired.
|
| @@ -2066,7 +2105,8 @@ TEST_F(CrasAudioHandlerTest, ActiveDeviceSelectionWithStableDeviceId) {
|
| // Change the active device to internal speaker, now USB headphone becomes
|
| // inactive.
|
| AudioDevice speaker(kInternalSpeaker);
|
| - cras_audio_handler_->SwitchToDevice(speaker, true);
|
| + cras_audio_handler_->SwitchToDevice(speaker, true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
| EXPECT_NE(kUSBHeadphone1.id,
|
| cras_audio_handler_->GetPrimaryActiveOutputNode());
|
|
|
| @@ -2112,6 +2152,11 @@ TEST_F(CrasAudioHandlerTest, ActiveDeviceSelectionWithStableDeviceId) {
|
| // by its priority.
|
| EXPECT_EQ(usb_headset.id, cras_audio_handler_->GetPrimaryActiveOutputNode());
|
|
|
| + audio_nodes.clear();
|
| + internal_speaker.active = false;
|
| + audio_nodes.push_back(internal_speaker);
|
| + usb_headset.active = true;
|
| + audio_nodes.push_back(usb_headset);
|
| usb_headset2.active = false;
|
| usb_headset2.plugged_time = 80000002;
|
| audio_nodes.push_back(usb_headset2);
|
| @@ -2122,6 +2167,212 @@ TEST_F(CrasAudioHandlerTest, ActiveDeviceSelectionWithStableDeviceId) {
|
| EXPECT_EQ(usb_headset2.id, cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| }
|
|
|
| +// Test the device new session case, either via reboot or logout, if there
|
| +// is an active device in the previous session, that device should still
|
| +// be set as active after the new session starts.
|
| +TEST_F(CrasAudioHandlerTest, PersistActiveDeviceAcrossSession) {
|
| + // Set the active device to internal speaker before the session starts.
|
| + AudioNodeList audio_nodes;
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kHeadphone);
|
| + SetupCrasAudioHandlerWithActiveNodeInPref(
|
| + audio_nodes, audio_nodes, AudioDevice(kInternalSpeaker), true);
|
| +
|
| + // Verify the audio devices size.
|
| + AudioDeviceList audio_devices;
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| +
|
| + // Verify the active device is the internal speaker, which is of a lower
|
| + // priority, but selected as active since it was the active device previously.
|
| + EXPECT_EQ(kInternalSpeaker.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +}
|
| +
|
| +TEST_F(CrasAudioHandlerTest, PersistActiveSpeakerAcrossReboot) {
|
| + // Simulates the device was shut down with three audio devices, and
|
| + // internal speaker being the active one selected by user.
|
| + AudioNodeList audio_nodes_in_pref;
|
| + audio_nodes_in_pref.push_back(kInternalSpeaker);
|
| + audio_nodes_in_pref.push_back(kHeadphone);
|
| + audio_nodes_in_pref.push_back(kUSBHeadphone1);
|
| +
|
| + // Simulate the first NodesChanged signal coming with only one node.
|
| + AudioNodeList audio_nodes;
|
| + audio_nodes.push_back(kUSBHeadphone1);
|
| +
|
| + SetupCrasAudioHandlerWithActiveNodeInPref(
|
| + audio_nodes, audio_nodes_in_pref, AudioDevice(kInternalSpeaker), true);
|
| +
|
| + // Verify the usb headphone has been made active.
|
| + AudioDeviceList audio_devices;
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kUSBHeadphone1.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +
|
| + // Simulate another NodesChanged signal coming later with all ndoes.
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kHeadphone);
|
| + ChangeAudioNodes(audio_nodes);
|
| +
|
| + // Verify the active output has been restored to internal speaker.
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kInternalSpeaker.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +}
|
| +
|
| +TEST_F(CrasAudioHandlerTest,
|
| + PersistActiveUsbHeadphoneAcrossRebootUsbComeLater) {
|
| + // Simulates the device was shut down with three audio devices, and
|
| + // usb headphone being the active one selected by priority.
|
| + AudioNodeList audio_nodes_in_pref;
|
| + audio_nodes_in_pref.push_back(kInternalSpeaker);
|
| + audio_nodes_in_pref.push_back(kHeadphone);
|
| + audio_nodes_in_pref.push_back(kUSBHeadphone1);
|
| +
|
| + // Simulate the first NodesChanged signal coming with only internal speaker
|
| + // and the headphone.
|
| + AudioNodeList audio_nodes;
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kHeadphone);
|
| +
|
| + SetupCrasAudioHandlerWithActiveNodeInPref(audio_nodes, audio_nodes_in_pref,
|
| + AudioDevice(kUSBHeadphone1), false);
|
| +
|
| + // Verify the headphone has been made active.
|
| + AudioDeviceList audio_devices;
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kHeadphone.id, cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +
|
| + // Simulate USB node comes later with all ndoes.
|
| + AudioNode usb_node(kUSBHeadphone1);
|
| + usb_node.plugged_time = 80000000;
|
| + audio_nodes.push_back(usb_node);
|
| + ChangeAudioNodes(audio_nodes);
|
| +
|
| + // Verify the active output has been restored to usb headphone.
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kUSBHeadphone1.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +}
|
| +
|
| +TEST_F(CrasAudioHandlerTest,
|
| + PersistActiveUsbHeadphoneAcrossRebootUsbComeFirst) {
|
| + // Simulates the device was shut down with three audio devices, and
|
| + // usb headphone being the active one selected by priority.
|
| + AudioNodeList audio_nodes_in_pref;
|
| + audio_nodes_in_pref.push_back(kInternalSpeaker);
|
| + audio_nodes_in_pref.push_back(kHeadphone);
|
| + audio_nodes_in_pref.push_back(kUSBHeadphone1);
|
| +
|
| + // Simulate the first NodesChanged signal coming with only internal speaker
|
| + // and the USB headphone.
|
| + AudioNodeList audio_nodes;
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kUSBHeadphone1);
|
| +
|
| + SetupCrasAudioHandlerWithActiveNodeInPref(audio_nodes, audio_nodes_in_pref,
|
| + AudioDevice(kUSBHeadphone1), false);
|
| +
|
| + // Verify the USB headphone has been made active.
|
| + AudioDeviceList audio_devices;
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kUSBHeadphone1.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +
|
| + // Simulate another NodesChanged signal coming later with all ndoes.
|
| + AudioNode headphone_node(kHeadphone);
|
| + headphone_node.plugged_time = 80000000;
|
| + audio_nodes.push_back(headphone_node);
|
| + ChangeAudioNodes(audio_nodes);
|
| +
|
| + // Verify the active output has been restored to USB headphone.
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kUSBHeadphone1.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +}
|
| +
|
| +// This covers the crbug.com/586026. Cras lost the active state of the internal
|
| +// speaker when user unplugs the headphone, which is a bug in cras. However,
|
| +// chrome code is still resilient and set the internal speaker back to active.
|
| +TEST_F(CrasAudioHandlerTest, UnplugHeadphoneLostActiveInternalSpeakerByCras) {
|
| + // Set up with three nodes.
|
| + AudioNodeList audio_nodes;
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kHeadphone);
|
| + audio_nodes.push_back(kUSBHeadphone1);
|
| + SetUpCrasAudioHandler(audio_nodes);
|
| +
|
| + // Switch the active output to internal speaker.
|
| + cras_audio_handler_->SwitchToDevice(AudioDevice(kInternalSpeaker), true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
| +
|
| + // Verify internal speaker has been made active.
|
| + AudioDeviceList audio_devices;
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kInternalSpeaker.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +
|
| + // Simulate unplug the headphone. Cras sends NodesChanged signal with
|
| + // both internal speaker and usb headphone being inactive.
|
| + audio_nodes.clear();
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kUSBHeadphone1);
|
| + EXPECT_FALSE(kInternalSpeaker.active);
|
| + EXPECT_FALSE(kUSBHeadphone1.active);
|
| + ChangeAudioNodes(audio_nodes);
|
| +
|
| + // Verify the active output is set back to internal speaker.
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kInternalSpeaker.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +}
|
| +
|
| +TEST_F(CrasAudioHandlerTest, RemoveNonActiveDevice) {
|
| + // Set up with three nodes.
|
| + AudioNodeList audio_nodes;
|
| + audio_nodes.push_back(kInternalSpeaker);
|
| + audio_nodes.push_back(kHeadphone);
|
| + audio_nodes.push_back(kUSBHeadphone1);
|
| + SetUpCrasAudioHandler(audio_nodes);
|
| +
|
| + // Switch the active output to internal speaker.
|
| + cras_audio_handler_->SwitchToDevice(AudioDevice(kInternalSpeaker), true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
| +
|
| + // Verify internal speaker has been made active.
|
| + AudioDeviceList audio_devices;
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kInternalSpeaker.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +
|
| + // Remove headphone, which is an non-active device.
|
| + audio_nodes.clear();
|
| + AudioNode speaker(kInternalSpeaker);
|
| + speaker.active = true;
|
| + audio_nodes.push_back(speaker);
|
| + AudioNode usb_headphone(kUSBHeadphone1);
|
| + usb_headphone.active = false;
|
| + audio_nodes.push_back(usb_headphone);
|
| +
|
| + ChangeAudioNodes(audio_nodes);
|
| +
|
| + // Verify the active output remains as internal speaker.
|
| + cras_audio_handler_->GetAudioDevices(&audio_devices);
|
| + EXPECT_EQ(audio_nodes.size(), audio_devices.size());
|
| + EXPECT_EQ(kInternalSpeaker.id,
|
| + cras_audio_handler_->GetPrimaryActiveOutputNode());
|
| +}
|
| +
|
| TEST_F(CrasAudioHandlerTest, ChangeActiveNodesHotrodInit) {
|
| AudioNodeList audio_nodes;
|
| audio_nodes.push_back(kHDMIOutput);
|
| @@ -2552,7 +2803,8 @@ TEST_F(CrasAudioHandlerTest, HotPlugHDMINotChangeActiveOutput) {
|
|
|
| // Manually set the active output to internal speaker.
|
| AudioDevice internal_output(kInternalSpeaker);
|
| - cras_audio_handler_->SwitchToDevice(internal_output, true);
|
| + cras_audio_handler_->SwitchToDevice(internal_output, true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
|
|
| // Verify the active output is switched to internal speaker.
|
| EXPECT_EQ(internal_speaker.id,
|
| @@ -2631,7 +2883,8 @@ TEST_F(CrasAudioHandlerTest, HDMIRemainInactiveAfterSuspendResume) {
|
| EXPECT_EQ(hdmi_output.id, cras_audio_handler_->GetPrimaryActiveOutputNode());
|
|
|
| // Manually set the active output to internal speaker.
|
| - cras_audio_handler_->SwitchToDevice(AudioDevice(internal_speaker), true);
|
| + cras_audio_handler_->SwitchToDevice(AudioDevice(internal_speaker), true,
|
| + CrasAudioHandler::ACTIVATE_BY_USER);
|
| EXPECT_EQ(internal_speaker.id,
|
| cras_audio_handler_->GetPrimaryActiveOutputNode());
|
|
|
|
|