Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1542)

Unified Diff: content/renderer/media/audio_output_ipc_factory.cc

Issue 2289543003: IPC->mojo of audio_renderer_host (Closed)
Patch Set: It builds \o/. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/audio_output_ipc_factory.cc
diff --git a/content/renderer/media/audio_output_ipc_factory.cc b/content/renderer/media/audio_output_ipc_factory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6109466b409e62fb774d40f7185b48e5ec370246
--- /dev/null
+++ b/content/renderer/media/audio_output_ipc_factory.cc
@@ -0,0 +1,284 @@
+// 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/renderer/media/audio_output_ipc_factory.h"
+
+#include <string>
+#include <utility>
+
+#include "base/files/file.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/single_thread_task_runner.h"
+#include "base/sync_socket.h"
+#include "content/renderer/media/webrtc_logging.h"
+#include "media/base/audio_parameters.h"
+#include "media/mojo/interfaces/audio_output.mojom.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/c/system/buffer.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/shell/public/cpp/interface_provider.h"
+
+namespace content {
+
+class AudioOutputIPCFactory::MojoAudioOutputIPC
+ : public media::AudioOutputIPC,
+ private media::mojom::AudioOutputStreamClient {
+ public:
+ MojoAudioOutputIPC(const scoped_refptr<AudioOutputIPCFactory> output_client,
+ const media::mojom::AudioOutputPtr* output_service,
+ int render_frame_id)
+ : output_client_(output_client),
+ output_service_(output_service),
+ delegate_(nullptr),
+ render_frame_id_(render_frame_id),
+ stream_created_(false),
+ weak_ptr_factory_(this) {}
+
+ ~MojoAudioOutputIPC() override { StopClient(false); }
+
+ private:
+ // media::AudioOutputIPC implementation
+ void RequestDeviceAuthorization(media::AudioOutputIPCDelegate* delegate,
o1ka 2016/09/02 07:31:46 Could you split declaration and definition of meth
Max Morin 2016/09/02 10:27:07 Yes. I'll go through this class later.
+ int session_id,
+ const std::string& device_id,
+ const url::Origin& origin) override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+ DCHECK(delegate);
+ DCHECK(!delegate_); // Request exists/completed
+ DCHECK(!stream_created_); // Active stream exists
+
+ delegate_ = delegate;
+ stream_id_ = output_client_->delegates_.Add(delegate);
+ (*output_service_)
+ ->RequestDeviceAuthorization(
+ stream_id_, render_frame_id_, session_id, device_id, origin,
+ base::Bind(&MojoAudioOutputIPC::RequestDeviceAuthorizationCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void CreateStream(media::AudioOutputIPCDelegate* delegate,
+ const media::AudioParameters& params) override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+ DCHECK(!stream_created_);
+ DCHECK(delegate);
+ DCHECK(!delegate_ || delegate_ == delegate); // Ensure same delegate.
+
+ if (!delegate_)
+ stream_id_ = output_client_->delegates_.Add(delegate);
+ delegate_ = delegate;
o1ka 2016/09/02 07:31:46 Do we really want to continue if (delegate_ == del
+ media::mojom::AudioOutputStreamClientPtr client;
+ binding_.reset(new mojo::Binding<media::mojom::AudioOutputStreamClient>(
+ this, mojo::GetProxy(&client)));
+ binding_->set_connection_error_handler(base::Bind(
+ &MojoAudioOutputIPC::OnError, weak_ptr_factory_.GetWeakPtr()));
+
+ (*output_service_)
+ ->CreateStream(stream_id_, render_frame_id_, std::move(client), params,
+ base::Bind(&MojoAudioOutputIPC::CreateStreamCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+ stream_created_ = true;
+ }
+
+ void PlayStream() override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+ DCHECK(stream_created_);
+
+ output_stream_service_->Play();
+ }
+
+ void PauseStream() override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+ DCHECK(stream_created_);
+
+ output_stream_service_->Pause();
+ }
+
+ void SetVolume(double volume) override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+ DCHECK(stream_created_);
+
+ output_stream_service_->SetVolume(volume);
+ }
+
+ void CloseStream() override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+
+ stream_created_ = false;
+ StopClient(false);
+ }
+
+ // media::mojom::AudioOutputStreamClient implementation
+ void OnStreamStateChange(
+ media::mojom::AudioOutputStreamState state) override {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+
+ if (state == media::mojom::AudioOutputStreamState::ERROR) {
+ StopClient(true);
+ } else if (delegate_) {
+ // delegate_->OnStateChanged(state);
+ }
+ }
+
+ // This error handler is used by |output_stream_service_| on a connection
+ // error.
+ void OnError() {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+
+ OnStreamStateChange(media::mojom::AudioOutputStreamState::ERROR);
+ }
+
+ void StopClient(bool error) {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+
+ if (delegate_) {
+ if (error)
+ delegate_->OnStateChanged(media::mojom::AudioOutputStreamState::ERROR);
+ // |output_client_| may have called NotifyConnectionClose()
+ if (output_client_->delegates_.Lookup(stream_id_) == delegate_)
+ output_client_->delegates_.Remove(stream_id_);
+ }
+
+ if (output_stream_service_.is_bound())
+ (*output_service_)->CloseStream(stream_id_);
+
+ delegate_ = nullptr;
+ output_stream_service_.reset();
+ binding_.reset();
+ }
+
+ // Callback implementations
+ void RequestDeviceAuthorizationCallback(
+ int device_status,
+ const media::AudioParameters& output_params,
+ mojo::String matched_device_id) {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+
+ if (!delegate_)
+ return;
+ delegate_->OnDeviceAuthorized(
+ static_cast<media::OutputDeviceStatus>(device_status), output_params,
+ matched_device_id.get());
+ }
+
+ void CreateStreamCallback(media::mojom::AudioOutputStreamPtr stream,
+ mojo::ScopedSharedBufferHandle shared_buffer,
+ mojo::ScopedHandle socket_descriptor) {
+ DCHECK(output_client_->io_task_runner_->BelongsToCurrentThread());
+
+ // If stream creation failed, inform the delegate.
+ if (!stream.is_bound())
+ return OnError();
+ output_stream_service_ = std::move(stream);
+ output_stream_service_.set_connection_error_handler(base::Bind(
+ &MojoAudioOutputIPC::OnError, weak_ptr_factory_.GetWeakPtr()));
+
+ base::SharedMemoryHandle handle;
+ size_t length;
+ bool read_only;
+ MojoResult unwrap_shared_memory_result = mojo::UnwrapSharedMemoryHandle(
+ std::move(shared_buffer), &handle, &length, &read_only);
+
+ if (unwrap_shared_memory_result != MOJO_RESULT_OK) {
+ DLOG(ERROR) << "Failed to pass shared memory. Closing: "
+ << unwrap_shared_memory_result;
+ return OnError();
+ }
+
+ base::SyncSocket::TransitDescriptor descriptor;
+ MojoResult unwrap_platform_file_result =
+ mojo::UnwrapPlatformFile(std::move(socket_descriptor),
+#if defined(OS_WIN)
+ &descriptor);
+#else
+ &descriptor.fd);
+#endif
+ if (unwrap_platform_file_result != MOJO_RESULT_OK) {
+ DLOG(ERROR) << "Failed to pass transit descriptor. Closing: "
+ << unwrap_platform_file_result;
+ return OnError();
+ }
+
+ base::SyncSocket::Handle socket_handle =
+ base::SyncSocket::UnwrapHandle(descriptor);
+ if (!delegate_) {
+ base::SharedMemory::CloseHandle(handle);
+ base::SyncSocket socket(socket_handle);
+ return;
+ }
+ delegate_->OnStreamCreated(handle, socket_handle, length);
+ }
+
+ const scoped_refptr<AudioOutputIPCFactory> output_client_;
+ const media::mojom::AudioOutputPtr* output_service_;
+ media::mojom::AudioOutputStreamPtr output_stream_service_;
+ media::AudioOutputIPCDelegate* delegate_;
+
+ const int render_frame_id_;
+ int stream_id_;
+ bool stream_created_;
+
+ std::unique_ptr<mojo::Binding<media::mojom::AudioOutputStreamClient>>
+ binding_;
+
+ base::WeakPtrFactory<MojoAudioOutputIPC> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputIPC);
+};
+
+AudioOutputIPCFactory::AudioOutputIPCFactory(
+ const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ shell::InterfaceProvider* interface_provider)
+ : io_task_runner_(io_task_runner) {
+ DCHECK(!g_audio_output_ipc_factory);
+ g_audio_output_ipc_factory = this;
+
+ interface_provider->GetInterface(&output_service_);
+ output_service_.Bind(output_service_.PassInterface(), io_task_runner_);
+}
+
+AudioOutputIPCFactory::~AudioOutputIPCFactory() {
+ DCHECK(g_audio_output_ipc_factory == this);
+ g_audio_output_ipc_factory = nullptr;
+
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&AudioOutputIPCFactory::NotifyConnectionClose,
+ base::RetainedRef(this)));
+}
+
+AudioOutputIPCFactory* AudioOutputIPCFactory::g_audio_output_ipc_factory =
+ nullptr;
+
+// static
+const scoped_refptr<AudioOutputIPCFactory> AudioOutputIPCFactory::Get() {
+ return g_audio_output_ipc_factory;
+}
+
+std::unique_ptr<media::AudioOutputIPC>
+AudioOutputIPCFactory::CreateAudioOutputIPC(int render_frame_id) {
+ return std::unique_ptr<media::AudioOutputIPC>(
+ new MojoAudioOutputIPC(this, &output_service_, render_frame_id));
+}
+
+void AudioOutputIPCFactory::OnConnectionError() {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ NotifyConnectionClose();
+}
+
+void AudioOutputIPCFactory::NotifyConnectionClose() {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ output_service_.reset();
+ IDMap<media::AudioOutputIPCDelegate>::iterator it(&delegates_);
+ while (!it.IsAtEnd()) {
+ it.GetCurrentValue()->OnIPCClosed();
+ delegates_.Remove(it.GetCurrentKey());
+ it.Advance();
+ }
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698