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