Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chromecast/renderer/media/media_pipeline_proxy.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/callback_helpers.h" | |
| 9 #include "base/location.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/message_loop/message_loop_proxy.h" | |
| 12 #include "chromecast/common/media/cma_messages.h" | |
| 13 #include "chromecast/media/cma/base/coded_frame_provider.h" | |
| 14 #include "chromecast/renderer/media/audio_pipeline_proxy.h" | |
| 15 #include "chromecast/renderer/media/media_channel_proxy.h" | |
| 16 #include "chromecast/renderer/media/video_pipeline_proxy.h" | |
| 17 | |
| 18 namespace chromecast { | |
| 19 namespace cma { | |
| 20 | |
| 21 // MediaPipelineProxyInternal - | |
| 22 // This class is not thread safe and should run on the same thread | |
| 23 // as the media channel proxy. | |
| 24 class MediaPipelineProxyInternal { | |
| 25 public: | |
| 26 static void Release(scoped_ptr<MediaPipelineProxyInternal> proxy); | |
| 27 | |
| 28 explicit MediaPipelineProxyInternal( | |
| 29 scoped_refptr<MediaChannelProxy> media_channel_proxy); | |
| 30 virtual ~MediaPipelineProxyInternal(); | |
| 31 | |
| 32 void SetClient(const chromecast::media::MediaPipelineClient& client); | |
| 33 void SetCdm(int render_frame_id, int cdm_id); | |
| 34 void StartPlayingFrom(const base::TimeDelta& time); | |
| 35 void Flush(const ::media::PipelineStatusCB& status_cb); | |
| 36 void Stop(); | |
| 37 void SetPlaybackRate(float playback_rate); | |
| 38 | |
| 39 private: | |
| 40 void Shutdown(); | |
| 41 | |
| 42 // Callbacks for CmaMessageFilterHost::MediaDelegate. | |
| 43 void OnStateChanged(::media::PipelineStatus status); | |
| 44 | |
| 45 base::ThreadChecker thread_checker_; | |
| 46 | |
| 47 scoped_refptr<MediaChannelProxy> media_channel_proxy_; | |
| 48 | |
| 49 chromecast::media::MediaPipelineClient client_; | |
| 50 | |
| 51 // Store the callback for a pending state transition. | |
| 52 ::media::PipelineStatusCB status_cb_; | |
| 53 | |
| 54 DISALLOW_COPY_AND_ASSIGN(MediaPipelineProxyInternal); | |
|
gunsch
2014/12/20 22:41:34
base/macros.h
erickung1
2014/12/21 11:10:47
may not need it since media_pipeline_proxy.h alrea
| |
| 55 }; | |
| 56 | |
| 57 // static | |
| 58 void MediaPipelineProxyInternal::Release( | |
| 59 scoped_ptr<MediaPipelineProxyInternal> proxy) { | |
| 60 proxy->Shutdown(); | |
| 61 } | |
| 62 | |
| 63 MediaPipelineProxyInternal::MediaPipelineProxyInternal( | |
| 64 scoped_refptr<MediaChannelProxy> media_channel_proxy) | |
| 65 : media_channel_proxy_(media_channel_proxy) { | |
| 66 DCHECK(media_channel_proxy.get()); | |
| 67 | |
| 68 // Creation can be done on a different thread. | |
| 69 thread_checker_.DetachFromThread(); | |
| 70 } | |
| 71 | |
| 72 MediaPipelineProxyInternal::~MediaPipelineProxyInternal() { | |
| 73 } | |
| 74 | |
| 75 void MediaPipelineProxyInternal::Shutdown() { | |
| 76 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 77 | |
| 78 // Remove any callback on VideoPipelineProxyInternal. | |
| 79 media_channel_proxy_->SetMediaDelegate( | |
| 80 CmaMessageFilterProxy::MediaDelegate()); | |
| 81 } | |
| 82 | |
| 83 void MediaPipelineProxyInternal::SetClient( | |
| 84 const chromecast::media::MediaPipelineClient& client) { | |
| 85 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 86 DCHECK(!client.error_cb.is_null()); | |
| 87 DCHECK(!client.buffering_state_cb.is_null()); | |
| 88 client_ = client; | |
| 89 | |
| 90 CmaMessageFilterProxy::MediaDelegate delegate; | |
| 91 delegate.state_changed_cb = | |
| 92 base::Bind(&MediaPipelineProxyInternal::OnStateChanged, | |
| 93 base::Unretained(this)); | |
| 94 delegate.client = client; | |
| 95 bool success = media_channel_proxy_->SetMediaDelegate(delegate); | |
| 96 CHECK(success); | |
| 97 } | |
| 98 | |
| 99 void MediaPipelineProxyInternal::SetCdm(int render_frame_id, int cdm_id) { | |
| 100 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 101 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>( | |
| 102 new CmaHostMsg_SetCdm(media_channel_proxy_->GetId(), | |
| 103 render_frame_id, | |
| 104 cdm_id))); | |
| 105 LOG_IF(ERROR, !success) << "Failed to send SetCdm=" << cdm_id; | |
| 106 } | |
| 107 | |
| 108 void MediaPipelineProxyInternal::Flush( | |
| 109 const ::media::PipelineStatusCB& status_cb) { | |
| 110 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 111 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>( | |
| 112 new CmaHostMsg_Flush(media_channel_proxy_->GetId()))); | |
| 113 if (!success) { | |
| 114 status_cb.Run(::media::PIPELINE_ERROR_ABORT); | |
| 115 return; | |
| 116 } | |
| 117 DCHECK(status_cb_.is_null()); | |
| 118 status_cb_ = status_cb; | |
| 119 } | |
| 120 | |
| 121 void MediaPipelineProxyInternal::Stop() { | |
| 122 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 123 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>( | |
| 124 new CmaHostMsg_Stop(media_channel_proxy_->GetId()))); | |
| 125 if (!success) | |
| 126 client_.error_cb.Run(::media::PIPELINE_ERROR_ABORT); | |
| 127 } | |
| 128 | |
| 129 void MediaPipelineProxyInternal::StartPlayingFrom(const base::TimeDelta& time) { | |
| 130 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 131 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>( | |
| 132 new CmaHostMsg_StartPlayingFrom( | |
| 133 media_channel_proxy_->GetId(), time))); | |
| 134 if (!success) | |
| 135 client_.error_cb.Run(::media::PIPELINE_ERROR_ABORT); | |
| 136 } | |
| 137 | |
| 138 void MediaPipelineProxyInternal::SetPlaybackRate(float playback_rate) { | |
| 139 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 140 media_channel_proxy_->Send(scoped_ptr<IPC::Message>( | |
| 141 new CmaHostMsg_SetPlaybackRate( | |
| 142 media_channel_proxy_->GetId(), playback_rate))); | |
| 143 } | |
| 144 | |
| 145 void MediaPipelineProxyInternal::OnStateChanged( | |
| 146 ::media::PipelineStatus status) { | |
| 147 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 148 DCHECK(!status_cb_.is_null()); | |
| 149 base::ResetAndReturn(&status_cb_).Run(status); | |
| 150 } | |
| 151 | |
| 152 | |
| 153 #define FORWARD_ON_IO_0(param_fn) \ | |
|
gunsch
2014/12/20 22:41:34
same comment: can these be merged using ##__VA_ARG
erickung1
2014/12/21 11:10:47
Done.
| |
| 154 io_message_loop_proxy_->PostTask( \ | |
| 155 FROM_HERE, \ | |
| 156 base::Bind(&MediaPipelineProxyInternal::param_fn, \ | |
| 157 base::Unretained(proxy_.get()))) | |
| 158 #define FORWARD_ON_IO_1(param_fn, param_arg1) \ | |
| 159 io_message_loop_proxy_->PostTask( \ | |
| 160 FROM_HERE, \ | |
| 161 base::Bind(&MediaPipelineProxyInternal::param_fn, \ | |
| 162 base::Unretained(proxy_.get()), (param_arg1))) | |
| 163 #define FORWARD_ON_IO_2(param_fn, param_arg1, param_arg2) \ | |
| 164 io_message_loop_proxy_->PostTask( \ | |
| 165 FROM_HERE, \ | |
| 166 base::Bind(&MediaPipelineProxyInternal::param_fn, \ | |
| 167 base::Unretained(proxy_.get()), (param_arg1), (param_arg2))) | |
| 168 | |
| 169 MediaPipelineProxy::MediaPipelineProxy( | |
| 170 int render_frame_id, | |
| 171 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy, | |
| 172 chromecast::media::LoadType load_type) | |
| 173 : io_message_loop_proxy_(io_message_loop_proxy), | |
| 174 render_frame_id_(render_frame_id), | |
| 175 media_channel_proxy_(new MediaChannelProxy), | |
| 176 proxy_(new MediaPipelineProxyInternal(media_channel_proxy_)), | |
| 177 has_audio_(false), | |
| 178 has_video_(false), | |
| 179 audio_pipeline_(new AudioPipelineProxy( | |
| 180 io_message_loop_proxy, media_channel_proxy_)), | |
| 181 video_pipeline_(new VideoPipelineProxy( | |
| 182 io_message_loop_proxy, media_channel_proxy_)), | |
| 183 weak_factory_(this) { | |
| 184 weak_this_ = weak_factory_.GetWeakPtr(); | |
| 185 io_message_loop_proxy_->PostTask( | |
| 186 FROM_HERE, | |
| 187 base::Bind(&MediaChannelProxy::Open, media_channel_proxy_, | |
| 188 load_type)); | |
| 189 thread_checker_.DetachFromThread(); | |
| 190 } | |
| 191 | |
| 192 MediaPipelineProxy::~MediaPipelineProxy() { | |
| 193 io_message_loop_proxy_->PostTask( | |
| 194 FROM_HERE, | |
| 195 base::Bind(&MediaPipelineProxyInternal::Release, base::Passed(&proxy_))); | |
| 196 io_message_loop_proxy_->PostTask( | |
| 197 FROM_HERE, | |
| 198 base::Bind(&MediaChannelProxy::Close, media_channel_proxy_)); | |
| 199 } | |
| 200 | |
| 201 void MediaPipelineProxy::SetClient( | |
| 202 const chromecast::media::MediaPipelineClient& client) { | |
| 203 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 204 FORWARD_ON_IO_1(SetClient, client); | |
| 205 } | |
| 206 | |
| 207 void MediaPipelineProxy::SetCdm(int cdm_id) { | |
| 208 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 209 FORWARD_ON_IO_2(SetCdm, render_frame_id_, cdm_id); | |
| 210 } | |
| 211 | |
| 212 chromecast::media::AudioPipeline* | |
| 213 MediaPipelineProxy::GetAudioPipeline() const { | |
| 214 return audio_pipeline_.get(); | |
| 215 } | |
| 216 | |
| 217 chromecast::media::VideoPipeline* | |
| 218 MediaPipelineProxy::GetVideoPipeline() const { | |
| 219 return video_pipeline_.get(); | |
| 220 } | |
| 221 | |
| 222 void MediaPipelineProxy::InitializeAudio( | |
| 223 const ::media::AudioDecoderConfig& config, | |
| 224 scoped_ptr<chromecast::media::CodedFrameProvider> frame_provider, | |
| 225 const ::media::PipelineStatusCB& status_cb) { | |
| 226 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 227 has_audio_ = true; | |
| 228 audio_pipeline_->Initialize(config, frame_provider.Pass(), status_cb); | |
| 229 } | |
| 230 | |
| 231 void MediaPipelineProxy::InitializeVideo( | |
| 232 const ::media::VideoDecoderConfig& config, | |
| 233 scoped_ptr<chromecast::media::CodedFrameProvider> frame_provider, | |
| 234 const ::media::PipelineStatusCB& status_cb) { | |
| 235 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 236 has_video_ = true; | |
| 237 video_pipeline_->Initialize(config, frame_provider.Pass(), status_cb); | |
| 238 } | |
| 239 | |
| 240 void MediaPipelineProxy::StartPlayingFrom(base::TimeDelta time) { | |
| 241 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 242 if (has_audio_) | |
| 243 audio_pipeline_->StartFeeding(); | |
| 244 if (has_video_) | |
| 245 video_pipeline_->StartFeeding(); | |
| 246 FORWARD_ON_IO_1(StartPlayingFrom, time); | |
| 247 } | |
| 248 | |
| 249 void MediaPipelineProxy::Flush(const ::media::PipelineStatusCB& status_cb) { | |
| 250 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 251 DCHECK(has_audio_ || has_video_); | |
| 252 | |
| 253 ::media::SerialRunner::Queue bound_fns; | |
| 254 if (has_audio_) { | |
| 255 bound_fns.Push(base::Bind(&AudioPipelineProxy::Flush, | |
| 256 base::Unretained(audio_pipeline_.get()))); | |
| 257 } | |
| 258 if (has_video_) { | |
| 259 bound_fns.Push(base::Bind(&VideoPipelineProxy::Flush, | |
| 260 base::Unretained(video_pipeline_.get()))); | |
| 261 } | |
| 262 ::media::PipelineStatusCB cb = | |
| 263 base::Bind(&MediaPipelineProxy::OnProxyFlushDone, weak_this_, status_cb); | |
| 264 pending_callbacks_ = ::media::SerialRunner::Run(bound_fns, cb); | |
| 265 } | |
| 266 | |
| 267 void MediaPipelineProxy::OnProxyFlushDone( | |
| 268 const ::media::PipelineStatusCB& status_cb, | |
| 269 ::media::PipelineStatus status) { | |
| 270 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 271 DCHECK_EQ(status, ::media::PIPELINE_OK); | |
| 272 pending_callbacks_.reset(); | |
| 273 FORWARD_ON_IO_1(Flush, status_cb); | |
| 274 } | |
| 275 | |
| 276 void MediaPipelineProxy::Stop() { | |
| 277 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 278 DCHECK(has_audio_ || has_video_); | |
| 279 | |
| 280 if (has_audio_) | |
| 281 audio_pipeline_->Stop(); | |
| 282 if (has_video_) | |
| 283 video_pipeline_->Stop(); | |
| 284 | |
| 285 FORWARD_ON_IO_0(Stop); | |
| 286 } | |
| 287 | |
| 288 void MediaPipelineProxy::SetPlaybackRate(float playback_rate) { | |
| 289 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 290 FORWARD_ON_IO_1(SetPlaybackRate, playback_rate); | |
| 291 } | |
| 292 | |
| 293 } // namespace cma | |
| 294 } // namespace chromecast | |
| 295 | |
| OLD | NEW |