1 // Copyright (c) 2013 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 "chrome/browser/extensions/api/audio/audio_service.h" 6 7 #include "base/callback.h" 8 #include "base/memory/weak_ptr.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "chromeos/audio/audio_device.h" 11 #include "chromeos/audio/cras_audio_handler.h" 12 #include "content/public/browser/browser_thread.h" 13 14 using content::BrowserThread; 15 16 namespace extensions { 17 18 using api::audio::OutputDeviceInfo; 19 using api::audio::InputDeviceInfo; 20 21 class AudioServiceImpl : public AudioService, 22 public chromeos::CrasAudioHandler::AudioObserver { 23 public: 24 AudioServiceImpl(); 25 virtual ~AudioServiceImpl(); 26 27 // Called by listeners to this service to add/remove themselves as observers. 28 virtual void AddObserver(AudioService::Observer* observer) OVERRIDE; 29 virtual void RemoveObserver(AudioService::Observer* observer) OVERRIDE; 30 31 // Start to query audio device information. 32 virtual void StartGetInfo(const GetInfoCallback& callback) OVERRIDE; 33 virtual void SetActiveDevices(const DeviceIdList& device_list) OVERRIDE; 34 virtual bool SetDeviceProperties(const std::string& device_id, 35 bool muted, 36 int volume, 37 int gain) OVERRIDE; 38 39 protected: 40 // chromeos::CrasAudioHandler::AudioObserver overrides. 41 virtual void OnOutputVolumeChanged() OVERRIDE; 42 virtual void OnInputGainChanged() OVERRIDE; 43 virtual void OnOutputMuteChanged() OVERRIDE; 44 virtual void OnInputMuteChanged() OVERRIDE; 45 virtual void OnAudioNodesChanged() OVERRIDE; 46 virtual void OnActiveOutputNodeChanged() OVERRIDE; 47 virtual void OnActiveInputNodeChanged() OVERRIDE; 48 49 private: 50 void NotifyDeviceChanged(); 51 52 bool FindDevice(uint64 id, chromeos::AudioDevice* device); 53 uint64 GetIdFromStr(const std::string& id_str); 54 55 // List of observers. 56 ObserverList<AudioService::Observer> observer_list_; 57 58 chromeos::CrasAudioHandler* cras_audio_handler_; 59 60 // Note: This should remain the last member so it'll be destroyed and 61 // invalidate the weak pointers before any other members are destroyed. 62 base::WeakPtrFactory<AudioServiceImpl> weak_ptr_factory_; 63 64 DISALLOW_COPY_AND_ASSIGN(AudioServiceImpl); 65 }; 66 67 AudioServiceImpl::AudioServiceImpl() 68 : cras_audio_handler_(NULL), 69 weak_ptr_factory_(this) { 70 if (chromeos::CrasAudioHandler::IsInitialized()) { 71 cras_audio_handler_ = chromeos::CrasAudioHandler::Get(); 72 cras_audio_handler_->AddAudioObserver(this); 73 } 74 } 75 76 AudioServiceImpl::~AudioServiceImpl() { 77 if (cras_audio_handler_ && chromeos::CrasAudioHandler::IsInitialized()) { 78 cras_audio_handler_->RemoveAudioObserver(this); 79 } 80 } 81 82 void AudioServiceImpl::AddObserver(AudioService::Observer* observer) { 83 observer_list_.AddObserver(observer); 84 } 85 86 void AudioServiceImpl::RemoveObserver(AudioService::Observer* observer) { 87 observer_list_.RemoveObserver(observer); 88 } 89 90 void AudioServiceImpl::StartGetInfo(const GetInfoCallback& callback) { 91 DCHECK_CURRENTLY_ON(BrowserThread::UI); 92 DCHECK(cras_audio_handler_); 93 DCHECK(!callback.is_null()); 94 95 if (callback.is_null()) 96 return; 97 98 OutputInfo output_info; 99 InputInfo input_info; 100 if (!cras_audio_handler_) { 101 callback.Run(output_info, input_info, false); 102 return; 103 } 104 105 chromeos::AudioDeviceList devices; 106 cras_audio_handler_->GetAudioDevices(&devices); 107 for (size_t i = 0; i < devices.size(); ++i) { 108 if (!devices[i].is_input) { 109 linked_ptr<OutputDeviceInfo> info(new OutputDeviceInfo()); 110 info->id = base::Uint64ToString(devices[i].id); 111 info->name = devices[i].device_name + ": " + devices[i].display_name; 112 info->is_active = devices[i].active; 113 info->volume = 114 cras_audio_handler_->GetOutputVolumePercentForDevice(devices[i].id); 115 info->is_muted = 116 cras_audio_handler_->IsOutputMutedForDevice(devices[i].id); 117 output_info.push_back(info); 118 } else { 119 linked_ptr<InputDeviceInfo> info(new InputDeviceInfo()); 120 info->id = base::Uint64ToString(devices[i].id); 121 info->name = devices[i].device_name + ": " + devices[i].display_name; 122 info->is_active = devices[i].active; 123 info->gain = 124 cras_audio_handler_->GetInputGainPercentForDevice(devices[i].id); 125 info->is_muted = 126 cras_audio_handler_->IsInputMutedForDevice(devices[i].id); 127 input_info.push_back(info); 128 } 129 } 130 callback.Run(output_info, input_info, true); 131 } 132 133 void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) { 134 DCHECK(cras_audio_handler_); 135 if (!cras_audio_handler_) 136 return; 137 138 chromeos::CrasAudioHandler::NodeIdList id_list; 139 for (size_t i = 0; i < device_list.size(); ++i) { 140 chromeos::AudioDevice device; 141 if (FindDevice(GetIdFromStr(device_list[i]), &device)) 142 id_list.push_back(device.id); 143 } 144 cras_audio_handler_->ChangeActiveNodes(id_list); 145 } 146 147 bool AudioServiceImpl::SetDeviceProperties(const std::string& device_id, 148 bool muted, 149 int volume, 150 int gain) { 151 DCHECK(cras_audio_handler_); 152 if (!cras_audio_handler_) 153 return false; 154 155 chromeos::AudioDevice device; 156 bool found = FindDevice(GetIdFromStr(device_id), &device); 157 if (!found) 158 return false; 159 160 cras_audio_handler_->SetMuteForDevice(device.id, muted); 161 162 if (!device.is_input && volume != -1) { 163 cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, volume); 164 return true; 165 } else if (device.is_input && gain != -1) { 166 cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, gain); 167 return true; 168 } 169 170 return false; 171 } 172 173 bool AudioServiceImpl::FindDevice(uint64 id, chromeos::AudioDevice* device) { 174 chromeos::AudioDeviceList devices; 175 cras_audio_handler_->GetAudioDevices(&devices); 176 177 for (size_t i = 0; i < devices.size(); ++i) { 178 if (devices[i].id == id) { 179 *device = devices[i]; 180 return true; 181 } 182 } 183 return false; 184 } 185 186 uint64 AudioServiceImpl::GetIdFromStr(const std::string& id_str) { 187 uint64 device_id; 188 if (!base::StringToUint64(id_str, &device_id)) 189 return 0; 190 else 191 return device_id; 192 } 193 194 void AudioServiceImpl::OnOutputVolumeChanged() { 195 NotifyDeviceChanged(); 196 } 197 198 void AudioServiceImpl::OnOutputMuteChanged() { 199 NotifyDeviceChanged(); 200 } 201 202 void AudioServiceImpl::OnInputGainChanged() { 203 NotifyDeviceChanged(); 204 } 205 206 void AudioServiceImpl::OnInputMuteChanged() { 207 NotifyDeviceChanged(); 208 } 209 210 void AudioServiceImpl::OnAudioNodesChanged() { 211 NotifyDeviceChanged(); 212 } 213 214 void AudioServiceImpl::OnActiveOutputNodeChanged() { 215 NotifyDeviceChanged(); 216 } 217 218 void AudioServiceImpl::OnActiveInputNodeChanged() { 219 NotifyDeviceChanged(); 220 } 221 222 void AudioServiceImpl::NotifyDeviceChanged() { 223 FOR_EACH_OBSERVER(AudioService::Observer, observer_list_, OnDeviceChanged()); 224 } 225 226 AudioService* AudioService::CreateInstance() { 227 return new AudioServiceImpl; 228 } 229 230 } // namespace extensions 231