| Index: content/browser/renderer_host/media/audio_output_delegate.cc
|
| diff --git a/content/browser/renderer_host/media/audio_output_delegate.cc b/content/browser/renderer_host/media/audio_output_delegate.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..32d936eb3f69ad35c575347c5cc2584cddbdb736
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/media/audio_output_delegate.cc
|
| @@ -0,0 +1,190 @@
|
| +// Copyright 2016 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 "content/browser/renderer_host/media/audio_output_delegate.h"
|
| +
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "content/browser/media/audio_stream_monitor.h"
|
| +#include "content/browser/media/capture/audio_mirroring_manager.h"
|
| +#include "content/browser/media/media_internals.h"
|
| +#include "content/browser/renderer_host/media/audio_sync_reader.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/media_observer.h"
|
| +
|
| +namespace content {
|
| +
|
| +AudioOutputDelegate::AudioOutputDelegate(
|
| + EventHandler* handler,
|
| + media::AudioManager* audio_manager,
|
| + std::unique_ptr<media::AudioLog> audio_log,
|
| + int stream_id,
|
| + int render_frame_id,
|
| + int render_process_id,
|
| + const media::AudioParameters& params,
|
| + const std::string& output_device_id)
|
| + : handler_(handler),
|
| + audio_log_(std::move(audio_log)),
|
| + reader_(AudioSyncReader::Create(params)),
|
| + stream_id_(stream_id),
|
| + render_frame_id_(render_frame_id),
|
| + render_process_id_(render_process_id),
|
| + weak_factory_(this) {
|
| + DCHECK(handler_);
|
| + DCHECK(audio_manager);
|
| + DCHECK(audio_log_);
|
| + weak_this_ = weak_factory_.GetWeakPtr();
|
| + audio_log_->OnCreated(stream_id, params, output_device_id);
|
| + controller_ = media::AudioOutputController::Create(
|
| + audio_manager, this, params, output_device_id, reader_.get());
|
| + DCHECK(controller_);
|
| +}
|
| +
|
| +AudioOutputDelegate::~AudioOutputDelegate() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(!playing_);
|
| + DCHECK(!handler_);
|
| +}
|
| +
|
| +void AudioOutputDelegate::Deleter::operator()(AudioOutputDelegate* delegate) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + delegate->UpdatePlayingState(false);
|
| + delegate->handler_ = nullptr;
|
| + delegate->audio_log_->OnClosed(delegate->stream_id_);
|
| +
|
| + // |controller| will call the closure (on IO thread) when it's done closing,
|
| + // and it is only after that call that we can delete |delegate|. By giving the
|
| + // closure ownership of |delegate|, we keep delegate alive until |controller|
|
| + // is closed.
|
| + //
|
| + // The mirroring manager is a leaky singleton, so Unretained is fine.
|
| + delegate->controller_->Close(base::Bind(
|
| + [](AudioOutputDelegate* delegate,
|
| + AudioMirroringManager* mirroring_manager) {
|
| + // De-register the controller from the AudioMirroringManager now that
|
| + // the controller has closed the AudioOutputStream and shut itself down.
|
| + // This ensures that calling RemoveDiverter() here won't trigger the
|
| + // controller to re-start the default AudioOutputStream and cause a
|
| + // brief audio blip to come out the user's speakers.
|
| + // http://crbug.com/474432
|
| + //
|
| + // It's fine if the task is canceled during shutdown, since the
|
| + // mirroring manager doesn't require that all diverters are
|
| + // removed.
|
| + if (mirroring_manager)
|
| + mirroring_manager->RemoveDiverter(delegate->controller_.get());
|
| + },
|
| + base::Owned(delegate), base::Unretained(mirroring_manager_)));
|
| +}
|
| +
|
| +// static
|
| +AudioOutputDelegate::UniquePtr AudioOutputDelegate::Create(
|
| + EventHandler* handler,
|
| + media::AudioManager* audio_manager,
|
| + std::unique_ptr<media::AudioLog> audio_log,
|
| + AudioMirroringManager* mirroring_manager,
|
| + MediaObserver* media_observer,
|
| + int stream_id,
|
| + int render_frame_id,
|
| + int render_process_id,
|
| + const media::AudioParameters& params,
|
| + const std::string& output_device_id) {
|
| + if (media_observer)
|
| + media_observer->OnCreatingAudioStream(render_process_id, render_frame_id);
|
| + UniquePtr delegate(
|
| + new AudioOutputDelegate(handler, audio_manager, std::move(audio_log),
|
| + stream_id, render_frame_id, render_process_id,
|
| + params, output_device_id),
|
| + Deleter(mirroring_manager));
|
| + if (mirroring_manager)
|
| + mirroring_manager->AddDiverter(render_process_id, render_frame_id,
|
| + delegate->controller_.get());
|
| + return delegate;
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnPlayStream() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + controller_->Play();
|
| + audio_log_->OnStarted(stream_id_);
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnPauseStream() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + controller_->Pause();
|
| + audio_log_->OnStopped(stream_id_);
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnSetVolume(double volume) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK_GE(volume, 0);
|
| + DCHECK_LE(volume, 1);
|
| + controller_->SetVolume(volume);
|
| + audio_log_->OnSetVolume(stream_id_, volume);
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnControllerCreated() {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioOutputDelegate::SendCreatedNotification, weak_this_));
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnControllerPlaying() {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioOutputDelegate::UpdatePlayingState, weak_this_, true));
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnControllerPaused() {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioOutputDelegate::UpdatePlayingState, weak_this_, false));
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnControllerError() {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioOutputDelegate::OnError, weak_this_));
|
| +}
|
| +
|
| +void AudioOutputDelegate::SendCreatedNotification() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + if (handler_) {
|
| + handler_->OnStreamCreated(stream_id_, reader_->shared_memory(),
|
| + reader_->foreign_socket());
|
| + }
|
| +}
|
| +
|
| +void AudioOutputDelegate::UpdatePlayingState(bool playing) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + if (!handler_ || playing == playing_)
|
| + return;
|
| +
|
| + playing_ = playing;
|
| + handler_->OnStreamStateChanged(playing);
|
| + if (playing) {
|
| + // Note that this takes a reference to |controller_|, and
|
| + // (Start|Stop)MonitoringStream calls are async, so we don't have a
|
| + // guarantee for when the controller is destroyed.
|
| + AudioStreamMonitor::StartMonitoringStream(
|
| + render_process_id_, render_frame_id_, stream_id_,
|
| + base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
|
| + controller_));
|
| + } else {
|
| + AudioStreamMonitor::StopMonitoringStream(render_process_id_,
|
| + render_frame_id_, stream_id_);
|
| + }
|
| +}
|
| +
|
| +void AudioOutputDelegate::OnError() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!handler_)
|
| + return;
|
| +
|
| + audio_log_->OnError(stream_id_);
|
| + handler_->OnStreamError(stream_id_);
|
| +}
|
| +
|
| +} // namespace content
|
|
|