Chromium Code Reviews| 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..306d43aefbd72167d7f7419b523558471f4fbb0d 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_PRIORITY); |
|
hychao
2016/03/02 15:34:05
When there are headphone and USB-headphone plugged
jennyz
2016/03/02 19:33:37
Good catch. Fixed.
|
| + |
| + // 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_PRIORITY); |
|
hychao
2016/03/02 15:34:05
same question as above
jennyz
2016/03/02 19:33:37
Fixed.
|
| + |
| + // 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()); |