| Index: content/browser/renderer_host/media/audio_renderer_host.cc
|
| diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
|
| index eadd484b31116d0507282c74ef860ffbc59fad1a..fd604950241b0d1aa78f5e7961df33314cab72ab 100644
|
| --- a/content/browser/renderer_host/media/audio_renderer_host.cc
|
| +++ b/content/browser/renderer_host/media/audio_renderer_host.cc
|
| @@ -11,7 +11,6 @@
|
| #include "base/bind_helpers.h"
|
| #include "base/lazy_instance.h"
|
| #include "base/logging.h"
|
| -#include "base/memory/shared_memory.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/process/process.h"
|
| #include "content/browser/bad_message.h"
|
| @@ -31,11 +30,17 @@
|
| #include "content/public/browser/media_observer.h"
|
| #include "content/public/browser/render_frame_host.h"
|
| #include "content/public/common/content_switches.h"
|
| +#include "content/renderer/media/audio_output_client.h"
|
| #include "media/audio/audio_device_name.h"
|
| #include "media/audio/audio_manager_base.h"
|
| #include "media/audio/audio_streams_tracker.h"
|
| #include "media/base/audio_bus.h"
|
| #include "media/base/limits.h"
|
| +#include "mojo/edk/embedder/embedder.h"
|
| +#include "mojo/public/cpp/system/handle.h"
|
| +#include "base/time/time.h"
|
| +
|
| +#include "content/browser/media/audio_output_impl.h"
|
|
|
| using media::AudioBus;
|
| using media::AudioManager;
|
| @@ -122,63 +127,7 @@ void MaybeFixAudioParameters(media::AudioParameters* params) {
|
|
|
| } // namespace
|
|
|
| -class AudioRendererHost::AudioEntry
|
| - : public media::AudioOutputController::EventHandler {
|
| - public:
|
| - AudioEntry(AudioRendererHost* host,
|
| - int stream_id,
|
| - int render_frame_id,
|
| - const media::AudioParameters& params,
|
| - const std::string& output_device_id,
|
| - scoped_ptr<base::SharedMemory> shared_memory,
|
| - scoped_ptr<media::AudioOutputController::SyncReader> reader);
|
| - ~AudioEntry() override;
|
| -
|
| - int stream_id() const {
|
| - return stream_id_;
|
| - }
|
| -
|
| - int render_frame_id() const { return render_frame_id_; }
|
| -
|
| - media::AudioOutputController* controller() const { return controller_.get(); }
|
| -
|
| - base::SharedMemory* shared_memory() {
|
| - return shared_memory_.get();
|
| - }
|
| -
|
| - media::AudioOutputController::SyncReader* reader() const {
|
| - return reader_.get();
|
| - }
|
| -
|
| - bool playing() const { return playing_; }
|
| - void set_playing(bool playing) { playing_ = playing; }
|
| -
|
| - private:
|
| - // media::AudioOutputController::EventHandler implementation.
|
| - void OnCreated() override;
|
| - void OnPlaying() override;
|
| - void OnPaused() override;
|
| - void OnError() override;
|
| -
|
| - AudioRendererHost* const host_;
|
| - const int stream_id_;
|
| -
|
| - // The routing ID of the source RenderFrame.
|
| - const int render_frame_id_;
|
| -
|
| - // Shared memory for transmission of the audio data. Used by |reader_|.
|
| - const scoped_ptr<base::SharedMemory> shared_memory_;
|
| -
|
| - // The synchronous reader to be used by |controller_|.
|
| - const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
|
| -
|
| - // The AudioOutputController that manages the audio stream.
|
| - const scoped_refptr<media::AudioOutputController> controller_;
|
| -
|
| - bool playing_;
|
| -};
|
| -
|
| -AudioRendererHost::AudioEntry::AudioEntry(
|
| +AudioEntry::AudioEntry(
|
| AudioRendererHost* host,
|
| int stream_id,
|
| int render_frame_id,
|
| @@ -200,7 +149,33 @@ AudioRendererHost::AudioEntry::AudioEntry(
|
| DCHECK(controller_.get());
|
| }
|
|
|
| -AudioRendererHost::AudioEntry::~AudioEntry() {}
|
| +AudioEntry::AudioEntry(
|
| + AudioRendererHost* host,
|
| + int stream_id,
|
| + int render_frame_id,
|
| + const media::AudioParameters& params,
|
| + const std::string& output_device_id,
|
| + scoped_ptr<base::SharedMemory> shared_memory,
|
| + scoped_ptr<media::AudioOutputController::SyncReader> reader,
|
| + mojom::AudioOutputStreamPtr stream,
|
| + const mojom::AudioOutput::CreateStreamCallback& callback)
|
| + : host_(host),
|
| + stream_id_(stream_id),
|
| + render_frame_id_(render_frame_id),
|
| + shared_memory_(std::move(shared_memory)),
|
| + reader_(std::move(reader)),
|
| + controller_(media::AudioOutputController::Create(host->audio_manager_,
|
| + this,
|
| + params,
|
| + output_device_id,
|
| + reader_.get(),
|
| + std::move(stream),
|
| + callback)),
|
| + playing_(false) {
|
| + DCHECK(controller_.get());
|
| +}
|
| +
|
| +AudioEntry::~AudioEntry() {}
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // AudioRendererHost implementations.
|
| @@ -267,14 +242,22 @@ void AudioRendererHost::OnDestruct() const {
|
| BrowserThread::DeleteOnIOThread::Destruct(this);
|
| }
|
|
|
| -void AudioRendererHost::AudioEntry::OnCreated() {
|
| +void AudioEntry::OnCreated() {
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| FROM_HERE,
|
| base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
|
| }
|
|
|
| -void AudioRendererHost::AudioEntry::OnPlaying() {
|
| +void AudioEntry::OnCreated(
|
| + mojom::AudioOutputStreamPtr stream,
|
| + const mojom::AudioOutput::CreateStreamCallback& callback) {
|
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioRendererHost::DoCompleteCreationMojo,
|
| + host_, stream_id_, callback));
|
| +}
|
| +
|
| +void AudioEntry::OnPlaying() {
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| FROM_HERE,
|
| @@ -284,7 +267,7 @@ void AudioRendererHost::AudioEntry::OnPlaying() {
|
| true));
|
| }
|
|
|
| -void AudioRendererHost::AudioEntry::OnPaused() {
|
| +void AudioEntry::OnPaused() {
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| FROM_HERE,
|
| @@ -294,7 +277,7 @@ void AudioRendererHost::AudioEntry::OnPaused() {
|
| false));
|
| }
|
|
|
| -void AudioRendererHost::AudioEntry::OnError() {
|
| +void AudioEntry::OnError() {
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| FROM_HERE,
|
| @@ -306,13 +289,13 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) {
|
|
|
| if (!PeerHandle()) {
|
| DLOG(WARNING) << "Renderer process handle is invalid.";
|
| - ReportErrorAndClose(stream_id);
|
| + // ReportErrorAndClose(stream_id);
|
| return;
|
| }
|
|
|
| AudioEntry* const entry = LookupById(stream_id);
|
| if (!entry) {
|
| - ReportErrorAndClose(stream_id);
|
| + // ReportErrorAndClose(stream_id);
|
| return;
|
| }
|
|
|
| @@ -323,7 +306,7 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) {
|
| &foreign_memory_handle)) {
|
| // If we failed to map and share the shared memory then close the audio
|
| // stream and send an error message.
|
| - ReportErrorAndClose(entry->stream_id());
|
| + // ReportErrorAndClose(entry->stream_id());
|
| return;
|
| }
|
|
|
| @@ -334,7 +317,7 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) {
|
| // If we failed to prepare the sync socket for the renderer then we fail
|
| // the construction of audio stream.
|
| if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
|
| - ReportErrorAndClose(entry->stream_id());
|
| + // ReportErrorAndClose(entry->stream_id());
|
| return;
|
| }
|
|
|
| @@ -343,6 +326,99 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) {
|
| entry->shared_memory()->requested_size()));
|
| }
|
|
|
| +void AudioRendererHost::DoCompleteCreationMojo(
|
| + int stream_id,
|
| + const mojom::AudioOutput::CreateStreamCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!PeerHandle()) {
|
| + DLOG(WARNING) << "Renderer process handle is invalid.";
|
| + ReportErrorAndCloseMojo(stream_id, callback);
|
| + return;
|
| + }
|
| +
|
| + AudioEntry* const entry = LookupById(stream_id);
|
| + if (!entry) {
|
| + ReportErrorAndCloseMojo(stream_id, callback);
|
| + return;
|
| + }
|
| +
|
| + scoped_ptr<mojom::AudioOutputStreamPtr> stream_ptr(
|
| + AudioOutputImpl::CreateStream(entry, stream_id));
|
| +
|
| + base::SharedMemoryHandle shared_memory_handle =
|
| + base::SharedMemory::DuplicateHandle(entry->shared_memory()->handle());
|
| +
|
| + MojoHandle mojo_foreign_memory_handle;
|
| +
|
| + MojoResult shared_buffer_result = mojo::edk::CreateSharedBufferWrapper(
|
| + shared_memory_handle, entry->shared_memory()->requested_size(), false,
|
| + &mojo_foreign_memory_handle);
|
| +
|
| + if (shared_buffer_result != MOJO_RESULT_OK) {
|
| + LOG(WARNING) << "Failed to wrap transit descriptor. Closing: "
|
| + << shared_buffer_result;
|
| + ReportErrorAndCloseMojo(entry->stream_id(), callback);
|
| + return;
|
| + }
|
| +
|
| + AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
|
| +
|
| + base::SyncSocket::TransitDescriptor socket_descriptor;
|
| +
|
| + // If we failed to prepare the sync socket for the renderer then we fail
|
| + // the construction of audio stream.
|
| + if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
|
| + ReportErrorAndCloseMojo(entry->stream_id(), callback);
|
| + return;
|
| + }
|
| + mojo::ScopedSharedBufferHandle shared_buffer_handle =
|
| + mojo::ScopedSharedBufferHandle(
|
| + mojo::SharedBufferHandle(mojo_foreign_memory_handle));
|
| +
|
| + MojoHandle socket_descriptor_handle;
|
| + MojoResult platform_handle_result;
|
| +
|
| +#if defined(OS_WIN)
|
| + platform_handle_result = mojo::edk::CreatePlatformHandleWrapper(
|
| + mojo::edk::ScopedPlatformHandle(
|
| + mojo::edk::PlatformHandle(socket_descriptor)),
|
| + &socket_descriptor_handle);
|
| +#else
|
| + platform_handle_result = mojo::edk::CreatePlatformHandleWrapper(
|
| + mojo::edk::ScopedPlatformHandle(
|
| + mojo::edk::PlatformHandle(socket_descriptor.fd)),
|
| + &socket_descriptor_handle);
|
| + LOG(WARNING) << "socket_descriptor.fd" << socket_descriptor.fd;
|
| + LOG(WARNING) << "socket_descriptor_handle" << socket_descriptor_handle;
|
| +#endif
|
| +
|
| + if (platform_handle_result != MOJO_RESULT_OK) {
|
| + LOG(WARNING) << "Failed to wrap platform handle. Closing: "
|
| + << platform_handle_result;
|
| + ReportErrorAndCloseMojo(stream_id, callback);
|
| + return;
|
| + }
|
| +
|
| + stream_ptr->get()->set(20);
|
| + mojo::ScopedHandle socket_handle =
|
| + mojo::ScopedHandle(mojo::Handle(socket_descriptor_handle));
|
| +
|
| + LOG(ERROR) << "stream_id" << stream_id;
|
| + // LOG(ERROR) << "foreign_memory_handle.fd" << foreign_memory_handle.fd;
|
| + // LOG(ERROR) << "foreign_memory_handle.auto_close" <<
|
| + // foreign_memory_handle.auto_close;
|
| + LOG(ERROR) << "socket_descriptor.fd" << socket_descriptor.fd;
|
| + LOG(ERROR) << "socket_descriptor.auto_close" << socket_descriptor.auto_close;
|
| + LOG(ERROR) << "entry->shared_memory()->requested_size()"
|
| + << entry->shared_memory()->requested_size();
|
| + LOG(ERROR) << "AudioRendererHost::DoCompleteCreationMojo"
|
| + << base::TimeTicks::Now();
|
| +
|
| + callback.Run(std::move(*stream_ptr), stream_id,
|
| + std::move(shared_buffer_handle), std::move(socket_handle));
|
| +}
|
| +
|
| void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
|
| bool is_playing) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| @@ -549,6 +625,32 @@ void AudioRendererHost::OnCreateStream(int stream_id,
|
| authorizations_.erase(auth_data);
|
| }
|
|
|
| +void AudioRendererHost::OnCreateStreamMojo(
|
| + int stream_id,
|
| + int render_frame_id,
|
| + const media::AudioParameters& params,
|
| + mojom::AudioOutputStreamPtr stream,
|
| + const mojom::AudioOutput::CreateStreamCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream"
|
| + << "(stream_id=" << stream_id << ")";
|
| + LOG(ERROR) << "stream_id" << stream_id;
|
| +
|
| + const auto& auth_data = authorizations_.find(stream_id);
|
| +
|
| + // If no previous authorization requested, assume default device
|
| + if (auth_data == authorizations_.end()) {
|
| + DoCreateStream(stream_id, render_frame_id, params, std::string(),
|
| + std::move(stream), callback);
|
| + return;
|
| + }
|
| +
|
| + CHECK(auth_data->second.first);
|
| + DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second,
|
| + std::move(stream), callback);
|
| + authorizations_.erase(auth_data);
|
| +}
|
| +
|
| void AudioRendererHost::DoCreateStream(int stream_id,
|
| int render_frame_id,
|
| const media::AudioParameters& params,
|
| @@ -600,6 +702,73 @@ void AudioRendererHost::DoCreateStream(int stream_id,
|
| max_simultaneous_streams_ = audio_entries_.size();
|
| }
|
|
|
| +void AudioRendererHost::DoCreateStream(
|
| + int stream_id,
|
| + int render_frame_id,
|
| + const media::AudioParameters& params,
|
| + const std::string& device_unique_id,
|
| + mojom::AudioOutputStreamPtr stream,
|
| + const mojom::AudioOutput::CreateStreamCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // media::AudioParameters is validated in the deserializer.
|
| + if (LookupById(stream_id) != NULL) {
|
| + SendErrorMessage(stream_id);
|
| + return;
|
| + }
|
| +
|
| + // Create the shared memory and share with the renderer process.
|
| + uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) +
|
| + AudioBus::CalculateMemorySize(params);
|
| + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
|
| + if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
|
| + SendErrorMessage(stream_id);
|
| + return;
|
| + }
|
| +
|
| + scoped_ptr<AudioSyncReader> reader(
|
| + new AudioSyncReader(shared_memory.get(), params));
|
| + if (!reader->Init()) {
|
| + SendErrorMessage(stream_id);
|
| + return;
|
| + }
|
| +
|
| + MediaObserver* const media_observer =
|
| + GetContentClient()->browser()->GetMediaObserver();
|
| + if (media_observer)
|
| + media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
|
| +
|
| + scoped_ptr<AudioEntry> entry(
|
| + new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id,
|
| + std::move(shared_memory), std::move(reader),
|
| + std::move(stream), callback));
|
| + if (mirroring_manager_) {
|
| + mirroring_manager_->AddDiverter(
|
| + render_process_id_, entry->render_frame_id(), entry->controller());
|
| + }
|
| + audio_entries_.insert(std::make_pair(stream_id, entry.release()));
|
| + g_audio_streams_tracker.Get().IncreaseStreamCount();
|
| +
|
| + audio_log_->OnCreated(stream_id, params, device_unique_id);
|
| + MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
|
| + stream_id, render_process_id_, render_frame_id, audio_log_.get());
|
| +
|
| + if (audio_entries_.size() > max_simultaneous_streams_)
|
| + max_simultaneous_streams_ = audio_entries_.size();
|
| +}
|
| +
|
| +void AudioRendererHost::OnPlayEntry(AudioEntry* entry) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!entry) {
|
| + SendErrorMessage(0);
|
| + return;
|
| + }
|
| +
|
| + entry->controller()->Play();
|
| + audio_log_->OnStarted(0);
|
| +}
|
| +
|
| void AudioRendererHost::OnPlayStream(int stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| @@ -648,6 +817,7 @@ void AudioRendererHost::SendErrorMessage(int stream_id) {
|
| }
|
|
|
| void AudioRendererHost::OnCloseStream(int stream_id) {
|
| + DLOG(WARNING) << "OnCloseStream " << stream_id;
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| authorizations_.erase(stream_id);
|
|
|
| @@ -697,7 +867,29 @@ void AudioRendererHost::ReportErrorAndClose(int stream_id) {
|
| OnCloseStream(stream_id);
|
| }
|
|
|
| -AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
|
| +void AudioRendererHost::ReportErrorAndCloseMojo(
|
| + int stream_id,
|
| + const mojom::AudioOutput::CreateStreamCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // Make sure this isn't a stray callback executing after the stream has been
|
| + // closed, so error notifications aren't sent after clients believe the stream
|
| + // is closed.
|
| + if (!LookupById(stream_id))
|
| + return;
|
| + mojo::ScopedSharedBufferHandle shared_buffer_handle =
|
| + mojo::ScopedSharedBufferHandle(mojo::SharedBufferHandle());
|
| +
|
| + mojo::ScopedHandle socket_handle = mojo::ScopedHandle(mojo::Handle());
|
| +
|
| + callback.Run(mojom::AudioOutputStreamPtr(), stream_id,
|
| + std::move(shared_buffer_handle), std::move(socket_handle));
|
| +
|
| + audio_log_->OnError(stream_id);
|
| + OnCloseStream(stream_id);
|
| +}
|
| +
|
| +AudioEntry* AudioRendererHost::LookupById(int stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
|
|
|