// 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 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 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 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 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