Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Unified Diff: chromeos/audio/cras_audio_handler_unittest.cc

Issue 1746843002: Persist the user's active audio device choice across chromeos session and reboots. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix nits. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chromeos/audio/cras_audio_handler.cc ('k') | chromeos/dbus/cras_audio_client.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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());
« no previous file with comments | « chromeos/audio/cras_audio_handler.cc ('k') | chromeos/dbus/cras_audio_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698