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

Side by Side Diff: media/mojo/clients/mojo_renderer_impl.cc

Issue 2070753002: media: Add unittest for MojoRenderer{Impl|Service} (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/mojo/clients/mojo_renderer_impl.h" 5 #include "media/mojo/clients/mojo_renderer_impl.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
(...skipping 16 matching lines...) Expand all
27 video_overlay_factory_(std::move(video_overlay_factory)), 27 video_overlay_factory_(std::move(video_overlay_factory)),
28 video_renderer_sink_(video_renderer_sink), 28 video_renderer_sink_(video_renderer_sink),
29 remote_renderer_info_(remote_renderer.PassInterface()), 29 remote_renderer_info_(remote_renderer.PassInterface()),
30 binding_(this) { 30 binding_(this) {
31 DVLOG(1) << __FUNCTION__; 31 DVLOG(1) << __FUNCTION__;
32 } 32 }
33 33
34 MojoRendererImpl::~MojoRendererImpl() { 34 MojoRendererImpl::~MojoRendererImpl() {
35 DVLOG(1) << __FUNCTION__; 35 DVLOG(1) << __FUNCTION__;
36 DCHECK(task_runner_->BelongsToCurrentThread()); 36 DCHECK(task_runner_->BelongsToCurrentThread());
37
38 FireAllPendingCallbacks();
sandersd (OOO until July 31) 2016/06/16 18:10:06 Why does the destructor need to call this?
xhwang 2016/06/17 06:59:00 The Renderer API says all pending callbacks should
37 } 39 }
38 40
39 void MojoRendererImpl::Initialize( 41 void MojoRendererImpl::Initialize(
40 DemuxerStreamProvider* demuxer_stream_provider, 42 DemuxerStreamProvider* demuxer_stream_provider,
41 media::RendererClient* client, 43 media::RendererClient* client,
42 const PipelineStatusCB& init_cb) { 44 const PipelineStatusCB& init_cb) {
43 DVLOG(1) << __FUNCTION__; 45 DVLOG(1) << __FUNCTION__;
44 DCHECK(task_runner_->BelongsToCurrentThread()); 46 DCHECK(task_runner_->BelongsToCurrentThread());
45 DCHECK(demuxer_stream_provider); 47 DCHECK(demuxer_stream_provider);
46 48
49 if (encountered_error_) {
50 task_runner_->PostTask(
51 FROM_HERE, base::Bind(init_cb, PIPELINE_ERROR_INITIALIZATION_FAILED));
52 return;
53 }
54
47 demuxer_stream_provider_ = demuxer_stream_provider; 55 demuxer_stream_provider_ = demuxer_stream_provider;
48 client_ = client;
49 init_cb_ = init_cb; 56 init_cb_ = init_cb;
50 57
51 // Create audio and video mojom::DemuxerStream and bind its lifetime to 58 // Create audio and video mojom::DemuxerStream and bind its lifetime to
52 // the pipe. 59 // the pipe.
53 DemuxerStream* const audio = 60 DemuxerStream* const audio =
54 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); 61 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
55 DemuxerStream* const video = 62 DemuxerStream* const video =
56 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); 63 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
57 64
58 mojom::DemuxerStreamPtr audio_stream; 65 mojom::DemuxerStreamPtr audio_stream;
59 if (audio) 66 if (audio)
60 new MojoDemuxerStreamImpl(audio, GetProxy(&audio_stream)); 67 new MojoDemuxerStreamImpl(audio, GetProxy(&audio_stream));
61 68
62 mojom::DemuxerStreamPtr video_stream; 69 mojom::DemuxerStreamPtr video_stream;
63 if (video) 70 if (video)
64 new MojoDemuxerStreamImpl(video, GetProxy(&video_stream)); 71 new MojoDemuxerStreamImpl(video, GetProxy(&video_stream));
65 72
66 BindRemoteRendererIfNeeded(); 73 BindRemoteRendererIfNeeded();
67 74
68 // Using base::Unretained(this) is safe because |this| owns 75 // Using base::Unretained(this) is safe because |this| owns
69 // |remote_renderer_|, and the callback won't be dispatched if 76 // |remote_renderer_|, and the callback won't be dispatched if
70 // |remote_renderer_| is destroyed. 77 // |remote_renderer_| is destroyed.
71 remote_renderer_->Initialize( 78 remote_renderer_->Initialize(binding_.CreateInterfacePtrAndBind(),
72 binding_.CreateInterfacePtrAndBind(), std::move(audio_stream), 79 std::move(audio_stream), std::move(video_stream),
73 std::move(video_stream), 80 base::Bind(&MojoRendererImpl::OnInitialized,
74 base::Bind(&MojoRendererImpl::OnInitialized, base::Unretained(this))); 81 base::Unretained(this), client));
75 } 82 }
76 83
77 void MojoRendererImpl::SetCdm(CdmContext* cdm_context, 84 void MojoRendererImpl::SetCdm(CdmContext* cdm_context,
78 const CdmAttachedCB& cdm_attached_cb) { 85 const CdmAttachedCB& cdm_attached_cb) {
79 DVLOG(1) << __FUNCTION__; 86 DVLOG(1) << __FUNCTION__;
80 DCHECK(task_runner_->BelongsToCurrentThread()); 87 DCHECK(task_runner_->BelongsToCurrentThread());
81 DCHECK(cdm_context); 88 DCHECK(cdm_context);
89 DCHECK(!cdm_attached_cb.is_null());
90 DCHECK(cdm_attached_cb_.is_null());
91
92 if (encountered_error_) {
93 task_runner_->PostTask(FROM_HERE, base::Bind(cdm_attached_cb, false));
94 return;
95 }
82 96
83 int32_t cdm_id = cdm_context->GetCdmId(); 97 int32_t cdm_id = cdm_context->GetCdmId();
84 if (cdm_id == CdmContext::kInvalidCdmId) { 98 if (cdm_id == CdmContext::kInvalidCdmId) {
85 DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID " 99 DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID "
86 "is invalid."; 100 "is invalid.";
87 cdm_attached_cb.Run(false); 101 task_runner_->PostTask(FROM_HERE, base::Bind(cdm_attached_cb, false));
88 return; 102 return;
89 } 103 }
90 104
91 BindRemoteRendererIfNeeded(); 105 BindRemoteRendererIfNeeded();
92 remote_renderer_->SetCdm(cdm_id, cdm_attached_cb); 106
107 cdm_attached_cb_ = cdm_attached_cb;
108 remote_renderer_->SetCdm(cdm_id, base::Bind(&MojoRendererImpl::OnCdmAttached,
109 base::Unretained(this)));
93 } 110 }
94 111
95 void MojoRendererImpl::Flush(const base::Closure& flush_cb) { 112 void MojoRendererImpl::Flush(const base::Closure& flush_cb) {
96 DVLOG(2) << __FUNCTION__; 113 DVLOG(2) << __FUNCTION__;
97 DCHECK(task_runner_->BelongsToCurrentThread()); 114 DCHECK(task_runner_->BelongsToCurrentThread());
98 DCHECK(remote_renderer_.is_bound()); 115 DCHECK(remote_renderer_.is_bound());
99 remote_renderer_->Flush(flush_cb); 116 DCHECK(!flush_cb.is_null());
117 DCHECK(flush_cb_.is_null());
118
119 if (encountered_error_) {
120 task_runner_->PostTask(FROM_HERE, flush_cb);
121 return;
122 }
123
124 flush_cb_ = flush_cb;
125 remote_renderer_->Flush(
126 base::Bind(&MojoRendererImpl::OnFlushed, base::Unretained(this)));
100 } 127 }
101 128
102 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time) { 129 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time) {
103 DVLOG(2) << __FUNCTION__; 130 DVLOG(2) << __FUNCTION__;
104 DCHECK(task_runner_->BelongsToCurrentThread()); 131 DCHECK(task_runner_->BelongsToCurrentThread());
105 DCHECK(remote_renderer_.is_bound()); 132 DCHECK(remote_renderer_.is_bound());
106 133
107 { 134 {
108 base::AutoLock auto_lock(lock_); 135 base::AutoLock auto_lock(lock_);
109 time_ = time; 136 time_ = time;
110 } 137 }
111 138
112 remote_renderer_->StartPlayingFrom(time.InMicroseconds()); 139 remote_renderer_->StartPlayingFrom(time.InMicroseconds());
113 } 140 }
114 141
115 void MojoRendererImpl::SetPlaybackRate(double playback_rate) { 142 void MojoRendererImpl::SetPlaybackRate(double playback_rate) {
116 DVLOG(2) << __FUNCTION__; 143 DVLOG(2) << __FUNCTION__;
117 DCHECK(task_runner_->BelongsToCurrentThread()); 144 DCHECK(task_runner_->BelongsToCurrentThread());
118 DCHECK(remote_renderer_.is_bound()); 145 DCHECK(remote_renderer_.is_bound());
146
119 remote_renderer_->SetPlaybackRate(playback_rate); 147 remote_renderer_->SetPlaybackRate(playback_rate);
120 } 148 }
121 149
122 void MojoRendererImpl::SetVolume(float volume) { 150 void MojoRendererImpl::SetVolume(float volume) {
123 DVLOG(2) << __FUNCTION__; 151 DVLOG(2) << __FUNCTION__;
124 DCHECK(task_runner_->BelongsToCurrentThread()); 152 DCHECK(task_runner_->BelongsToCurrentThread());
125 DCHECK(remote_renderer_.is_bound()); 153 DCHECK(remote_renderer_.is_bound());
154
126 remote_renderer_->SetVolume(volume); 155 remote_renderer_->SetVolume(volume);
127 } 156 }
128 157
129 base::TimeDelta MojoRendererImpl::GetMediaTime() { 158 base::TimeDelta MojoRendererImpl::GetMediaTime() {
130 base::AutoLock auto_lock(lock_); 159 base::AutoLock auto_lock(lock_);
131 DVLOG(3) << __FUNCTION__ << ": " << time_.InMilliseconds() << " ms"; 160 DVLOG(3) << __FUNCTION__ << ": " << time_.InMilliseconds() << " ms";
132 return time_; 161 return time_;
133 } 162 }
134 163
135 bool MojoRendererImpl::HasAudio() { 164 bool MojoRendererImpl::HasAudio() {
136 DVLOG(1) << __FUNCTION__; 165 DVLOG(1) << __FUNCTION__;
137 DCHECK(task_runner_->BelongsToCurrentThread()); 166 DCHECK(task_runner_->BelongsToCurrentThread());
138 DCHECK(remote_renderer_.get()); // We always bind the renderer. 167 DCHECK(remote_renderer_.is_bound());
168
139 return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); 169 return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
140 } 170 }
141 171
142 bool MojoRendererImpl::HasVideo() { 172 bool MojoRendererImpl::HasVideo() {
143 DVLOG(1) << __FUNCTION__; 173 DVLOG(1) << __FUNCTION__;
144 DCHECK(task_runner_->BelongsToCurrentThread()); 174 DCHECK(task_runner_->BelongsToCurrentThread());
175 DCHECK(remote_renderer_.is_bound());
176
145 return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); 177 return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
146 } 178 }
147 179
148 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec, int64_t max_time_usec) { 180 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec, int64_t max_time_usec) {
149 DVLOG(3) << __FUNCTION__ << ": " << time_usec << ", " << max_time_usec; 181 DVLOG(3) << __FUNCTION__ << ": " << time_usec << ", " << max_time_usec;
150 DCHECK(task_runner_->BelongsToCurrentThread()); 182 DCHECK(task_runner_->BelongsToCurrentThread());
151 183
152 base::AutoLock auto_lock(lock_); 184 base::AutoLock auto_lock(lock_);
153 time_ = base::TimeDelta::FromMicroseconds(time_usec); 185 time_ = base::TimeDelta::FromMicroseconds(time_usec);
154 } 186 }
155 187
156 void MojoRendererImpl::OnBufferingStateChange(mojom::BufferingState state) { 188 void MojoRendererImpl::OnBufferingStateChange(mojom::BufferingState state) {
157 DVLOG(2) << __FUNCTION__; 189 DVLOG(2) << __FUNCTION__;
158 DCHECK(task_runner_->BelongsToCurrentThread()); 190 DCHECK(task_runner_->BelongsToCurrentThread());
159 client_->OnBufferingStateChange(static_cast<media::BufferingState>(state)); 191 client_->OnBufferingStateChange(static_cast<media::BufferingState>(state));
160 } 192 }
161 193
162 void MojoRendererImpl::OnEnded() { 194 void MojoRendererImpl::OnEnded() {
163 DVLOG(1) << __FUNCTION__; 195 DVLOG(1) << __FUNCTION__;
164 DCHECK(task_runner_->BelongsToCurrentThread()); 196 DCHECK(task_runner_->BelongsToCurrentThread());
165 client_->OnEnded(); 197 client_->OnEnded();
166 } 198 }
167 199
168 void MojoRendererImpl::OnError() { 200 void MojoRendererImpl::OnError() {
169 DVLOG(1) << __FUNCTION__; 201 DVLOG(1) << __FUNCTION__;
170 DCHECK(task_runner_->BelongsToCurrentThread()); 202 DCHECK(task_runner_->BelongsToCurrentThread());
171 DCHECK(init_cb_.is_null()); 203 DCHECK(init_cb_.is_null());
172 204
205 encountered_error_ = true;
206
173 // TODO(tim): Should we plumb error code from remote renderer? 207 // TODO(tim): Should we plumb error code from remote renderer?
174 // http://crbug.com/410451. 208 // http://crbug.com/410451.
175 client_->OnError(PIPELINE_ERROR_DECODE); 209 client_->OnError(PIPELINE_ERROR_DECODE);
176 } 210 }
177 211
178 void MojoRendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { 212 void MojoRendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
179 DVLOG(2) << __FUNCTION__ << ": " << size.ToString(); 213 DVLOG(2) << __FUNCTION__ << ": " << size.ToString();
180 DCHECK(task_runner_->BelongsToCurrentThread()); 214 DCHECK(task_runner_->BelongsToCurrentThread());
181 215
182 video_renderer_sink_->PaintSingleFrame( 216 video_renderer_sink_->PaintSingleFrame(
183 video_overlay_factory_->CreateFrame(size)); 217 video_overlay_factory_->CreateFrame(size));
184 client_->OnVideoNaturalSizeChange(size); 218 client_->OnVideoNaturalSizeChange(size);
185 } 219 }
186 220
187 void MojoRendererImpl::OnVideoOpacityChange(bool opaque) { 221 void MojoRendererImpl::OnVideoOpacityChange(bool opaque) {
188 DVLOG(2) << __FUNCTION__ << ": " << opaque; 222 DVLOG(2) << __FUNCTION__ << ": " << opaque;
189 DCHECK(task_runner_->BelongsToCurrentThread()); 223 DCHECK(task_runner_->BelongsToCurrentThread());
190 client_->OnVideoOpacityChange(opaque); 224 client_->OnVideoOpacityChange(opaque);
191 } 225 }
192 226
193 void MojoRendererImpl::OnConnectionError() { 227 void MojoRendererImpl::OnConnectionError() {
194 DVLOG(1) << __FUNCTION__; 228 DVLOG(1) << __FUNCTION__;
195 DCHECK(task_runner_->BelongsToCurrentThread()); 229 DCHECK(task_runner_->BelongsToCurrentThread());
196 230
197 if (!init_cb_.is_null()) { 231 encountered_error_ = true;
198 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); 232 FireAllPendingCallbacks();
199 return;
200 }
201 233
202 client_->OnError(PIPELINE_ERROR_DECODE); 234 if (client_)
235 client_->OnError(PIPELINE_ERROR_DECODE);
203 } 236 }
204 237
205 void MojoRendererImpl::BindRemoteRendererIfNeeded() { 238 void MojoRendererImpl::BindRemoteRendererIfNeeded() {
206 DVLOG(2) << __FUNCTION__; 239 DVLOG(2) << __FUNCTION__;
207 DCHECK(task_runner_->BelongsToCurrentThread()); 240 DCHECK(task_runner_->BelongsToCurrentThread());
208 241
209 // If |remote_renderer_| has already been bound, do nothing. 242 // If |remote_renderer_| has already been bound, do nothing.
243 // Note that after Bind() is called, |remote_renderer_| is always bound even
244 // after connection error.
210 if (remote_renderer_.is_bound()) 245 if (remote_renderer_.is_bound())
211 return; 246 return;
212 247
213 // Bind |remote_renderer_| to the |task_runner_|. 248 // Bind |remote_renderer_| to the |task_runner_|.
214 remote_renderer_.Bind(std::move(remote_renderer_info_)); 249 remote_renderer_.Bind(std::move(remote_renderer_info_));
215 250
216 // Otherwise, set an error handler to catch the connection error. 251 // Otherwise, set an error handler to catch the connection error.
217 // Using base::Unretained(this) is safe because |this| owns 252 // Using base::Unretained(this) is safe because |this| owns
218 // |remote_renderer_|, and the error handler can't be invoked once 253 // |remote_renderer_|, and the error handler can't be invoked once
219 // |remote_renderer_| is destroyed. 254 // |remote_renderer_| is destroyed.
220 remote_renderer_.set_connection_error_handler( 255 remote_renderer_.set_connection_error_handler(
221 base::Bind(&MojoRendererImpl::OnConnectionError, base::Unretained(this))); 256 base::Bind(&MojoRendererImpl::OnConnectionError, base::Unretained(this)));
222 } 257 }
223 258
224 void MojoRendererImpl::OnInitialized(bool success) { 259 void MojoRendererImpl::OnInitialized(media::RendererClient* client,
260 bool success) {
225 DVLOG(1) << __FUNCTION__; 261 DVLOG(1) << __FUNCTION__;
226 DCHECK(task_runner_->BelongsToCurrentThread()); 262 DCHECK(task_runner_->BelongsToCurrentThread());
227 DCHECK(!init_cb_.is_null()); 263 DCHECK(!init_cb_.is_null());
228 264
265 // Only set |client_| after initialization succeeded. No client methods should
266 // be called before this.
267 if (success)
268 client_ = client;
269
229 base::ResetAndReturn(&init_cb_).Run( 270 base::ResetAndReturn(&init_cb_).Run(
230 success ? PIPELINE_OK : PIPELINE_ERROR_INITIALIZATION_FAILED); 271 success ? PIPELINE_OK : PIPELINE_ERROR_INITIALIZATION_FAILED);
231 } 272 }
232 273
274 void MojoRendererImpl::OnFlushed() {
275 DVLOG(1) << __FUNCTION__;
276 DCHECK(task_runner_->BelongsToCurrentThread());
277 DCHECK(!flush_cb_.is_null());
278
279 base::ResetAndReturn(&flush_cb_).Run();
280 }
281
282 void MojoRendererImpl::OnCdmAttached(bool success) {
283 DVLOG(1) << __FUNCTION__;
284 DCHECK(task_runner_->BelongsToCurrentThread());
285 DCHECK(!cdm_attached_cb_.is_null());
286
287 base::ResetAndReturn(&cdm_attached_cb_).Run(success);
288 }
289
290 void MojoRendererImpl::FireAllPendingCallbacks() {
sandersd (OOO until July 31) 2016/06/16 18:10:06 This name should probably indicate that the callba
xhwang 2016/06/17 06:59:00 Done.
291 DVLOG(1) << __FUNCTION__;
292 DCHECK(task_runner_->BelongsToCurrentThread());
293
294 if (!init_cb_.is_null())
295 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
296
297 if (!flush_cb_.is_null())
298 base::ResetAndReturn(&flush_cb_).Run();
299
300 if (!cdm_attached_cb_.is_null())
301 base::ResetAndReturn(&cdm_attached_cb_).Run(false);
302 }
303
233 } // namespace media 304 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698