| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/api/audio/audio_service.h" |
| |
| #include "base/callback.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "chromeos/audio/audio_device.h" |
| #include "chromeos/audio/cras_audio_handler.h" |
| #include "content/public/browser/browser_thread.h" |
| |
| using content::BrowserThread; |
| |
| namespace extensions { |
| |
| using core_api::audio::OutputDeviceInfo; |
| using core_api::audio::InputDeviceInfo; |
| |
| class AudioServiceImpl : public AudioService, |
| public chromeos::CrasAudioHandler::AudioObserver { |
| public: |
| AudioServiceImpl(); |
| ~AudioServiceImpl() override; |
| |
| // Called by listeners to this service to add/remove themselves as observers. |
| void AddObserver(AudioService::Observer* observer) override; |
| void RemoveObserver(AudioService::Observer* observer) override; |
| |
| // Start to query audio device information. |
| void StartGetInfo(const GetInfoCallback& callback) override; |
| void SetActiveDevices(const DeviceIdList& device_list) override; |
| bool SetDeviceProperties(const std::string& device_id, |
| bool muted, |
| int volume, |
| int gain) override; |
| |
| protected: |
| // chromeos::CrasAudioHandler::AudioObserver overrides. |
| void OnOutputVolumeChanged() override; |
| void OnInputGainChanged() override; |
| void OnOutputMuteChanged() override; |
| void OnInputMuteChanged() override; |
| void OnAudioNodesChanged() override; |
| void OnActiveOutputNodeChanged() override; |
| void OnActiveInputNodeChanged() override; |
| |
| private: |
| void NotifyDeviceChanged(); |
| |
| bool FindDevice(uint64 id, chromeos::AudioDevice* device); |
| uint64 GetIdFromStr(const std::string& id_str); |
| |
| // List of observers. |
| ObserverList<AudioService::Observer> observer_list_; |
| |
| chromeos::CrasAudioHandler* cras_audio_handler_; |
| |
| // Note: This should remain the last member so it'll be destroyed and |
| // invalidate the weak pointers before any other members are destroyed. |
| base::WeakPtrFactory<AudioServiceImpl> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AudioServiceImpl); |
| }; |
| |
| AudioServiceImpl::AudioServiceImpl() |
| : cras_audio_handler_(NULL), |
| weak_ptr_factory_(this) { |
| if (chromeos::CrasAudioHandler::IsInitialized()) { |
| cras_audio_handler_ = chromeos::CrasAudioHandler::Get(); |
| cras_audio_handler_->AddAudioObserver(this); |
| } |
| } |
| |
| AudioServiceImpl::~AudioServiceImpl() { |
| if (cras_audio_handler_ && chromeos::CrasAudioHandler::IsInitialized()) { |
| cras_audio_handler_->RemoveAudioObserver(this); |
| } |
| } |
| |
| void AudioServiceImpl::AddObserver(AudioService::Observer* observer) { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void AudioServiceImpl::RemoveObserver(AudioService::Observer* observer) { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| void AudioServiceImpl::StartGetInfo(const GetInfoCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK(cras_audio_handler_); |
| DCHECK(!callback.is_null()); |
| |
| if (callback.is_null()) |
| return; |
| |
| OutputInfo output_info; |
| InputInfo input_info; |
| if (!cras_audio_handler_) { |
| callback.Run(output_info, input_info, false); |
| return; |
| } |
| |
| chromeos::AudioDeviceList devices; |
| cras_audio_handler_->GetAudioDevices(&devices); |
| for (size_t i = 0; i < devices.size(); ++i) { |
| if (!devices[i].is_input) { |
| linked_ptr<OutputDeviceInfo> info(new OutputDeviceInfo()); |
| info->id = base::Uint64ToString(devices[i].id); |
| info->name = devices[i].device_name + ": " + devices[i].display_name; |
| info->is_active = devices[i].active; |
| info->volume = |
| cras_audio_handler_->GetOutputVolumePercentForDevice(devices[i].id); |
| info->is_muted = |
| cras_audio_handler_->IsOutputMutedForDevice(devices[i].id); |
| output_info.push_back(info); |
| } else { |
| linked_ptr<InputDeviceInfo> info(new InputDeviceInfo()); |
| info->id = base::Uint64ToString(devices[i].id); |
| info->name = devices[i].device_name + ": " + devices[i].display_name; |
| info->is_active = devices[i].active; |
| info->gain = |
| cras_audio_handler_->GetInputGainPercentForDevice(devices[i].id); |
| info->is_muted = |
| cras_audio_handler_->IsInputMutedForDevice(devices[i].id); |
| input_info.push_back(info); |
| } |
| } |
| callback.Run(output_info, input_info, true); |
| } |
| |
| void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) { |
| DCHECK(cras_audio_handler_); |
| if (!cras_audio_handler_) |
| return; |
| |
| chromeos::CrasAudioHandler::NodeIdList id_list; |
| for (size_t i = 0; i < device_list.size(); ++i) { |
| chromeos::AudioDevice device; |
| if (FindDevice(GetIdFromStr(device_list[i]), &device)) |
| id_list.push_back(device.id); |
| } |
| cras_audio_handler_->ChangeActiveNodes(id_list); |
| } |
| |
| bool AudioServiceImpl::SetDeviceProperties(const std::string& device_id, |
| bool muted, |
| int volume, |
| int gain) { |
| DCHECK(cras_audio_handler_); |
| if (!cras_audio_handler_) |
| return false; |
| |
| chromeos::AudioDevice device; |
| bool found = FindDevice(GetIdFromStr(device_id), &device); |
| if (!found) |
| return false; |
| |
| cras_audio_handler_->SetMuteForDevice(device.id, muted); |
| |
| if (!device.is_input && volume != -1) { |
| cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, volume); |
| return true; |
| } else if (device.is_input && gain != -1) { |
| cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, gain); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool AudioServiceImpl::FindDevice(uint64 id, chromeos::AudioDevice* device) { |
| chromeos::AudioDeviceList devices; |
| cras_audio_handler_->GetAudioDevices(&devices); |
| |
| for (size_t i = 0; i < devices.size(); ++i) { |
| if (devices[i].id == id) { |
| *device = devices[i]; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| uint64 AudioServiceImpl::GetIdFromStr(const std::string& id_str) { |
| uint64 device_id; |
| if (!base::StringToUint64(id_str, &device_id)) |
| return 0; |
| else |
| return device_id; |
| } |
| |
| void AudioServiceImpl::OnOutputVolumeChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::OnOutputMuteChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::OnInputGainChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::OnInputMuteChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::OnAudioNodesChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::OnActiveOutputNodeChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::OnActiveInputNodeChanged() { |
| NotifyDeviceChanged(); |
| } |
| |
| void AudioServiceImpl::NotifyDeviceChanged() { |
| FOR_EACH_OBSERVER(AudioService::Observer, observer_list_, OnDeviceChanged()); |
| } |
| |
| AudioService* AudioService::CreateInstance() { |
| return new AudioServiceImpl; |
| } |
| |
| } // namespace extensions |