blob: 8005ac69f22175600364894e4e8c047976ce9e33 [file] [log] [blame]
// 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