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

Unified Diff: chromecast/browser/media/cma_message_filter_host.cc

Issue 823923002: [Chromecast] Add IPC code on brower process side (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years 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
« no previous file with comments | « chromecast/browser/media/cma_message_filter_host.h ('k') | chromecast/browser/media/cma_message_loop.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chromecast/browser/media/cma_message_filter_host.cc
diff --git a/chromecast/browser/media/cma_message_filter_host.cc b/chromecast/browser/media/cma_message_filter_host.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2fc590c3472dc20cf211b85835e154fd3d2380a5
--- /dev/null
+++ b/chromecast/browser/media/cma_message_filter_host.cc
@@ -0,0 +1,443 @@
+// Copyright 2014 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 "chromecast/browser/media/cma_message_filter_host.h"
+
+#include <utility>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/sync_socket.h"
+#include "chromecast/browser/media/cma_message_loop.h"
+#include "chromecast/browser/media/media_pipeline_host.h"
+#include "chromecast/common/media/cma_messages.h"
+#include "chromecast/media/cma/backend/video_plane.h"
+#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
+#include "chromecast/media/cma/pipeline/media_pipeline_client.h"
+#include "chromecast/media/cma/pipeline/video_pipeline_client.h"
+#include "content/public/browser/browser_thread.h"
+#include "media/base/bind_to_current_loop.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/size.h"
+
+namespace chromecast {
+namespace media {
+
+#define FORWARD_CALL(arg_pipeline, arg_fn, ...) \
+ task_runner_->PostTask( \
+ FROM_HERE, \
+ base::Bind(&MediaPipelineHost::arg_fn, \
+ base::Unretained(arg_pipeline), __VA_ARGS__))
+
+namespace {
+
+const size_t kMaxSharedMem = 8 * 1024 * 1024;
+
+void DestroyMediaPipeline(scoped_ptr<MediaPipelineHost> media_pipeline) {
+}
+
+void UpdateVideoSurfaceHost(int surface_id, const gfx::QuadF& quad) {
+ // Currently supports only one video plane.
+ CHECK_EQ(surface_id, 0);
+
+ VideoPlane* video_plane = GetVideoPlane();
+ video_plane->SetGeometry(
+ quad,
+ VideoPlane::COORDINATE_TYPE_GRAPHICS_PLANE);
+}
+
+} // namespace
+
+CmaMessageFilterHost::CmaMessageFilterHost(int render_process_id)
+ : content::BrowserMessageFilter(CastMediaMsgStart),
+ process_id_(render_process_id),
+ task_runner_(CmaMessageLoop::GetMessageLoopProxy()),
+ weak_factory_(this) {
+ weak_this_ = weak_factory_.GetWeakPtr();
+}
+
+CmaMessageFilterHost::~CmaMessageFilterHost() {
+ DCHECK(media_pipelines_.empty());
+}
+
+void CmaMessageFilterHost::OnChannelClosing() {
+ content::BrowserMessageFilter::OnChannelClosing();
+ DeleteEntries();
+}
+
+void CmaMessageFilterHost::OnDestruct() const {
+ content::BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
+bool CmaMessageFilterHost::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(CmaMessageFilterHost, message)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_CreateMedia, CreateMedia)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_DestroyMedia, DestroyMedia)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_SetCdm, SetCdm)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_CreateAvPipe, CreateAvPipe)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_AudioInitialize, AudioInitialize)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_VideoInitialize, VideoInitialize)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_StartPlayingFrom, StartPlayingFrom)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_Flush, Flush)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_Stop, Stop)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_SetPlaybackRate, SetPlaybackRate)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_SetVolume, SetVolume)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_NotifyPipeWrite, NotifyPipeWrite)
+ IPC_MESSAGE_HANDLER(CmaHostMsg_NotifyExternalSurface,
+ NotifyExternalSurface)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void CmaMessageFilterHost::DeleteEntries() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ for (MediaPipelineMap::iterator it = media_pipelines_.begin();
+ it != media_pipelines_.end(); ) {
+ scoped_ptr<MediaPipelineHost> media_pipeline(it->second);
+ media_pipelines_.erase(it++);
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DestroyMediaPipeline, base::Passed(&media_pipeline)));
+ }
+}
+
+MediaPipelineHost* CmaMessageFilterHost::LookupById(int media_id) {
+ MediaPipelineMap::iterator it = media_pipelines_.find(media_id);
+ if (it == media_pipelines_.end())
+ return NULL;
+ return it->second;
+}
+
+
+// *** Handle incoming messages ***
+
+void CmaMessageFilterHost::CreateMedia(int media_id, LoadType load_type) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ scoped_ptr<MediaPipelineHost> media_pipeline_host(new MediaPipelineHost());
+ MediaPipelineClient client;
+ client.time_update_cb = ::media::BindToCurrentLoop(base::Bind(
+ &CmaMessageFilterHost::OnTimeUpdate, weak_this_, media_id));
+ client.buffering_state_cb = ::media::BindToCurrentLoop(base::Bind(
+ &CmaMessageFilterHost::OnBufferingNotification, weak_this_, media_id));
+ client.error_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnPlaybackError,
+ weak_this_, media_id, media::kNoTrackId));
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaPipelineHost::Initialize,
+ base::Unretained(media_pipeline_host.get()),
+ load_type, client));
+ std::pair<MediaPipelineMap::iterator, bool> ret =
+ media_pipelines_.insert(
+ std::make_pair(media_id, media_pipeline_host.release()));
+
+ // Check there is no other entry with the same ID.
+ DCHECK(ret.second != false);
+}
+
+void CmaMessageFilterHost::DestroyMedia(int media_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ MediaPipelineMap::iterator it = media_pipelines_.find(media_id);
+ if (it == media_pipelines_.end())
+ return;
+
+ scoped_ptr<MediaPipelineHost> media_pipeline(it->second);
+ media_pipelines_.erase(it);
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DestroyMediaPipeline, base::Passed(&media_pipeline)));
+}
+
+void CmaMessageFilterHost::SetCdm(int media_id,
+ int render_frame_id,
+ int cdm_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline)
+ return;
+
+ FORWARD_CALL(media_pipeline, SetCdm, process_id_, render_frame_id, cdm_id);
+}
+
+void CmaMessageFilterHost::CreateAvPipe(
+ int media_id, TrackId track_id, size_t shared_mem_size) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ base::FileDescriptor foreign_socket_handle;
+ base::SharedMemoryHandle foreign_memory_handle;
+
+ // A few sanity checks before allocating resources.
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline || !PeerHandle() || shared_mem_size > kMaxSharedMem) {
+ Send(new CmaMsg_AvPipeCreated(
+ media_id, track_id, false,
+ foreign_memory_handle, foreign_socket_handle));
+ return;
+ }
+
+ // Create the local/foreign sockets to signal media message
+ // consune/feed events.
+ // Use CancelableSyncSocket so that write is always non-blocking.
+ scoped_ptr<base::CancelableSyncSocket> local_socket(
+ new base::CancelableSyncSocket());
+ scoped_ptr<base::CancelableSyncSocket> foreign_socket(
+ new base::CancelableSyncSocket());
+ if (!base::CancelableSyncSocket::CreatePair(local_socket.get(),
+ foreign_socket.get()) ||
+ foreign_socket->handle() == -1) {
+ Send(new CmaMsg_AvPipeCreated(
+ media_id, track_id, false,
+ foreign_memory_handle, foreign_socket_handle));
+ return;
+ }
+
+ // Shared memory used to convey media messages.
+ scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
+ if (!shared_memory->CreateAndMapAnonymous(shared_mem_size) ||
+ !shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle)) {
+ Send(new CmaMsg_AvPipeCreated(
+ media_id, track_id, false,
+ foreign_memory_handle, foreign_socket_handle));
+ return;
+ }
+
+ // Note: the IPC message can be sent only once the pipe has been fully
+ // configured. Part of this configuration is done in
+ // |MediaPipelineHost::SetAvPipe|.
+ // TODO(erickung): investigate possible memory leak here.
+ // If the weak pointer in |av_pipe_set_cb| gets invalidated,
+ // then |foreign_memory_handle| leaks.
+ base::Closure pipe_read_activity_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnPipeReadActivity, weak_this_,
+ media_id, track_id));
+ base::Closure av_pipe_set_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnAvPipeSet, weak_this_,
+ media_id, track_id,
+ foreign_memory_handle, base::Passed(&foreign_socket)));
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaPipelineHost::SetAvPipe,
+ base::Unretained(media_pipeline),
+ track_id,
+ base::Passed(&shared_memory),
+ pipe_read_activity_cb,
+ av_pipe_set_cb));
+}
+
+void CmaMessageFilterHost::OnAvPipeSet(
+ int media_id,
+ TrackId track_id,
+ base::SharedMemoryHandle foreign_memory_handle,
+ scoped_ptr<base::CancelableSyncSocket> foreign_socket) {
+ base::FileDescriptor foreign_socket_handle;
+ foreign_socket_handle.fd = foreign_socket->handle();
+ foreign_socket_handle.auto_close = false;
+
+ // This message can only be set once the pipe has fully been configured
+ // by |MediaPipelineHost|.
+ Send(new CmaMsg_AvPipeCreated(
+ media_id, track_id, true, foreign_memory_handle, foreign_socket_handle));
+}
+
+void CmaMessageFilterHost::AudioInitialize(
+ int media_id, TrackId track_id, const ::media::AudioDecoderConfig& config) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline) {
+ Send(new CmaMsg_TrackStateChanged(
+ media_id, track_id, ::media::PIPELINE_ERROR_ABORT));
+ return;
+ }
+
+ AvPipelineClient client;
+ client.eos_cb = ::media::BindToCurrentLoop(base::Bind(
+ &CmaMessageFilterHost::OnEos, weak_this_, media_id, track_id));
+ client.playback_error_cb = ::media::BindToCurrentLoop(base::Bind(
+ &CmaMessageFilterHost::OnPlaybackError, weak_this_, media_id, track_id));
+ client.statistics_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnStatisticsUpdated, weak_this_,
+ media_id, track_id));
+
+ ::media::PipelineStatusCB pipeline_status_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnTrackStateChanged, weak_this_,
+ media_id, track_id));
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaPipelineHost::AudioInitialize,
+ base::Unretained(media_pipeline),
+ track_id, client, config, pipeline_status_cb));
+}
+
+void CmaMessageFilterHost::VideoInitialize(
+ int media_id, TrackId track_id, const ::media::VideoDecoderConfig& config) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline) {
+ Send(new CmaMsg_TrackStateChanged(
+ media_id, track_id, ::media::PIPELINE_ERROR_ABORT));
+ return;
+ }
+
+ VideoPipelineClient client;
+ client.av_pipeline_client.eos_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnEos, weak_this_,
+ media_id, track_id));
+ client.av_pipeline_client.playback_error_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnPlaybackError, weak_this_,
+ media_id, track_id));
+ client.av_pipeline_client.statistics_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnStatisticsUpdated, weak_this_,
+ media_id, track_id));
+ client.natural_size_changed_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnNaturalSizeChanged, weak_this_,
+ media_id, track_id));
+
+ ::media::PipelineStatusCB pipeline_status_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnTrackStateChanged, weak_this_,
+ media_id, track_id));
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaPipelineHost::VideoInitialize,
+ base::Unretained(media_pipeline),
+ track_id, client, config, pipeline_status_cb));
+}
+
+void CmaMessageFilterHost::StartPlayingFrom(
+ int media_id, base::TimeDelta time) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline)
+ return;
+ FORWARD_CALL(media_pipeline, StartPlayingFrom, time);
+}
+
+void CmaMessageFilterHost::Flush(int media_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline) {
+ Send(new CmaMsg_MediaStateChanged(
+ media_id, ::media::PIPELINE_ERROR_ABORT));
+ return;
+ }
+ ::media::PipelineStatusCB pipeline_status_cb = ::media::BindToCurrentLoop(
+ base::Bind(&CmaMessageFilterHost::OnMediaStateChanged, weak_this_,
+ media_id));
+ FORWARD_CALL(media_pipeline, Flush, pipeline_status_cb);
+}
+
+void CmaMessageFilterHost::Stop(int media_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline)
+ return;
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaPipelineHost::Stop,
+ base::Unretained(media_pipeline)));
+}
+
+void CmaMessageFilterHost::SetPlaybackRate(
+ int media_id, float playback_rate) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline)
+ return;
+ FORWARD_CALL(media_pipeline, SetPlaybackRate, playback_rate);
+}
+
+void CmaMessageFilterHost::SetVolume(
+ int media_id, TrackId track_id, float volume) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline)
+ return;
+ FORWARD_CALL(media_pipeline, SetVolume, track_id, volume);
+}
+
+void CmaMessageFilterHost::NotifyPipeWrite(int media_id, TrackId track_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ MediaPipelineHost* media_pipeline = LookupById(media_id);
+ if (!media_pipeline)
+ return;
+ FORWARD_CALL(media_pipeline, NotifyPipeWrite, track_id);
+}
+
+void CmaMessageFilterHost::NotifyExternalSurface(
+ int surface_id,
+ const gfx::PointF& p0, const gfx::PointF& p1,
+ const gfx::PointF& p2, const gfx::PointF& p3) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UpdateVideoSurfaceHost, surface_id,
+ gfx::QuadF(p0, p1, p2, p3)));
+}
+
+// *** Browser to renderer messages ***
+
+void CmaMessageFilterHost::OnMediaStateChanged(
+ int media_id, ::media::PipelineStatus status) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_MediaStateChanged(media_id, status));
+}
+
+void CmaMessageFilterHost::OnTrackStateChanged(
+ int media_id, TrackId track_id, ::media::PipelineStatus status) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_TrackStateChanged(media_id, track_id, status));
+}
+
+void CmaMessageFilterHost::OnPipeReadActivity(int media_id, TrackId track_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_NotifyPipeRead(media_id, track_id));
+}
+
+void CmaMessageFilterHost::OnTimeUpdate(
+ int media_id,
+ base::TimeDelta media_time,
+ base::TimeDelta max_media_time,
+ base::TimeTicks stc) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_TimeUpdate(media_id,
+ media_time, max_media_time, stc));
+}
+
+void CmaMessageFilterHost::OnBufferingNotification(
+ int media_id, ::media::BufferingState state) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_BufferingNotification(media_id, state));
+}
+
+void CmaMessageFilterHost::OnEos(int media_id, TrackId track_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_Eos(media_id, track_id));
+}
+
+void CmaMessageFilterHost::OnPlaybackError(
+ int media_id, TrackId track_id, ::media::PipelineStatus status) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_PlaybackError(media_id, track_id, status));
+}
+
+void CmaMessageFilterHost::OnStatisticsUpdated(
+ int media_id, TrackId track_id, const ::media::PipelineStatistics& stats) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_PlaybackStatistics(media_id, track_id, stats));
+}
+
+void CmaMessageFilterHost::OnNaturalSizeChanged(
+ int media_id, TrackId track_id, const gfx::Size& size) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ Send(new CmaMsg_NaturalSizeChanged(media_id, track_id, size));
+}
+
+} // namespace media
+} // namespace chromecast
« no previous file with comments | « chromecast/browser/media/cma_message_filter_host.h ('k') | chromecast/browser/media/cma_message_loop.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698