From 3147abc7657de300afcfa3a65d02413e6bca477a Mon Sep 17 00:00:00 2001 From: jennyz Date: Tue, 28 Apr 2015 17:13:03 -0700 Subject: [PATCH] Fix the issue where the active output device is lost after the device suspend/resume without any active stream. BUG=478968 Review URL: https://codereview.chromium.org/1109793005 Cr-Commit-Position: refs/heads/master@{#327399} --- chromeos/audio/cras_audio_handler.cc | 9 ++- chromeos/audio/cras_audio_handler_unittest.cc | 64 +++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc index 52af951687b3b2..3a86d8676ff483 100644 --- a/chromeos/audio/cras_audio_handler.cc +++ b/chromeos/audio/cras_audio_handler.cc @@ -852,10 +852,13 @@ void CrasAudioHandler::UpdateDevicesAndSwitchActive( } // If the previous active device is removed from the new node list, - // reset active_output_node_id_. - if (!GetDeviceFromId(active_output_node_id_)) + // or changed to inactive by cras, reset active_output_node_id_. + // See crbug.com/478968. + const AudioDevice* active_output = GetDeviceFromId(active_output_node_id_); + if (!active_output || !active_output->active) active_output_node_id_ = 0; - if (!GetDeviceFromId(active_input_node_id_)) + const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_); + if (!active_input || !active_input->active) active_input_node_id_ = 0; // If audio nodes change is caused by unplugging some non-active audio diff --git a/chromeos/audio/cras_audio_handler_unittest.cc b/chromeos/audio/cras_audio_handler_unittest.cc index 72eaaf38411d32..fa5dbc35ba60a5 100644 --- a/chromeos/audio/cras_audio_handler_unittest.cc +++ b/chromeos/audio/cras_audio_handler_unittest.cc @@ -2429,4 +2429,68 @@ TEST_F(CrasAudioHandlerTest, HotPlugHDMINotChangeActiveOutput) { cras_audio_handler_->GetPrimaryActiveOutputNode()); } +// Test the case in which the active device was set to inactive from cras after +// resuming from suspension state. See crbug.com/478968. +TEST_F(CrasAudioHandlerTest, ActiveNodeLostAfterResume) { + AudioNodeList audio_nodes; + EXPECT_FALSE(kHeadphone.active); + audio_nodes.push_back(kHeadphone); + EXPECT_FALSE(kHDMIOutput.active); + audio_nodes.push_back(kHDMIOutput); + SetUpCrasAudioHandler(audio_nodes); + + // Verify the headphone is selected as the active output. + 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()); + const AudioDevice* active_headphone = GetDeviceFromId(kHeadphone.id); + EXPECT_EQ(kHeadphone.id, active_headphone->id); + EXPECT_TRUE(active_headphone->active); + + // Simulate NodesChanged signal with headphone turning into inactive state, + // and HDMI node removed. + audio_nodes.clear(); + audio_nodes.push_back(kHeadphone); + ChangeAudioNodes(audio_nodes); + + // Verify the headphone is set to active again. + EXPECT_EQ(kHeadphone.id, cras_audio_handler_->GetPrimaryActiveOutputNode()); + const AudioDevice* headphone_resumed = GetDeviceFromId(kHeadphone.id); + EXPECT_EQ(kHeadphone.id, headphone_resumed->id); + EXPECT_TRUE(headphone_resumed->active); +} + +// Test the case in which there are two NodesChanged signal for discovering +// output devices, and there is race between NodesChange and SetActiveOutput +// during this process. See crbug.com/478968. +TEST_F(CrasAudioHandlerTest, ActiveNodeLostDuringLoginSession) { + AudioNodeList audio_nodes; + EXPECT_FALSE(kHeadphone.active); + audio_nodes.push_back(kHeadphone); + SetUpCrasAudioHandler(audio_nodes); + + // Verify the headphone is selected as the active output. + 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()); + const AudioDevice* active_headphone = GetDeviceFromId(kHeadphone.id); + EXPECT_EQ(kHeadphone.id, active_headphone->id); + EXPECT_TRUE(active_headphone->active); + + // Simulate NodesChanged signal with headphone turning into inactive state, + // and add a new HDMI output node. + audio_nodes.clear(); + audio_nodes.push_back(kHeadphone); + audio_nodes.push_back(kHDMIOutput); + ChangeAudioNodes(audio_nodes); + + // Verify the headphone is set to active again. + EXPECT_EQ(kHeadphone.id, cras_audio_handler_->GetPrimaryActiveOutputNode()); + const AudioDevice* headphone_resumed = GetDeviceFromId(kHeadphone.id); + EXPECT_EQ(kHeadphone.id, headphone_resumed->id); + EXPECT_TRUE(headphone_resumed->active); +} + } // namespace chromeos