Commit b0a37e67 authored by Ken MacKay's avatar Ken MacKay Committed by Commit Bot

[Chromecast] Fully implement volume control for desktop

Bug: internal b/111451219
Change-Id: I9ffa8324d3392cf7ced97465c4a65fdcd8c0c00c
Reviewed-on: https://chromium-review.googlesource.com/1145793
Commit-Queue: Kenneth MacKay <kmackay@chromium.org>
Reviewed-by: default avatarLuke Halliwell <halliwell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577190}
parent ed9d8eeb
......@@ -4,51 +4,203 @@
#include "chromecast/public/volume_control.h"
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/no_destructor.h"
#include "base/numerics/ranges.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
namespace chromecast {
namespace media {
namespace {
const float kMinVolumeDbfs = -60.0f;
const float kMaxVolumeDbfs = 0.0f;
class VolumeControlInternal {
public:
VolumeControlInternal() : thread_("VolumeControl") {
for (auto type :
{AudioContentType::kMedia, AudioContentType::kAlarm,
AudioContentType::kCommunication, AudioContentType::kOther}) {
volumes_[type] = 1.0f;
muted_[type] = false;
}
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
thread_.StartWithOptions(options);
}
~VolumeControlInternal() = default;
void AddVolumeObserver(VolumeObserver* observer) {
base::AutoLock lock(observer_lock_);
volume_observers_.push_back(observer);
}
void RemoveVolumeObserver(VolumeObserver* observer) {
base::AutoLock lock(observer_lock_);
volume_observers_.erase(std::remove(volume_observers_.begin(),
volume_observers_.end(), observer),
volume_observers_.end());
}
float GetVolume(AudioContentType type) {
base::AutoLock lock(volume_lock_);
return volumes_[type];
}
void SetVolume(AudioContentType type, float level) {
if (type == AudioContentType::kOther) {
NOTREACHED() << "Can't set volume for content type kOther";
return;
}
level = base::ClampToRange(level, 0.0f, 1.0f);
thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&VolumeControlInternal::SetVolumeOnThread,
base::Unretained(this), type, level));
}
bool IsMuted(AudioContentType type) {
base::AutoLock lock(volume_lock_);
return muted_[type];
}
void SetMuted(AudioContentType type, bool muted) {
if (type == AudioContentType::kOther) {
NOTREACHED() << "Can't set mute state for content type kOther";
return;
}
thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&VolumeControlInternal::SetMutedOnThread,
base::Unretained(this), type, muted));
}
private:
void SetVolumeOnThread(AudioContentType type, float level) {
DCHECK(thread_.task_runner()->BelongsToCurrentThread());
DCHECK(type != AudioContentType::kOther);
{
base::AutoLock lock(volume_lock_);
if (level == volumes_[type]) {
return;
}
volumes_[type] = level;
}
{
base::AutoLock lock(observer_lock_);
for (VolumeObserver* observer : volume_observers_) {
observer->OnVolumeChange(type, level);
}
}
}
void SetMutedOnThread(AudioContentType type, bool muted) {
DCHECK(thread_.task_runner()->BelongsToCurrentThread());
DCHECK(type != AudioContentType::kOther);
{
base::AutoLock lock(volume_lock_);
if (muted == muted_[type]) {
return;
}
muted_[type] = muted;
}
{
base::AutoLock lock(observer_lock_);
for (VolumeObserver* observer : volume_observers_) {
observer->OnMuteChange(type, muted);
}
}
}
base::Lock volume_lock_;
std::map<AudioContentType, float> volumes_;
std::map<AudioContentType, bool> muted_;
base::Lock observer_lock_;
std::vector<VolumeObserver*> volume_observers_;
base::Thread thread_;
DISALLOW_COPY_AND_ASSIGN(VolumeControlInternal);
};
VolumeControlInternal& GetVolumeControl() {
static base::NoDestructor<VolumeControlInternal> g_volume_control;
return *g_volume_control;
}
} // namespace
// static
void VolumeControl::Initialize(const std::vector<std::string>& argv) {}
void VolumeControl::Initialize(const std::vector<std::string>& argv) {
GetVolumeControl();
}
// static
void VolumeControl::Finalize() {}
// static
void VolumeControl::AddVolumeObserver(VolumeObserver* observer) {}
void VolumeControl::AddVolumeObserver(VolumeObserver* observer) {
GetVolumeControl().AddVolumeObserver(observer);
}
// static
void VolumeControl::RemoveVolumeObserver(VolumeObserver* observer) {}
void VolumeControl::RemoveVolumeObserver(VolumeObserver* observer) {
GetVolumeControl().RemoveVolumeObserver(observer);
}
// static
float VolumeControl::GetVolume(AudioContentType type) {
return 1.0f;
return GetVolumeControl().GetVolume(type);
}
// static
void VolumeControl::SetVolume(AudioContentType type, float level) {}
void VolumeControl::SetVolume(AudioContentType type, float level) {
GetVolumeControl().SetVolume(type, level);
}
// static
bool VolumeControl::IsMuted(AudioContentType type) {
return false;
return GetVolumeControl().IsMuted(type);
}
// static
void VolumeControl::SetMuted(AudioContentType type, bool muted) {}
void VolumeControl::SetMuted(AudioContentType type, bool muted) {
GetVolumeControl().SetMuted(type, muted);
}
// static
void VolumeControl::SetOutputLimit(AudioContentType type, float limit) {}
// static
float VolumeControl::VolumeToDbFS(float volume) {
return 0.0f;
volume = base::ClampToRange(volume, 0.0f, 1.0f);
return kMinVolumeDbfs + volume * (kMaxVolumeDbfs - kMinVolumeDbfs);
}
// static
float VolumeControl::DbFSToVolume(float db) {
return 0.0f;
db = base::ClampToRange(db, kMinVolumeDbfs, kMaxVolumeDbfs);
return (db - kMinVolumeDbfs) / (kMaxVolumeDbfs - kMinVolumeDbfs);
}
// static
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment