1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "extensions/shell/browser/shell_audio_controller_chromeos.h" 6 7 #include "base/macros.h" 8 #include "chromeos/audio/audio_device.h" 9 #include "chromeos/audio/cras_audio_handler.h" 10 #include "chromeos/dbus/audio_node.h" 11 #include "chromeos/dbus/cras_audio_client_stub_impl.h" 12 #include "chromeos/dbus/dbus_thread_manager.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 using chromeos::AudioDevice; 16 using chromeos::AudioNode; 17 using chromeos::AudioNodeList; 18 19 namespace extensions { 20 21 class ShellAudioControllerTest : public testing::Test { 22 public: 23 ShellAudioControllerTest() : next_node_id_(1) { 24 // This also initializes DBusThreadManager. 25 scoped_ptr<chromeos::DBusThreadManagerSetter> dbus_setter = 26 chromeos::DBusThreadManager::GetSetterForTesting(); 27 28 audio_client_ = new chromeos::CrasAudioClientStubImpl(); 29 audio_client_->SetAudioNodesForTesting(AudioNodeList()); 30 dbus_setter->SetCrasAudioClient( 31 make_scoped_ptr(audio_client_).PassAs<chromeos::CrasAudioClient>()); 32 33 chromeos::CrasAudioHandler::Initialize( 34 new ShellAudioController::PrefHandler()); 35 audio_handler_ = chromeos::CrasAudioHandler::Get(); 36 37 controller_.reset(new ShellAudioController()); 38 } 39 40 virtual ~ShellAudioControllerTest() { 41 controller_.reset(); 42 chromeos::CrasAudioHandler::Shutdown(); 43 chromeos::DBusThreadManager::Shutdown(); 44 } 45 46 protected: 47 // Fills a AudioNode for use by tests. 48 AudioNode CreateNode(chromeos::AudioDeviceType type) { 49 AudioNode node; 50 node.is_input = 51 type == chromeos::AUDIO_TYPE_MIC || 52 type == chromeos::AUDIO_TYPE_INTERNAL_MIC || 53 type == chromeos::AUDIO_TYPE_KEYBOARD_MIC; 54 node.id = next_node_id_++; 55 node.type = AudioDevice::GetTypeString(type); 56 return node; 57 } 58 59 // Changes the active state of the node with |id| in |nodes|. 60 void SetNodeActive(AudioNodeList* nodes, uint64 id, bool active) { 61 for (AudioNodeList::iterator it = nodes->begin(); 62 it != nodes->end(); ++it) { 63 if (it->id == id) { 64 it->active = active; 65 return; 66 } 67 } 68 ASSERT_TRUE(false) << "Didn't find ID " << id; 69 } 70 71 chromeos::CrasAudioClientStubImpl* audio_client_; // Not owned. 72 chromeos::CrasAudioHandler* audio_handler_; // Not owned. 73 scoped_ptr<ShellAudioController> controller_; 74 75 // Next audio node ID to be returned by CreateNode(). 76 uint64 next_node_id_; 77 78 private: 79 DISALLOW_COPY_AND_ASSIGN(ShellAudioControllerTest); 80 }; 81 82 // Tests that higher-priority devices are activated as soon as they're 83 // connected. 84 TEST_F(ShellAudioControllerTest, SelectBestDevices) { 85 AudioNode internal_speaker = 86 CreateNode(chromeos::AUDIO_TYPE_INTERNAL_SPEAKER); 87 AudioNode internal_mic = CreateNode(chromeos::AUDIO_TYPE_INTERNAL_MIC); 88 AudioNode headphone = CreateNode(chromeos::AUDIO_TYPE_HEADPHONE); 89 AudioNode external_mic = CreateNode(chromeos::AUDIO_TYPE_MIC); 90 91 // AudioDevice gives the headphone jack a higher priority than the internal 92 // speaker and an external mic a higher priority than the internal mic, so we 93 // should start out favoring headphones and the external mic. 94 AudioNodeList all_nodes; 95 all_nodes.push_back(internal_speaker); 96 all_nodes.push_back(internal_mic); 97 all_nodes.push_back(headphone); 98 all_nodes.push_back(external_mic); 99 audio_client_->SetAudioNodesAndNotifyObserversForTesting(all_nodes); 100 EXPECT_EQ(headphone.id, audio_handler_->GetPrimaryActiveOutputNode()); 101 EXPECT_EQ(external_mic.id, audio_handler_->GetPrimaryActiveInputNode()); 102 103 // Unplug the headphones and mic and check that we switch to the internal 104 // devices. 105 AudioNodeList internal_nodes; 106 internal_nodes.push_back(internal_speaker); 107 internal_nodes.push_back(internal_mic); 108 audio_client_->SetAudioNodesAndNotifyObserversForTesting(internal_nodes); 109 EXPECT_EQ(internal_speaker.id, audio_handler_->GetPrimaryActiveOutputNode()); 110 EXPECT_EQ(internal_mic.id, audio_handler_->GetPrimaryActiveInputNode()); 111 112 // Switch back to the external devices. Mark the previously-activated internal 113 // devices as being active so CrasAudioHandler doesn't complain. 114 SetNodeActive(&all_nodes, internal_speaker.id, true); 115 SetNodeActive(&all_nodes, internal_mic.id, true); 116 audio_client_->SetAudioNodesAndNotifyObserversForTesting(all_nodes); 117 EXPECT_EQ(headphone.id, audio_handler_->GetPrimaryActiveOutputNode()); 118 EXPECT_EQ(external_mic.id, audio_handler_->GetPrimaryActiveInputNode()); 119 } 120 121 // Tests that active audio devices are unmuted and set to 100% volume. 122 TEST_F(ShellAudioControllerTest, MaxVolume) { 123 AudioNodeList nodes; 124 nodes.push_back(CreateNode(chromeos::AUDIO_TYPE_INTERNAL_SPEAKER)); 125 nodes.push_back(CreateNode(chromeos::AUDIO_TYPE_INTERNAL_MIC)); 126 audio_client_->SetAudioNodesAndNotifyObserversForTesting(nodes); 127 128 EXPECT_FALSE(audio_handler_->IsOutputMuted()); 129 EXPECT_FALSE(audio_handler_->IsInputMuted()); 130 EXPECT_EQ(100, audio_handler_->GetOutputVolumePercent()); 131 EXPECT_EQ(100, audio_handler_->GetInputGainPercent()); 132 } 133 134 } // namespace extensions 135