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

Side by Side Diff: media/remoting/remote_renderer_impl.cc

Issue 2643253003: Media Remoting Clean-up: Less-redundant naming, style consistency, etc. (Closed)
Patch Set: Created 3 years, 11 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
(Empty)
1 // Copyright 2016 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 "media/remoting/remote_renderer_impl.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback_helpers.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/numerics/safe_math.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "base/time/time.h"
19 #include "media/base/bind_to_current_loop.h"
20 #include "media/base/demuxer_stream_provider.h"
21 #include "media/remoting/remote_demuxer_stream_adapter.h"
22 #include "media/remoting/remoting_renderer_controller.h"
23 #include "media/remoting/rpc/proto_enum_utils.h"
24 #include "media/remoting/rpc/proto_utils.h"
25
26 namespace {
27
28 // The moving time window to track the media time and statistics updates.
29 constexpr base::TimeDelta kTrackingWindow = base::TimeDelta::FromSeconds(3);
30
31 // The allowed delay for the remoting playback. When exceeds this limit, the
32 // user experience is likely poor and the controller is notified.
33 constexpr base::TimeDelta kMediaPlaybackDelayThreshold =
34 base::TimeDelta::FromMilliseconds(450);
35
36 // The allowed percentage of the number of video frames dropped vs. the number
37 // of the video frames decoded. When exceeds this limit, the user experience is
38 // likely poor and the controller is notified.
39 constexpr int kMaxNumVideoFramesDroppedPercentage = 3;
40
41 // The time period to allow receiver get stable after playback rate change or
42 // Flush().
43 constexpr base::TimeDelta kStabilizationPeriod =
44 base::TimeDelta::FromSeconds(2);
45
46 // The amount of time between polling the DemuxerStreamAdapters to measure their
47 // data flow rates for metrics.
48 constexpr base::TimeDelta kDataFlowPollPeriod =
49 base::TimeDelta::FromSeconds(10);
50
51 } // namespace
52
53 namespace media {
54
55 RemoteRendererImpl::RemoteRendererImpl(
56 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
57 const base::WeakPtr<RemotingRendererController>&
58 remoting_renderer_controller,
59 VideoRendererSink* video_renderer_sink)
60 : state_(STATE_UNINITIALIZED),
61 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
62 media_task_runner_(std::move(media_task_runner)),
63 demuxer_stream_provider_(nullptr),
64 client_(nullptr),
65 remoting_renderer_controller_(remoting_renderer_controller),
66 rpc_broker_(remoting_renderer_controller_->GetRpcBroker()),
67 rpc_handle_(rpc_broker_->GetUniqueHandle()),
68 remote_renderer_handle_(remoting::kInvalidHandle),
69 video_renderer_sink_(video_renderer_sink),
70 weak_factory_(this) {
71 VLOG(2) << __func__;
72 // The constructor is running on the main thread.
73 DCHECK(remoting_renderer_controller_);
74 remoting_renderer_controller_->SetShowInterstitialCallback(
75 base::Bind(&RemoteRendererImpl::RequestUpdateInterstitialOnMainThread,
76 media_task_runner_, weak_factory_.GetWeakPtr()));
77
78 const remoting::RpcBroker::ReceiveMessageCallback receive_callback =
79 base::Bind(&RemoteRendererImpl::OnMessageReceivedOnMainThread,
80 media_task_runner_, weak_factory_.GetWeakPtr());
81 rpc_broker_->RegisterMessageReceiverCallback(rpc_handle_, receive_callback);
82 }
83
84 RemoteRendererImpl::~RemoteRendererImpl() {
85 VLOG(2) << __func__;
86 DCHECK(media_task_runner_->BelongsToCurrentThread());
87
88 UpdateInterstitial(interstitial_background_, canvas_size_,
89 RemotingInterstitialType::BETWEEN_SESSIONS);
90
91 // Post task on main thread to unset the interstial callback.
92 main_task_runner_->PostTask(
93 FROM_HERE,
94 base::Bind(&RemotingRendererController::SetShowInterstitialCallback,
95 remoting_renderer_controller_,
96 RemotingRendererController::ShowInterstitialCallback()));
97
98 // Post task on main thread to unregister message receiver.
99 main_task_runner_->PostTask(
100 FROM_HERE,
101 base::Bind(&remoting::RpcBroker::UnregisterMessageReceiverCallback,
102 rpc_broker_, rpc_handle_));
103 }
104
105 void RemoteRendererImpl::Initialize(
106 DemuxerStreamProvider* demuxer_stream_provider,
107 media::RendererClient* client,
108 const PipelineStatusCB& init_cb) {
109 VLOG(2) << __func__;
110 DCHECK(media_task_runner_->BelongsToCurrentThread());
111 DCHECK(demuxer_stream_provider);
112 DCHECK(client);
113
114 if (state_ != STATE_UNINITIALIZED) {
115 media_task_runner_->PostTask(
116 FROM_HERE, base::Bind(init_cb, PIPELINE_ERROR_INVALID_STATE));
117 return;
118 }
119
120 demuxer_stream_provider_ = demuxer_stream_provider;
121 client_ = client;
122 init_workflow_done_callback_ = init_cb;
123
124 state_ = STATE_CREATE_PIPE;
125 // Create audio mojo data pipe handles if audio is available.
126 ::media::DemuxerStream* audio_demuxer_stream =
127 demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO);
128 std::unique_ptr<mojo::DataPipe> audio_data_pipe;
129 if (audio_demuxer_stream) {
130 audio_data_pipe = base::WrapUnique(remoting::CreateDataPipe());
131 }
132
133 // Create video mojo data pipe handles if video is available.
134 ::media::DemuxerStream* video_demuxer_stream =
135 demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO);
136 std::unique_ptr<mojo::DataPipe> video_data_pipe;
137 if (video_demuxer_stream) {
138 video_data_pipe = base::WrapUnique(remoting::CreateDataPipe());
139 }
140
141 // Establish remoting data pipe connection using main thread.
142 const RemotingSourceImpl::DataPipeStartCallback data_pipe_callback =
143 base::Bind(&RemoteRendererImpl::OnDataPipeCreatedOnMainThread,
144 media_task_runner_, weak_factory_.GetWeakPtr(), rpc_broker_);
145 main_task_runner_->PostTask(
146 FROM_HERE,
147 base::Bind(&RemotingRendererController::StartDataPipe,
148 remoting_renderer_controller_, base::Passed(&audio_data_pipe),
149 base::Passed(&video_data_pipe), data_pipe_callback));
150 }
151
152 void RemoteRendererImpl::SetCdm(CdmContext* cdm_context,
153 const CdmAttachedCB& cdm_attached_cb) {
154 VLOG(2) << __func__ << " cdm_id:" << cdm_context->GetCdmId();
155 DCHECK(media_task_runner_->BelongsToCurrentThread());
156
157 // TODO(erickung): add implementation once Remote CDM implementation is done.
158 // Right now it returns callback immediately.
159 if (!cdm_attached_cb.is_null()) {
160 cdm_attached_cb.Run(false);
161 }
162 }
163
164 void RemoteRendererImpl::Flush(const base::Closure& flush_cb) {
165 VLOG(2) << __func__;
166 DCHECK(media_task_runner_->BelongsToCurrentThread());
167 DCHECK(flush_cb_.is_null());
168
169 if (state_ != STATE_PLAYING) {
170 DCHECK_EQ(state_, STATE_ERROR);
171 // In the error state, this renderer will be shut down shortly. To prevent
172 // breaking the pipeline impl, just run the done callback (interface
173 // requirement).
174 media_task_runner_->PostTask(FROM_HERE, flush_cb);
175 return;
176 }
177
178 state_ = STATE_FLUSHING;
179 base::Optional<uint32_t> flush_audio_count;
180 if (audio_demuxer_stream_adapter_)
181 flush_audio_count = audio_demuxer_stream_adapter_->SignalFlush(true);
182 base::Optional<uint32_t> flush_video_count;
183 if (video_demuxer_stream_adapter_)
184 flush_video_count = video_demuxer_stream_adapter_->SignalFlush(true);
185 // Makes sure flush count is valid if stream is available or both audio and
186 // video agrees on the same flushing state.
187 if ((audio_demuxer_stream_adapter_ && !flush_audio_count.has_value()) ||
188 (video_demuxer_stream_adapter_ && !flush_video_count.has_value()) ||
189 (audio_demuxer_stream_adapter_ && video_demuxer_stream_adapter_ &&
190 flush_audio_count.has_value() != flush_video_count.has_value())) {
191 VLOG(1) << "Ignoring flush request while under flushing operation";
192 return;
193 }
194
195 flush_cb_ = flush_cb;
196
197 // Issues RPC_R_FLUSHUNTIL RPC message.
198 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
199 rpc->set_handle(remote_renderer_handle_);
200 rpc->set_proc(remoting::pb::RpcMessage::RPC_R_FLUSHUNTIL);
201 remoting::pb::RendererFlushUntil* message =
202 rpc->mutable_renderer_flushuntil_rpc();
203 if (flush_audio_count.has_value())
204 message->set_audio_count(*flush_audio_count);
205 if (flush_video_count.has_value())
206 message->set_video_count(*flush_video_count);
207 message->set_callback_handle(rpc_handle_);
208 VLOG(2) << __func__ << ": Sending RPC_R_FLUSHUNTIL to " << rpc->handle()
209 << " with audio_count=" << message->audio_count()
210 << ", video_count=" << message->video_count()
211 << ", callback_handle=" << message->callback_handle();
212 SendRpcToRemote(std::move(rpc));
213 }
214
215 void RemoteRendererImpl::StartPlayingFrom(base::TimeDelta time) {
216 VLOG(2) << __func__ << ": " << time.InMicroseconds();
217 DCHECK(media_task_runner_->BelongsToCurrentThread());
218
219 if (state_ != STATE_PLAYING) {
220 DCHECK_EQ(state_, STATE_ERROR);
221 return;
222 }
223
224 // Issues RPC_R_STARTPLAYINGFROM RPC message.
225 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
226 rpc->set_handle(remote_renderer_handle_);
227 rpc->set_proc(remoting::pb::RpcMessage::RPC_R_STARTPLAYINGFROM);
228 rpc->set_integer64_value(time.InMicroseconds());
229 VLOG(2) << __func__ << ": Sending RPC_R_STARTPLAYINGFROM to " << rpc->handle()
230 << " with time_usec=" << rpc->integer64_value();
231 SendRpcToRemote(std::move(rpc));
232
233 {
234 base::AutoLock auto_lock(time_lock_);
235 current_media_time_ = time;
236 }
237 ResetMeasurements();
238 }
239
240 void RemoteRendererImpl::SetPlaybackRate(double playback_rate) {
241 VLOG(2) << __func__ << ": " << playback_rate;
242 DCHECK(media_task_runner_->BelongsToCurrentThread());
243
244 if (state_ != STATE_FLUSHING && state_ != STATE_PLAYING) {
245 DCHECK_EQ(state_, STATE_ERROR);
246 return;
247 }
248
249 // Issues RPC_R_SETPLAYBACKRATE RPC message.
250 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
251 rpc->set_handle(remote_renderer_handle_);
252 rpc->set_proc(remoting::pb::RpcMessage::RPC_R_SETPLAYBACKRATE);
253 rpc->set_double_value(playback_rate);
254 VLOG(2) << __func__ << ": Sending RPC_R_SETPLAYBACKRATE to " << rpc->handle()
255 << " with rate=" << rpc->double_value();
256 SendRpcToRemote(std::move(rpc));
257 playback_rate_ = playback_rate;
258 ResetMeasurements();
259 }
260
261 void RemoteRendererImpl::SetVolume(float volume) {
262 VLOG(2) << __func__ << ": " << volume;
263 DCHECK(media_task_runner_->BelongsToCurrentThread());
264
265 if (state_ != STATE_FLUSHING && state_ != STATE_PLAYING) {
266 DCHECK_EQ(state_, STATE_ERROR);
267 return;
268 }
269
270 // Issues RPC_R_SETVOLUME RPC message.
271 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
272 rpc->set_handle(remote_renderer_handle_);
273 rpc->set_proc(remoting::pb::RpcMessage::RPC_R_SETVOLUME);
274 rpc->set_double_value(volume);
275 VLOG(2) << __func__ << ": Sending RPC_R_SETVOLUME to " << rpc->handle()
276 << " with volume=" << rpc->double_value();
277 SendRpcToRemote(std::move(rpc));
278 }
279
280 base::TimeDelta RemoteRendererImpl::GetMediaTime() {
281 // No BelongsToCurrentThread() checking because this can be called from other
282 // threads.
283 // TODO(erickung): Interpolate current media time using local system time.
284 // Current receiver is to update |current_media_time_| every 250ms. But it
285 // needs to lower the update frequency in order to reduce network usage. Hence
286 // the interpolation is needed after receiver implementation is changed.
287 base::AutoLock auto_lock(time_lock_);
288 return current_media_time_;
289 }
290
291 // static
292 void RemoteRendererImpl::OnDataPipeCreatedOnMainThread(
293 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
294 base::WeakPtr<RemoteRendererImpl> self,
295 base::WeakPtr<remoting::RpcBroker> rpc_broker,
296 mojom::RemotingDataStreamSenderPtrInfo audio,
297 mojom::RemotingDataStreamSenderPtrInfo video,
298 mojo::ScopedDataPipeProducerHandle audio_handle,
299 mojo::ScopedDataPipeProducerHandle video_handle) {
300 media_task_runner->PostTask(
301 FROM_HERE,
302 base::Bind(
303 &RemoteRendererImpl::OnDataPipeCreated, self, base::Passed(&audio),
304 base::Passed(&video), base::Passed(&audio_handle),
305 base::Passed(&video_handle),
306 rpc_broker ? rpc_broker->GetUniqueHandle() : remoting::kInvalidHandle,
307 rpc_broker ? rpc_broker->GetUniqueHandle()
308 : remoting::kInvalidHandle));
309 }
310
311 void RemoteRendererImpl::OnDataPipeCreated(
312 mojom::RemotingDataStreamSenderPtrInfo audio,
313 mojom::RemotingDataStreamSenderPtrInfo video,
314 mojo::ScopedDataPipeProducerHandle audio_handle,
315 mojo::ScopedDataPipeProducerHandle video_handle,
316 int audio_rpc_handle,
317 int video_rpc_handle) {
318 VLOG(2) << __func__;
319 DCHECK(media_task_runner_->BelongsToCurrentThread());
320 DCHECK(!init_workflow_done_callback_.is_null());
321
322 if (state_ == STATE_ERROR)
323 return; // Abort because something went wrong in the meantime.
324 DCHECK_EQ(state_, STATE_CREATE_PIPE);
325
326 // Create audio demuxer stream adapter if audio is available.
327 ::media::DemuxerStream* audio_demuxer_stream =
328 demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO);
329 if (audio_demuxer_stream && audio.is_valid() && audio_handle.is_valid() &&
330 audio_rpc_handle != remoting::kInvalidHandle) {
331 VLOG(2) << "Initialize audio";
332 audio_demuxer_stream_adapter_.reset(
333 new remoting::RemoteDemuxerStreamAdapter(
334 main_task_runner_, media_task_runner_, "audio",
335 audio_demuxer_stream, rpc_broker_, audio_rpc_handle,
336 std::move(audio), std::move(audio_handle),
337 base::Bind(&RemoteRendererImpl::OnFatalError,
338 base::Unretained(this))));
339 }
340
341 // Create video demuxer stream adapter if video is available.
342 ::media::DemuxerStream* video_demuxer_stream =
343 demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO);
344 if (video_demuxer_stream && video.is_valid() && video_handle.is_valid() &&
345 video_rpc_handle != remoting::kInvalidHandle) {
346 VLOG(2) << "Initialize video";
347 video_demuxer_stream_adapter_.reset(
348 new remoting::RemoteDemuxerStreamAdapter(
349 main_task_runner_, media_task_runner_, "video",
350 video_demuxer_stream, rpc_broker_, video_rpc_handle,
351 std::move(video), std::move(video_handle),
352 base::Bind(&RemoteRendererImpl::OnFatalError,
353 base::Unretained(this))));
354 }
355
356 // Checks if data pipe is created successfully.
357 if (!audio_demuxer_stream_adapter_ && !video_demuxer_stream_adapter_) {
358 OnFatalError(remoting::DATA_PIPE_CREATE_ERROR);
359 return;
360 }
361
362 state_ = STATE_ACQUIRING;
363 // Issues RPC_ACQUIRE_RENDERER RPC message.
364 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
365 rpc->set_handle(remoting::kReceiverHandle);
366 rpc->set_proc(remoting::pb::RpcMessage::RPC_ACQUIRE_RENDERER);
367 rpc->set_integer_value(rpc_handle_);
368 VLOG(2) << __func__ << ": Sending RPC_ACQUIRE_RENDERER to " << rpc->handle()
369 << " with rpc_handle=" << rpc->integer_value();
370 SendRpcToRemote(std::move(rpc));
371 }
372
373 // static
374 void RemoteRendererImpl::OnMessageReceivedOnMainThread(
375 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
376 base::WeakPtr<RemoteRendererImpl> self,
377 std::unique_ptr<remoting::pb::RpcMessage> message) {
378 media_task_runner->PostTask(
379 FROM_HERE, base::Bind(&RemoteRendererImpl::OnReceivedRpc, self,
380 base::Passed(&message)));
381 }
382
383 void RemoteRendererImpl::OnReceivedRpc(
384 std::unique_ptr<remoting::pb::RpcMessage> message) {
385 DCHECK(media_task_runner_->BelongsToCurrentThread());
386 DCHECK(message);
387 switch (message->proc()) {
388 case remoting::pb::RpcMessage::RPC_ACQUIRE_RENDERER_DONE:
389 AcquireRendererDone(std::move(message));
390 break;
391 case remoting::pb::RpcMessage::RPC_R_INITIALIZE_CALLBACK:
392 InitializeCallback(std::move(message));
393 break;
394 case remoting::pb::RpcMessage::RPC_R_FLUSHUNTIL_CALLBACK:
395 FlushUntilCallback();
396 break;
397 case remoting::pb::RpcMessage::RPC_R_SETCDM_CALLBACK:
398 SetCdmCallback(std::move(message));
399 break;
400 case remoting::pb::RpcMessage::RPC_RC_ONTIMEUPDATE:
401 OnTimeUpdate(std::move(message));
402 break;
403 case remoting::pb::RpcMessage::RPC_RC_ONBUFFERINGSTATECHANGE:
404 OnBufferingStateChange(std::move(message));
405 break;
406 case remoting::pb::RpcMessage::RPC_RC_ONENDED:
407 VLOG(2) << __func__ << ": Received RPC_RC_ONENDED.";
408 client_->OnEnded();
409 break;
410 case remoting::pb::RpcMessage::RPC_RC_ONERROR:
411 VLOG(2) << __func__ << ": Received RPC_RC_ONERROR.";
412 OnFatalError(remoting::RECEIVER_PIPELINE_ERROR);
413 break;
414 case remoting::pb::RpcMessage::RPC_RC_ONVIDEONATURALSIZECHANGE:
415 OnVideoNaturalSizeChange(std::move(message));
416 break;
417 case remoting::pb::RpcMessage::RPC_RC_ONVIDEOOPACITYCHANGE:
418 OnVideoOpacityChange(std::move(message));
419 break;
420 case remoting::pb::RpcMessage::RPC_RC_ONSTATISTICSUPDATE:
421 OnStatisticsUpdate(std::move(message));
422 break;
423 case remoting::pb::RpcMessage::RPC_RC_ONWAITINGFORDECRYPTIONKEY:
424 VLOG(2) << __func__ << ": Received RPC_RC_ONWAITINGFORDECRYPTIONKEY.";
425 client_->OnWaitingForDecryptionKey();
426 break;
427 case remoting::pb::RpcMessage::RPC_RC_ONDURATIONCHANGE:
428 OnDurationChange(std::move(message));
429 break;
430
431 default:
432 LOG(ERROR) << "Unknown rpc: " << message->proc();
433 }
434 }
435
436 void RemoteRendererImpl::SendRpcToRemote(
437 std::unique_ptr<remoting::pb::RpcMessage> message) {
438 DCHECK(media_task_runner_->BelongsToCurrentThread());
439 DCHECK(main_task_runner_);
440 main_task_runner_->PostTask(
441 FROM_HERE, base::Bind(&remoting::RpcBroker::SendMessageToRemote,
442 rpc_broker_, base::Passed(&message)));
443 }
444
445 void RemoteRendererImpl::AcquireRendererDone(
446 std::unique_ptr<remoting::pb::RpcMessage> message) {
447 DCHECK(media_task_runner_->BelongsToCurrentThread());
448 DCHECK(message);
449
450 remote_renderer_handle_ = message->integer_value();
451 VLOG(2) << __func__
452 << ": Received RPC_ACQUIRE_RENDERER_DONE with remote_renderer_handle="
453 << remote_renderer_handle_;
454
455 if (state_ != STATE_ACQUIRING || init_workflow_done_callback_.is_null()) {
456 LOG(WARNING) << "Unexpected acquire renderer done RPC.";
457 OnFatalError(remoting::PEERS_OUT_OF_SYNC);
458 return;
459 }
460 state_ = STATE_INITIALIZING;
461
462 // Issues RPC_R_INITIALIZE RPC message to initialize renderer.
463 std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage());
464 rpc->set_handle(remote_renderer_handle_);
465 rpc->set_proc(remoting::pb::RpcMessage::RPC_R_INITIALIZE);
466 remoting::pb::RendererInitialize* init =
467 rpc->mutable_renderer_initialize_rpc();
468 init->set_client_handle(rpc_handle_);
469 init->set_audio_demuxer_handle(
470 audio_demuxer_stream_adapter_
471 ? audio_demuxer_stream_adapter_->rpc_handle()
472 : remoting::kInvalidHandle);
473 init->set_video_demuxer_handle(
474 video_demuxer_stream_adapter_
475 ? video_demuxer_stream_adapter_->rpc_handle()
476 : remoting::kInvalidHandle);
477 init->set_callback_handle(rpc_handle_);
478 VLOG(2) << __func__ << ": Sending RPC_R_INITIALIZE to " << rpc->handle()
479 << " with client_handle=" << init->client_handle()
480 << ", audio_demuxer_handle=" << init->audio_demuxer_handle()
481 << ", video_demuxer_handle=" << init->video_demuxer_handle()
482 << ", callback_handle=" << init->callback_handle();
483 SendRpcToRemote(std::move(rpc));
484 }
485
486 void RemoteRendererImpl::InitializeCallback(
487 std::unique_ptr<remoting::pb::RpcMessage> message) {
488 DCHECK(media_task_runner_->BelongsToCurrentThread());
489 DCHECK(message);
490
491 const bool success = message->boolean_value();
492 VLOG(2) << __func__
493 << ": Received RPC_R_INITIALIZE_CALLBACK with success=" << success;
494
495 if (state_ != STATE_INITIALIZING || init_workflow_done_callback_.is_null()) {
496 LOG(WARNING) << "Unexpected initialize callback RPC.";
497 OnFatalError(remoting::PEERS_OUT_OF_SYNC);
498 return;
499 }
500
501 if (!success) {
502 OnFatalError(remoting::RECEIVER_INITIALIZE_FAILED);
503 return;
504 }
505
506 metrics_recorder_.OnRendererInitialized();
507
508 state_ = STATE_PLAYING;
509 base::ResetAndReturn(&init_workflow_done_callback_).Run(::media::PIPELINE_OK);
510 }
511
512 void RemoteRendererImpl::FlushUntilCallback() {
513 DCHECK(media_task_runner_->BelongsToCurrentThread());
514 VLOG(2) << __func__ << ": Received RPC_R_FLUSHUNTIL_CALLBACK";
515
516 if (state_ != STATE_FLUSHING || flush_cb_.is_null()) {
517 LOG(WARNING) << "Unexpected flushuntil callback RPC.";
518 OnFatalError(remoting::PEERS_OUT_OF_SYNC);
519 return;
520 }
521
522 state_ = STATE_PLAYING;
523 if (audio_demuxer_stream_adapter_)
524 audio_demuxer_stream_adapter_->SignalFlush(false);
525 if (video_demuxer_stream_adapter_)
526 video_demuxer_stream_adapter_->SignalFlush(false);
527 base::ResetAndReturn(&flush_cb_).Run();
528 ResetMeasurements();
529 }
530
531 void RemoteRendererImpl::SetCdmCallback(
532 std::unique_ptr<remoting::pb::RpcMessage> message) {
533 DCHECK(media_task_runner_->BelongsToCurrentThread());
534 DCHECK(message);
535 VLOG(2) << __func__ << ": Received RPC_R_SETCDM_CALLBACK with cdm_id="
536 << message->renderer_set_cdm_rpc().cdm_id() << ", callback_handle="
537 << message->renderer_set_cdm_rpc().callback_handle();
538 // TODO(erickung): add implementation once Remote CDM implementation is done.
539 NOTIMPLEMENTED();
540 }
541
542 void RemoteRendererImpl::OnTimeUpdate(
543 std::unique_ptr<remoting::pb::RpcMessage> message) {
544 DCHECK(media_task_runner_->BelongsToCurrentThread());
545 DCHECK(message);
546 // Shutdown remoting session if receiving malformed RPC message.
547 if (!message->has_rendererclient_ontimeupdate_rpc()) {
548 VLOG(1) << __func__ << " missing required RPC message";
549 OnFatalError(remoting::RPC_INVALID);
550 return;
551 }
552 const int64_t time_usec =
553 message->rendererclient_ontimeupdate_rpc().time_usec();
554 const int64_t max_time_usec =
555 message->rendererclient_ontimeupdate_rpc().max_time_usec();
556 VLOG(2) << __func__
557 << ": Received RPC_RC_ONTIMEUPDATE with time_usec=" << time_usec
558 << ", max_time_usec=" << max_time_usec;
559 // Ignores invalid time, such as negative value, or time larger than max value
560 // (usually the time stamp that all streams are pushed into AV pipeline).
561 if (time_usec < 0 || max_time_usec < 0 || time_usec > max_time_usec)
562 return;
563
564 {
565 // Updates current time information.
566 base::AutoLock auto_lock(time_lock_);
567 current_media_time_ = base::TimeDelta::FromMicroseconds(time_usec);
568 current_max_time_ = base::TimeDelta::FromMicroseconds(max_time_usec);
569 }
570
571 metrics_recorder_.OnEvidenceOfPlayoutAtReceiver();
572 OnMediaTimeUpdated();
573 }
574
575 void RemoteRendererImpl::OnBufferingStateChange(
576 std::unique_ptr<remoting::pb::RpcMessage> message) {
577 DCHECK(media_task_runner_->BelongsToCurrentThread());
578 DCHECK(message);
579 if (!message->has_rendererclient_onbufferingstatechange_rpc()) {
580 VLOG(1) << __func__ << " missing required RPC message";
581 OnFatalError(remoting::RPC_INVALID);
582 return;
583 }
584 VLOG(2) << __func__ << ": Received RPC_RC_ONBUFFERINGSTATECHANGE with state="
585 << message->rendererclient_onbufferingstatechange_rpc().state();
586 base::Optional<::media::BufferingState> state =
587 remoting::ToMediaBufferingState(
588 message->rendererclient_onbufferingstatechange_rpc().state());
589 if (!state.has_value())
590 return;
591 client_->OnBufferingStateChange(state.value());
592 }
593
594 void RemoteRendererImpl::OnVideoNaturalSizeChange(
595 std::unique_ptr<remoting::pb::RpcMessage> message) {
596 DCHECK(media_task_runner_->BelongsToCurrentThread());
597 DCHECK(message);
598 // Shutdown remoting session if receiving malformed RPC message.
599 if (!message->has_rendererclient_onvideonatualsizechange_rpc()) {
600 VLOG(1) << __func__ << " missing required RPC message";
601 OnFatalError(remoting::RPC_INVALID);
602 return;
603 }
604 const auto& size_change =
605 message->rendererclient_onvideonatualsizechange_rpc();
606 VLOG(2) << __func__ << ": Received RPC_RC_ONVIDEONATURALSIZECHANGE with size="
607 << size_change.width() << 'x' << size_change.height();
608 if (size_change.width() <= 0 || size_change.height() <= 0)
609 return;
610 client_->OnVideoNaturalSizeChange(
611 gfx::Size(size_change.width(), size_change.height()));
612 }
613
614 void RemoteRendererImpl::OnVideoOpacityChange(
615 std::unique_ptr<remoting::pb::RpcMessage> message) {
616 DCHECK(media_task_runner_->BelongsToCurrentThread());
617 DCHECK(message);
618 const bool opaque = message->boolean_value();
619 VLOG(2) << __func__
620 << ": Received RPC_RC_ONVIDEOOPACITYCHANGE with opaque=" << opaque;
621 client_->OnVideoOpacityChange(opaque);
622 }
623
624 void RemoteRendererImpl::OnStatisticsUpdate(
625 std::unique_ptr<remoting::pb::RpcMessage> message) {
626 DCHECK(media_task_runner_->BelongsToCurrentThread());
627 DCHECK(message);
628 // Shutdown remoting session if receiving malformed RPC message.
629 if (!message->has_rendererclient_onstatisticsupdate_rpc()) {
630 VLOG(1) << __func__ << " missing required RPC message";
631 OnFatalError(remoting::RPC_INVALID);
632 return;
633 }
634 const auto& rpc_message = message->rendererclient_onstatisticsupdate_rpc();
635 ::media::PipelineStatistics stats;
636 // Note: Each |stats| value is a delta, not the aggregate amount.
637 stats.audio_bytes_decoded = rpc_message.audio_bytes_decoded();
638 stats.video_bytes_decoded = rpc_message.video_bytes_decoded();
639 stats.video_frames_decoded = rpc_message.video_frames_decoded();
640 stats.video_frames_dropped = rpc_message.video_frames_dropped();
641 stats.audio_memory_usage = rpc_message.audio_memory_usage();
642 stats.video_memory_usage = rpc_message.video_memory_usage();
643 VLOG(2) << __func__
644 << ": Received RPC_RC_ONSTATISTICSUPDATE with audio_bytes_decoded="
645 << stats.audio_bytes_decoded
646 << ", video_bytes_decoded=" << stats.video_bytes_decoded
647 << ", video_frames_decoded=" << stats.video_frames_decoded
648 << ", video_frames_dropped=" << stats.video_frames_dropped
649 << ", audio_memory_usage=" << stats.audio_memory_usage
650 << ", video_memory_usage=" << stats.video_memory_usage;
651
652 if (stats.audio_bytes_decoded > 0 || stats.video_frames_decoded > 0 ||
653 stats.video_frames_dropped > 0) {
654 metrics_recorder_.OnEvidenceOfPlayoutAtReceiver();
655 }
656 UpdateVideoStatsQueue(stats.video_frames_decoded, stats.video_frames_dropped);
657 client_->OnStatisticsUpdate(stats);
658 }
659
660 void RemoteRendererImpl::OnDurationChange(
661 std::unique_ptr<remoting::pb::RpcMessage> message) {
662 DCHECK(media_task_runner_->BelongsToCurrentThread());
663 DCHECK(message);
664 VLOG(2) << __func__ << ": Received RPC_RC_ONDURATIONCHANGE with usec="
665 << message->integer64_value();
666 if (message->integer64_value() < 0)
667 return;
668 client_->OnDurationChange(
669 base::TimeDelta::FromMicroseconds(message->integer64_value()));
670 }
671
672 void RemoteRendererImpl::OnFatalError(remoting::StopTrigger stop_trigger) {
673 DCHECK(media_task_runner_->BelongsToCurrentThread());
674 DCHECK_NE(remoting::UNKNOWN_STOP_TRIGGER, stop_trigger);
675
676 VLOG(2) << __func__ << " with StopTrigger " << stop_trigger;
677
678 // If this is the first error, notify the controller. It is expected the
679 // controller will shut down this renderer shortly.
680 if (state_ != STATE_ERROR) {
681 state_ = STATE_ERROR;
682 main_task_runner_->PostTask(
683 FROM_HERE, base::Bind(&RemotingRendererController::OnRendererFatalError,
684 remoting_renderer_controller_, stop_trigger));
685 }
686
687 data_flow_poll_timer_.Stop();
688
689 if (!init_workflow_done_callback_.is_null()) {
690 base::ResetAndReturn(&init_workflow_done_callback_)
691 .Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
692 return;
693 }
694
695 if (!flush_cb_.is_null())
696 base::ResetAndReturn(&flush_cb_).Run();
697 }
698
699 // static
700 void RemoteRendererImpl::RequestUpdateInterstitialOnMainThread(
701 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
702 base::WeakPtr<RemoteRendererImpl> remote_renderer_impl,
703 const base::Optional<SkBitmap>& background_image,
704 const gfx::Size& canvas_size,
705 RemotingInterstitialType interstitial_type) {
706 media_task_runner->PostTask(
707 FROM_HERE,
708 base::Bind(&RemoteRendererImpl::UpdateInterstitial, remote_renderer_impl,
709 background_image, canvas_size, interstitial_type));
710 }
711
712 void RemoteRendererImpl::UpdateInterstitial(
713 const base::Optional<SkBitmap>& background_image,
714 const gfx::Size& canvas_size,
715 RemotingInterstitialType interstitial_type) {
716 DCHECK(media_task_runner_->BelongsToCurrentThread());
717 if (background_image.has_value())
718 interstitial_background_ = background_image.value();
719 canvas_size_ = canvas_size;
720 PaintRemotingInterstitial(interstitial_background_, canvas_size_,
721 interstitial_type, video_renderer_sink_);
722 }
723
724 void RemoteRendererImpl::OnMediaTimeUpdated() {
725 DCHECK(media_task_runner_->BelongsToCurrentThread());
726 if (!flush_cb_.is_null())
727 return; // Don't manage and check the queue when Flush() is on-going.
728
729 base::TimeTicks current_time = base::TimeTicks::Now();
730 if (current_time < ignore_updates_until_time_)
731 return; // Not stable yet.
732
733 media_time_queue_.push_back(
734 std::make_pair(current_time, current_media_time_));
735 base::TimeDelta window_duration =
736 current_time - media_time_queue_.front().first;
737 if (window_duration < kTrackingWindow)
738 return; // Not enough data to make a reliable decision.
739
740 base::TimeDelta media_duration =
741 media_time_queue_.back().second - media_time_queue_.front().second;
742 base::TimeDelta update_duration =
743 (media_time_queue_.back().first - media_time_queue_.front().first) *
744 playback_rate_;
745 if ((media_duration - update_duration).magnitude() >=
746 kMediaPlaybackDelayThreshold) {
747 VLOG(1) << "Irregular playback detected: Media playback delayed."
748 << " media_duration = " << media_duration
749 << " update_duration = " << update_duration;
750 OnFatalError(remoting::PACING_TOO_SLOWLY);
751 }
752 // Prune |media_time_queue_|.
753 while (media_time_queue_.back().first - media_time_queue_.front().first >=
754 kTrackingWindow)
755 media_time_queue_.pop_front();
756 }
757
758 void RemoteRendererImpl::UpdateVideoStatsQueue(int video_frames_decoded,
759 int video_frames_dropped) {
760 DCHECK(media_task_runner_->BelongsToCurrentThread());
761 if (!flush_cb_.is_null())
762 return; // Don't manage and check the queue when Flush() is on-going.
763
764 if (!stats_updated_) {
765 if (video_frames_decoded)
766 stats_updated_ = true;
767 // Ignore the first stats since it may include the information during
768 // unstable period.
769 return;
770 }
771
772 base::TimeTicks current_time = base::TimeTicks::Now();
773 if (current_time < ignore_updates_until_time_)
774 return; // Not stable yet.
775
776 video_stats_queue_.push_back(std::make_tuple(
777 current_time, video_frames_decoded, video_frames_dropped));
778 sum_video_frames_decoded_ += video_frames_decoded;
779 sum_video_frames_dropped_ += video_frames_dropped;
780 base::TimeDelta window_duration =
781 current_time - std::get<0>(video_stats_queue_.front());
782 if (window_duration < kTrackingWindow)
783 return; // Not enough data to make a reliable decision.
784
785 if (sum_video_frames_decoded_ &&
786 sum_video_frames_dropped_ * 100 >
787 sum_video_frames_decoded_ * kMaxNumVideoFramesDroppedPercentage) {
788 VLOG(1) << "Irregular playback detected: Too many video frames dropped."
789 << " video_frames_decoded= " << sum_video_frames_decoded_
790 << " video_frames_dropped= " << sum_video_frames_dropped_;
791 OnFatalError(remoting::FRAME_DROP_RATE_HIGH);
792 }
793 // Prune |video_stats_queue_|.
794 while (std::get<0>(video_stats_queue_.back()) -
795 std::get<0>(video_stats_queue_.front()) >=
796 kTrackingWindow) {
797 sum_video_frames_decoded_ -= std::get<1>(video_stats_queue_.front());
798 sum_video_frames_dropped_ -= std::get<2>(video_stats_queue_.front());
799 video_stats_queue_.pop_front();
800 }
801 }
802
803 void RemoteRendererImpl::ResetMeasurements() {
804 DCHECK(media_task_runner_->BelongsToCurrentThread());
805 media_time_queue_.clear();
806 video_stats_queue_.clear();
807 sum_video_frames_dropped_ = 0;
808 sum_video_frames_decoded_ = 0;
809 stats_updated_ = false;
810 ignore_updates_until_time_ = base::TimeTicks::Now() + kStabilizationPeriod;
811
812 if (state_ != STATE_ERROR &&
813 (audio_demuxer_stream_adapter_ || video_demuxer_stream_adapter_)) {
814 data_flow_poll_timer_.Start(FROM_HERE, kDataFlowPollPeriod, this,
815 &RemoteRendererImpl::MeasureAndRecordDataRates);
816 }
817 }
818
819 void RemoteRendererImpl::MeasureAndRecordDataRates() {
820 DCHECK(media_task_runner_->BelongsToCurrentThread());
821
822 // Whenever media is first started or flushed/seeked, there is a "burst
823 // bufferring" period as the remote device rapidly fills its buffer before
824 // resuming playback. Since the goal here is to measure the sustained content
825 // bitrates, ignore the byte counts the first time since the last
826 // ResetMeasurements() call.
827 const base::TimeTicks current_time = base::TimeTicks::Now();
828 if (current_time < ignore_updates_until_time_ + kDataFlowPollPeriod) {
829 if (audio_demuxer_stream_adapter_)
830 audio_demuxer_stream_adapter_->GetBytesWrittenAndReset();
831 if (video_demuxer_stream_adapter_)
832 video_demuxer_stream_adapter_->GetBytesWrittenAndReset();
833 return;
834 }
835
836 const int kBytesPerKilobit = 1024 / 8;
837 if (audio_demuxer_stream_adapter_) {
838 const double kilobits_per_second =
839 (audio_demuxer_stream_adapter_->GetBytesWrittenAndReset() /
840 kDataFlowPollPeriod.InSecondsF()) /
841 kBytesPerKilobit;
842 DCHECK_GE(kilobits_per_second, 0);
843 const base::CheckedNumeric<int> checked_kbps = kilobits_per_second;
844 metrics_recorder_.OnAudioRateEstimate(
845 checked_kbps.ValueOrDefault(std::numeric_limits<int>::max()));
846 }
847 if (video_demuxer_stream_adapter_) {
848 const double kilobits_per_second =
849 (video_demuxer_stream_adapter_->GetBytesWrittenAndReset() /
850 kDataFlowPollPeriod.InSecondsF()) /
851 kBytesPerKilobit;
852 DCHECK_GE(kilobits_per_second, 0);
853 const base::CheckedNumeric<int> checked_kbps = kilobits_per_second;
854 metrics_recorder_.OnVideoRateEstimate(
855 checked_kbps.ValueOrDefault(std::numeric_limits<int>::max()));
856 }
857 }
858
859 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698