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 |