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 |