| Index: chrome/browser/chromeos/audio/audio_mixer_cras.cc
|
| diff --git a/chrome/browser/chromeos/audio/audio_mixer_cras.cc b/chrome/browser/chromeos/audio/audio_mixer_cras.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d17972050b57ccbb496535008f513140f99d8487
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/audio/audio_mixer_cras.cc
|
| @@ -0,0 +1,147 @@
|
| +// Copyright (c) 2012 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 "chrome/browser/chromeos/audio/audio_mixer_cras.h"
|
| +
|
| +#include <cmath>
|
| +#include <cras_client.h>
|
| +#include <unistd.h>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/logging.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/threading/thread.h"
|
| +#include "base/threading/thread_restrictions.h"
|
| +#include "chrome/browser/extensions/extension_tts_api_chromeos.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +
|
| +using content::BrowserThread;
|
| +
|
| +namespace chromeos {
|
| +
|
| +namespace {
|
| +
|
| +// Default volume as a percentage in the range [0.0, 100.0].
|
| +const double kDefaultVolumePercent = 75.0;
|
| +
|
| +// Number of seconds that we'll sleep between each connection attempt.
|
| +const int kConnectionRetrySleepSec = 1;
|
| +
|
| +} // namespace
|
| +
|
| +AudioMixerCras::AudioMixerCras()
|
| + : client_(NULL),
|
| + client_connected_(false),
|
| + volume_percent_(kDefaultVolumePercent),
|
| + is_muted_(false),
|
| + apply_is_pending_(true) {
|
| +}
|
| +
|
| +AudioMixerCras::~AudioMixerCras() {
|
| + if (!thread_.get())
|
| + return;
|
| + DCHECK(MessageLoop::current() != thread_->message_loop());
|
| +
|
| + base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
|
| + thread_->Stop();
|
| + thread_.reset();
|
| +
|
| + cras_client_destroy(client_);
|
| +}
|
| +
|
| +void AudioMixerCras::Init() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + DCHECK(!thread_.get()) << "Init() called twice";
|
| +
|
| + thread_.reset(new base::Thread("AudioMixerCras"));
|
| + CHECK(thread_->Start());
|
| + thread_->message_loop()->PostTask(
|
| + FROM_HERE, base::Bind(&AudioMixerCras::Connect, base::Unretained(this)));
|
| +}
|
| +
|
| +double AudioMixerCras::GetVolumePercent() {
|
| + base::AutoLock lock(lock_);
|
| + return volume_percent_;
|
| +}
|
| +
|
| +void AudioMixerCras::SetVolumePercent(double percent) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + if (isnan(percent))
|
| + percent = 0.0;
|
| + percent = std::max(std::min(percent, 100.0), 0.0);
|
| +
|
| + base::AutoLock lock(lock_);
|
| + volume_percent_ = percent;
|
| + if (client_connected_ && !apply_is_pending_)
|
| + thread_->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&AudioMixerCras::ApplyState, base::Unretained(this)));
|
| +}
|
| +
|
| +bool AudioMixerCras::IsMuted() {
|
| + base::AutoLock lock(lock_);
|
| + return is_muted_;
|
| +}
|
| +
|
| +void AudioMixerCras::SetMuted(bool muted) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + base::AutoLock lock(lock_);
|
| + is_muted_ = muted;
|
| + if (client_connected_ && !apply_is_pending_)
|
| + thread_->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&AudioMixerCras::ApplyState, base::Unretained(this)));
|
| +}
|
| +
|
| +void AudioMixerCras::Connect() {
|
| + DCHECK(MessageLoop::current() == thread_->message_loop());
|
| +
|
| + // Create the client structure.
|
| + if (client_ == NULL && cras_client_create(&client_) < 0) {
|
| + LOG(DFATAL) << "cras_client_create() failed";
|
| + return; // TODO(dgreid) change interface so this can return an error.
|
| + }
|
| +
|
| + if (cras_client_connect(client_) != 0) {
|
| + thread_->message_loop()->PostDelayedTask(FROM_HERE,
|
| + base::Bind(&AudioMixerCras::Connect, base::Unretained(this)),
|
| + kConnectionRetrySleepSec * 1000);
|
| + return;
|
| + }
|
| + client_connected_ = true;
|
| +
|
| + // The speech synthesis service shouldn't be initialized until after
|
| + // we get to this point, so we call this function to tell it that it's
|
| + // safe to do TTS now. NotificationService would be cleaner,
|
| + // but it's not available at this point.
|
| + EnableChromeOsTts();
|
| +
|
| + ApplyState();
|
| +}
|
| +
|
| +void AudioMixerCras::ApplyState() {
|
| + DCHECK(MessageLoop::current() == thread_->message_loop());
|
| + if (!client_connected_)
|
| + return;
|
| +
|
| + bool should_mute = false;
|
| + size_t new_volume = 0;
|
| + {
|
| + base::AutoLock lock(lock_);
|
| + should_mute = is_muted_;
|
| + new_volume = floor(volume_percent_ + 0.5);
|
| + apply_is_pending_ = false;
|
| + }
|
| +
|
| + // If muting mute before setting volume, if un-muting set volume first.
|
| + if (should_mute) {
|
| + cras_client_set_system_mute(client_, should_mute);
|
| + cras_client_set_system_volume(client_, new_volume);
|
| + } else {
|
| + cras_client_set_system_volume(client_, new_volume);
|
| + cras_client_set_system_mute(client_, should_mute);
|
| + }
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|