Index: media/remoting/remote_renderer_impl.cc |
diff --git a/media/remoting/remote_renderer_impl.cc b/media/remoting/remote_renderer_impl.cc |
deleted file mode 100644 |
index f90ed1858ebad0b4b0b17b322a8648b9ad77ca95..0000000000000000000000000000000000000000 |
--- a/media/remoting/remote_renderer_impl.cc |
+++ /dev/null |
@@ -1,866 +0,0 @@ |
-// Copyright 2016 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "media/remoting/remote_renderer_impl.h" |
- |
-#include <algorithm> |
-#include <limits> |
-#include <utility> |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/callback_helpers.h" |
-#include "base/memory/ptr_util.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/numerics/safe_math.h" |
-#include "base/threading/thread_task_runner_handle.h" |
-#include "base/time/time.h" |
-#include "media/base/bind_to_current_loop.h" |
-#include "media/base/demuxer_stream_provider.h" |
-#include "media/remoting/remote_demuxer_stream_adapter.h" |
-#include "media/remoting/remoting_renderer_controller.h" |
-#include "media/remoting/rpc/proto_enum_utils.h" |
-#include "media/remoting/rpc/proto_utils.h" |
- |
-namespace { |
- |
-// The moving time window to track the media time and statistics updates. |
-constexpr base::TimeDelta kTrackingWindow = base::TimeDelta::FromSeconds(5); |
- |
-// The allowed delay for the remoting playback. When continuously exceeds this |
-// limit for |kPlaybackDelayCountThreshold| times, the user experience is likely |
-// poor and the controller is notified. |
-constexpr base::TimeDelta kMediaPlaybackDelayThreshold = |
- base::TimeDelta::FromMilliseconds(750); |
-constexpr int kPlaybackDelayCountThreshold = 3; |
- |
-// The allowed percentage of the number of video frames dropped vs. the number |
-// of the video frames decoded. When exceeds this limit, the user experience is |
-// likely poor and the controller is notified. |
-constexpr int kMaxNumVideoFramesDroppedPercentage = 3; |
- |
-// The time period to allow receiver get stable after playback rate change or |
-// Flush(). |
-constexpr base::TimeDelta kStabilizationPeriod = |
- base::TimeDelta::FromSeconds(2); |
- |
-// The amount of time between polling the DemuxerStreamAdapters to measure their |
-// data flow rates for metrics. |
-constexpr base::TimeDelta kDataFlowPollPeriod = |
- base::TimeDelta::FromSeconds(10); |
- |
-} // namespace |
- |
-namespace media { |
- |
-RemoteRendererImpl::RemoteRendererImpl( |
- scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, |
- const base::WeakPtr<RemotingRendererController>& |
- remoting_renderer_controller, |
- VideoRendererSink* video_renderer_sink) |
- : state_(STATE_UNINITIALIZED), |
- main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
- media_task_runner_(std::move(media_task_runner)), |
- demuxer_stream_provider_(nullptr), |
- client_(nullptr), |
- remoting_renderer_controller_(remoting_renderer_controller), |
- rpc_broker_(remoting_renderer_controller_->GetRpcBroker()), |
- rpc_handle_(rpc_broker_->GetUniqueHandle()), |
- remote_renderer_handle_(remoting::kInvalidHandle), |
- video_renderer_sink_(video_renderer_sink), |
- weak_factory_(this) { |
- VLOG(2) << __func__; |
- // The constructor is running on the main thread. |
- DCHECK(remoting_renderer_controller_); |
- remoting_renderer_controller_->SetShowInterstitialCallback( |
- base::Bind(&RemoteRendererImpl::RequestUpdateInterstitialOnMainThread, |
- media_task_runner_, weak_factory_.GetWeakPtr())); |
- |
- const remoting::RpcBroker::ReceiveMessageCallback receive_callback = |
- base::Bind(&RemoteRendererImpl::OnMessageReceivedOnMainThread, |
- media_task_runner_, weak_factory_.GetWeakPtr()); |
- rpc_broker_->RegisterMessageReceiverCallback(rpc_handle_, receive_callback); |
-} |
- |
-RemoteRendererImpl::~RemoteRendererImpl() { |
- VLOG(2) << __func__; |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- |
- UpdateInterstitial(interstitial_background_, canvas_size_, |
- RemotingInterstitialType::BETWEEN_SESSIONS); |
- |
- // Post task on main thread to unset the interstial callback. |
- main_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&RemotingRendererController::SetShowInterstitialCallback, |
- remoting_renderer_controller_, |
- RemotingRendererController::ShowInterstitialCallback())); |
- |
- // Post task on main thread to unregister message receiver. |
- main_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&remoting::RpcBroker::UnregisterMessageReceiverCallback, |
- rpc_broker_, rpc_handle_)); |
-} |
- |
-void RemoteRendererImpl::Initialize( |
- DemuxerStreamProvider* demuxer_stream_provider, |
- media::RendererClient* client, |
- const PipelineStatusCB& init_cb) { |
- VLOG(2) << __func__; |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(demuxer_stream_provider); |
- DCHECK(client); |
- |
- if (state_ != STATE_UNINITIALIZED) { |
- media_task_runner_->PostTask( |
- FROM_HERE, base::Bind(init_cb, PIPELINE_ERROR_INVALID_STATE)); |
- return; |
- } |
- |
- demuxer_stream_provider_ = demuxer_stream_provider; |
- client_ = client; |
- init_workflow_done_callback_ = init_cb; |
- |
- state_ = STATE_CREATE_PIPE; |
- // Create audio mojo data pipe handles if audio is available. |
- ::media::DemuxerStream* audio_demuxer_stream = |
- demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO); |
- std::unique_ptr<mojo::DataPipe> audio_data_pipe; |
- if (audio_demuxer_stream) { |
- audio_data_pipe = base::WrapUnique(remoting::CreateDataPipe()); |
- } |
- |
- // Create video mojo data pipe handles if video is available. |
- ::media::DemuxerStream* video_demuxer_stream = |
- demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO); |
- std::unique_ptr<mojo::DataPipe> video_data_pipe; |
- if (video_demuxer_stream) { |
- video_data_pipe = base::WrapUnique(remoting::CreateDataPipe()); |
- } |
- |
- // Establish remoting data pipe connection using main thread. |
- const RemotingSourceImpl::DataPipeStartCallback data_pipe_callback = |
- base::Bind(&RemoteRendererImpl::OnDataPipeCreatedOnMainThread, |
- media_task_runner_, weak_factory_.GetWeakPtr(), rpc_broker_); |
- main_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&RemotingRendererController::StartDataPipe, |
- remoting_renderer_controller_, base::Passed(&audio_data_pipe), |
- base::Passed(&video_data_pipe), data_pipe_callback)); |
-} |
- |
-void RemoteRendererImpl::SetCdm(CdmContext* cdm_context, |
- const CdmAttachedCB& cdm_attached_cb) { |
- VLOG(2) << __func__ << " cdm_id:" << cdm_context->GetCdmId(); |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- |
- // TODO(erickung): add implementation once Remote CDM implementation is done. |
- // Right now it returns callback immediately. |
- if (!cdm_attached_cb.is_null()) { |
- cdm_attached_cb.Run(false); |
- } |
-} |
- |
-void RemoteRendererImpl::Flush(const base::Closure& flush_cb) { |
- VLOG(2) << __func__; |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(flush_cb_.is_null()); |
- |
- if (state_ != STATE_PLAYING) { |
- DCHECK_EQ(state_, STATE_ERROR); |
- // In the error state, this renderer will be shut down shortly. To prevent |
- // breaking the pipeline impl, just run the done callback (interface |
- // requirement). |
- media_task_runner_->PostTask(FROM_HERE, flush_cb); |
- return; |
- } |
- |
- state_ = STATE_FLUSHING; |
- base::Optional<uint32_t> flush_audio_count; |
- if (audio_demuxer_stream_adapter_) |
- flush_audio_count = audio_demuxer_stream_adapter_->SignalFlush(true); |
- base::Optional<uint32_t> flush_video_count; |
- if (video_demuxer_stream_adapter_) |
- flush_video_count = video_demuxer_stream_adapter_->SignalFlush(true); |
- // Makes sure flush count is valid if stream is available or both audio and |
- // video agrees on the same flushing state. |
- if ((audio_demuxer_stream_adapter_ && !flush_audio_count.has_value()) || |
- (video_demuxer_stream_adapter_ && !flush_video_count.has_value()) || |
- (audio_demuxer_stream_adapter_ && video_demuxer_stream_adapter_ && |
- flush_audio_count.has_value() != flush_video_count.has_value())) { |
- VLOG(1) << "Ignoring flush request while under flushing operation"; |
- return; |
- } |
- |
- flush_cb_ = flush_cb; |
- |
- // Issues RPC_R_FLUSHUNTIL RPC message. |
- std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
- rpc->set_handle(remote_renderer_handle_); |
- rpc->set_proc(remoting::pb::RpcMessage::RPC_R_FLUSHUNTIL); |
- remoting::pb::RendererFlushUntil* message = |
- rpc->mutable_renderer_flushuntil_rpc(); |
- if (flush_audio_count.has_value()) |
- message->set_audio_count(*flush_audio_count); |
- if (flush_video_count.has_value()) |
- message->set_video_count(*flush_video_count); |
- message->set_callback_handle(rpc_handle_); |
- VLOG(2) << __func__ << ": Sending RPC_R_FLUSHUNTIL to " << rpc->handle() |
- << " with audio_count=" << message->audio_count() |
- << ", video_count=" << message->video_count() |
- << ", callback_handle=" << message->callback_handle(); |
- SendRpcToRemote(std::move(rpc)); |
-} |
- |
-void RemoteRendererImpl::StartPlayingFrom(base::TimeDelta time) { |
- VLOG(2) << __func__ << ": " << time.InMicroseconds(); |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- |
- if (state_ != STATE_PLAYING) { |
- DCHECK_EQ(state_, STATE_ERROR); |
- return; |
- } |
- |
- // Issues RPC_R_STARTPLAYINGFROM RPC message. |
- std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
- rpc->set_handle(remote_renderer_handle_); |
- rpc->set_proc(remoting::pb::RpcMessage::RPC_R_STARTPLAYINGFROM); |
- rpc->set_integer64_value(time.InMicroseconds()); |
- VLOG(2) << __func__ << ": Sending RPC_R_STARTPLAYINGFROM to " << rpc->handle() |
- << " with time_usec=" << rpc->integer64_value(); |
- SendRpcToRemote(std::move(rpc)); |
- |
- { |
- base::AutoLock auto_lock(time_lock_); |
- current_media_time_ = time; |
- } |
- ResetMeasurements(); |
-} |
- |
-void RemoteRendererImpl::SetPlaybackRate(double playback_rate) { |
- VLOG(2) << __func__ << ": " << playback_rate; |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- |
- if (state_ != STATE_FLUSHING && state_ != STATE_PLAYING) { |
- DCHECK_EQ(state_, STATE_ERROR); |
- return; |
- } |
- |
- // Issues RPC_R_SETPLAYBACKRATE RPC message. |
- std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
- rpc->set_handle(remote_renderer_handle_); |
- rpc->set_proc(remoting::pb::RpcMessage::RPC_R_SETPLAYBACKRATE); |
- rpc->set_double_value(playback_rate); |
- VLOG(2) << __func__ << ": Sending RPC_R_SETPLAYBACKRATE to " << rpc->handle() |
- << " with rate=" << rpc->double_value(); |
- SendRpcToRemote(std::move(rpc)); |
- playback_rate_ = playback_rate; |
- ResetMeasurements(); |
-} |
- |
-void RemoteRendererImpl::SetVolume(float volume) { |
- VLOG(2) << __func__ << ": " << volume; |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- |
- if (state_ != STATE_FLUSHING && state_ != STATE_PLAYING) { |
- DCHECK_EQ(state_, STATE_ERROR); |
- return; |
- } |
- |
- // Issues RPC_R_SETVOLUME RPC message. |
- std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
- rpc->set_handle(remote_renderer_handle_); |
- rpc->set_proc(remoting::pb::RpcMessage::RPC_R_SETVOLUME); |
- rpc->set_double_value(volume); |
- VLOG(2) << __func__ << ": Sending RPC_R_SETVOLUME to " << rpc->handle() |
- << " with volume=" << rpc->double_value(); |
- SendRpcToRemote(std::move(rpc)); |
-} |
- |
-base::TimeDelta RemoteRendererImpl::GetMediaTime() { |
- // No BelongsToCurrentThread() checking because this can be called from other |
- // threads. |
- // TODO(erickung): Interpolate current media time using local system time. |
- // Current receiver is to update |current_media_time_| every 250ms. But it |
- // needs to lower the update frequency in order to reduce network usage. Hence |
- // the interpolation is needed after receiver implementation is changed. |
- base::AutoLock auto_lock(time_lock_); |
- return current_media_time_; |
-} |
- |
-// static |
-void RemoteRendererImpl::OnDataPipeCreatedOnMainThread( |
- scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, |
- base::WeakPtr<RemoteRendererImpl> self, |
- base::WeakPtr<remoting::RpcBroker> rpc_broker, |
- mojom::RemotingDataStreamSenderPtrInfo audio, |
- mojom::RemotingDataStreamSenderPtrInfo video, |
- mojo::ScopedDataPipeProducerHandle audio_handle, |
- mojo::ScopedDataPipeProducerHandle video_handle) { |
- media_task_runner->PostTask( |
- FROM_HERE, |
- base::Bind( |
- &RemoteRendererImpl::OnDataPipeCreated, self, base::Passed(&audio), |
- base::Passed(&video), base::Passed(&audio_handle), |
- base::Passed(&video_handle), |
- rpc_broker ? rpc_broker->GetUniqueHandle() : remoting::kInvalidHandle, |
- rpc_broker ? rpc_broker->GetUniqueHandle() |
- : remoting::kInvalidHandle)); |
-} |
- |
-void RemoteRendererImpl::OnDataPipeCreated( |
- mojom::RemotingDataStreamSenderPtrInfo audio, |
- mojom::RemotingDataStreamSenderPtrInfo video, |
- mojo::ScopedDataPipeProducerHandle audio_handle, |
- mojo::ScopedDataPipeProducerHandle video_handle, |
- int audio_rpc_handle, |
- int video_rpc_handle) { |
- VLOG(2) << __func__; |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(!init_workflow_done_callback_.is_null()); |
- |
- if (state_ == STATE_ERROR) |
- return; // Abort because something went wrong in the meantime. |
- DCHECK_EQ(state_, STATE_CREATE_PIPE); |
- |
- // Create audio demuxer stream adapter if audio is available. |
- ::media::DemuxerStream* audio_demuxer_stream = |
- demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO); |
- if (audio_demuxer_stream && audio.is_valid() && audio_handle.is_valid() && |
- audio_rpc_handle != remoting::kInvalidHandle) { |
- VLOG(2) << "Initialize audio"; |
- audio_demuxer_stream_adapter_.reset( |
- new remoting::RemoteDemuxerStreamAdapter( |
- main_task_runner_, media_task_runner_, "audio", |
- audio_demuxer_stream, rpc_broker_, audio_rpc_handle, |
- std::move(audio), std::move(audio_handle), |
- base::Bind(&RemoteRendererImpl::OnFatalError, |
- base::Unretained(this)))); |
- } |
- |
- // Create video demuxer stream adapter if video is available. |
- ::media::DemuxerStream* video_demuxer_stream = |
- demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO); |
- if (video_demuxer_stream && video.is_valid() && video_handle.is_valid() && |
- video_rpc_handle != remoting::kInvalidHandle) { |
- VLOG(2) << "Initialize video"; |
- video_demuxer_stream_adapter_.reset( |
- new remoting::RemoteDemuxerStreamAdapter( |
- main_task_runner_, media_task_runner_, "video", |
- video_demuxer_stream, rpc_broker_, video_rpc_handle, |
- std::move(video), std::move(video_handle), |
- base::Bind(&RemoteRendererImpl::OnFatalError, |
- base::Unretained(this)))); |
- } |
- |
- // Checks if data pipe is created successfully. |
- if (!audio_demuxer_stream_adapter_ && !video_demuxer_stream_adapter_) { |
- OnFatalError(remoting::DATA_PIPE_CREATE_ERROR); |
- return; |
- } |
- |
- state_ = STATE_ACQUIRING; |
- // Issues RPC_ACQUIRE_RENDERER RPC message. |
- std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
- rpc->set_handle(remoting::kReceiverHandle); |
- rpc->set_proc(remoting::pb::RpcMessage::RPC_ACQUIRE_RENDERER); |
- rpc->set_integer_value(rpc_handle_); |
- VLOG(2) << __func__ << ": Sending RPC_ACQUIRE_RENDERER to " << rpc->handle() |
- << " with rpc_handle=" << rpc->integer_value(); |
- SendRpcToRemote(std::move(rpc)); |
-} |
- |
-// static |
-void RemoteRendererImpl::OnMessageReceivedOnMainThread( |
- scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, |
- base::WeakPtr<RemoteRendererImpl> self, |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- media_task_runner->PostTask( |
- FROM_HERE, base::Bind(&RemoteRendererImpl::OnReceivedRpc, self, |
- base::Passed(&message))); |
-} |
- |
-void RemoteRendererImpl::OnReceivedRpc( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- switch (message->proc()) { |
- case remoting::pb::RpcMessage::RPC_ACQUIRE_RENDERER_DONE: |
- AcquireRendererDone(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_R_INITIALIZE_CALLBACK: |
- InitializeCallback(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_R_FLUSHUNTIL_CALLBACK: |
- FlushUntilCallback(); |
- break; |
- case remoting::pb::RpcMessage::RPC_R_SETCDM_CALLBACK: |
- SetCdmCallback(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONTIMEUPDATE: |
- OnTimeUpdate(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONBUFFERINGSTATECHANGE: |
- OnBufferingStateChange(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONENDED: |
- VLOG(2) << __func__ << ": Received RPC_RC_ONENDED."; |
- client_->OnEnded(); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONERROR: |
- VLOG(2) << __func__ << ": Received RPC_RC_ONERROR."; |
- OnFatalError(remoting::RECEIVER_PIPELINE_ERROR); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONVIDEONATURALSIZECHANGE: |
- OnVideoNaturalSizeChange(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONVIDEOOPACITYCHANGE: |
- OnVideoOpacityChange(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONSTATISTICSUPDATE: |
- OnStatisticsUpdate(std::move(message)); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONWAITINGFORDECRYPTIONKEY: |
- VLOG(2) << __func__ << ": Received RPC_RC_ONWAITINGFORDECRYPTIONKEY."; |
- client_->OnWaitingForDecryptionKey(); |
- break; |
- case remoting::pb::RpcMessage::RPC_RC_ONDURATIONCHANGE: |
- OnDurationChange(std::move(message)); |
- break; |
- |
- default: |
- LOG(ERROR) << "Unknown rpc: " << message->proc(); |
- } |
-} |
- |
-void RemoteRendererImpl::SendRpcToRemote( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(main_task_runner_); |
- main_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&remoting::RpcBroker::SendMessageToRemote, |
- rpc_broker_, base::Passed(&message))); |
-} |
- |
-void RemoteRendererImpl::AcquireRendererDone( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- |
- remote_renderer_handle_ = message->integer_value(); |
- VLOG(2) << __func__ |
- << ": Received RPC_ACQUIRE_RENDERER_DONE with remote_renderer_handle=" |
- << remote_renderer_handle_; |
- |
- if (state_ != STATE_ACQUIRING || init_workflow_done_callback_.is_null()) { |
- LOG(WARNING) << "Unexpected acquire renderer done RPC."; |
- OnFatalError(remoting::PEERS_OUT_OF_SYNC); |
- return; |
- } |
- state_ = STATE_INITIALIZING; |
- |
- // Issues RPC_R_INITIALIZE RPC message to initialize renderer. |
- std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
- rpc->set_handle(remote_renderer_handle_); |
- rpc->set_proc(remoting::pb::RpcMessage::RPC_R_INITIALIZE); |
- remoting::pb::RendererInitialize* init = |
- rpc->mutable_renderer_initialize_rpc(); |
- init->set_client_handle(rpc_handle_); |
- init->set_audio_demuxer_handle( |
- audio_demuxer_stream_adapter_ |
- ? audio_demuxer_stream_adapter_->rpc_handle() |
- : remoting::kInvalidHandle); |
- init->set_video_demuxer_handle( |
- video_demuxer_stream_adapter_ |
- ? video_demuxer_stream_adapter_->rpc_handle() |
- : remoting::kInvalidHandle); |
- init->set_callback_handle(rpc_handle_); |
- VLOG(2) << __func__ << ": Sending RPC_R_INITIALIZE to " << rpc->handle() |
- << " with client_handle=" << init->client_handle() |
- << ", audio_demuxer_handle=" << init->audio_demuxer_handle() |
- << ", video_demuxer_handle=" << init->video_demuxer_handle() |
- << ", callback_handle=" << init->callback_handle(); |
- SendRpcToRemote(std::move(rpc)); |
-} |
- |
-void RemoteRendererImpl::InitializeCallback( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- |
- const bool success = message->boolean_value(); |
- VLOG(2) << __func__ |
- << ": Received RPC_R_INITIALIZE_CALLBACK with success=" << success; |
- |
- if (state_ != STATE_INITIALIZING || init_workflow_done_callback_.is_null()) { |
- LOG(WARNING) << "Unexpected initialize callback RPC."; |
- OnFatalError(remoting::PEERS_OUT_OF_SYNC); |
- return; |
- } |
- |
- if (!success) { |
- OnFatalError(remoting::RECEIVER_INITIALIZE_FAILED); |
- return; |
- } |
- |
- metrics_recorder_.OnRendererInitialized(); |
- |
- state_ = STATE_PLAYING; |
- base::ResetAndReturn(&init_workflow_done_callback_).Run(::media::PIPELINE_OK); |
-} |
- |
-void RemoteRendererImpl::FlushUntilCallback() { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- VLOG(2) << __func__ << ": Received RPC_R_FLUSHUNTIL_CALLBACK"; |
- |
- if (state_ != STATE_FLUSHING || flush_cb_.is_null()) { |
- LOG(WARNING) << "Unexpected flushuntil callback RPC."; |
- OnFatalError(remoting::PEERS_OUT_OF_SYNC); |
- return; |
- } |
- |
- state_ = STATE_PLAYING; |
- if (audio_demuxer_stream_adapter_) |
- audio_demuxer_stream_adapter_->SignalFlush(false); |
- if (video_demuxer_stream_adapter_) |
- video_demuxer_stream_adapter_->SignalFlush(false); |
- base::ResetAndReturn(&flush_cb_).Run(); |
- ResetMeasurements(); |
-} |
- |
-void RemoteRendererImpl::SetCdmCallback( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- VLOG(2) << __func__ << ": Received RPC_R_SETCDM_CALLBACK with cdm_id=" |
- << message->renderer_set_cdm_rpc().cdm_id() << ", callback_handle=" |
- << message->renderer_set_cdm_rpc().callback_handle(); |
- // TODO(erickung): add implementation once Remote CDM implementation is done. |
- NOTIMPLEMENTED(); |
-} |
- |
-void RemoteRendererImpl::OnTimeUpdate( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- // Shutdown remoting session if receiving malformed RPC message. |
- if (!message->has_rendererclient_ontimeupdate_rpc()) { |
- VLOG(1) << __func__ << " missing required RPC message"; |
- OnFatalError(remoting::RPC_INVALID); |
- return; |
- } |
- const int64_t time_usec = |
- message->rendererclient_ontimeupdate_rpc().time_usec(); |
- const int64_t max_time_usec = |
- message->rendererclient_ontimeupdate_rpc().max_time_usec(); |
- VLOG(2) << __func__ |
- << ": Received RPC_RC_ONTIMEUPDATE with time_usec=" << time_usec |
- << ", max_time_usec=" << max_time_usec; |
- // Ignores invalid time, such as negative value, or time larger than max value |
- // (usually the time stamp that all streams are pushed into AV pipeline). |
- if (time_usec < 0 || max_time_usec < 0 || time_usec > max_time_usec) |
- return; |
- |
- { |
- // Updates current time information. |
- base::AutoLock auto_lock(time_lock_); |
- current_media_time_ = base::TimeDelta::FromMicroseconds(time_usec); |
- current_max_time_ = base::TimeDelta::FromMicroseconds(max_time_usec); |
- } |
- |
- metrics_recorder_.OnEvidenceOfPlayoutAtReceiver(); |
- OnMediaTimeUpdated(); |
-} |
- |
-void RemoteRendererImpl::OnBufferingStateChange( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- if (!message->has_rendererclient_onbufferingstatechange_rpc()) { |
- VLOG(1) << __func__ << " missing required RPC message"; |
- OnFatalError(remoting::RPC_INVALID); |
- return; |
- } |
- VLOG(2) << __func__ << ": Received RPC_RC_ONBUFFERINGSTATECHANGE with state=" |
- << message->rendererclient_onbufferingstatechange_rpc().state(); |
- base::Optional<::media::BufferingState> state = |
- remoting::ToMediaBufferingState( |
- message->rendererclient_onbufferingstatechange_rpc().state()); |
- if (!state.has_value()) |
- return; |
- client_->OnBufferingStateChange(state.value()); |
-} |
- |
-void RemoteRendererImpl::OnVideoNaturalSizeChange( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- // Shutdown remoting session if receiving malformed RPC message. |
- if (!message->has_rendererclient_onvideonatualsizechange_rpc()) { |
- VLOG(1) << __func__ << " missing required RPC message"; |
- OnFatalError(remoting::RPC_INVALID); |
- return; |
- } |
- const auto& size_change = |
- message->rendererclient_onvideonatualsizechange_rpc(); |
- VLOG(2) << __func__ << ": Received RPC_RC_ONVIDEONATURALSIZECHANGE with size=" |
- << size_change.width() << 'x' << size_change.height(); |
- if (size_change.width() <= 0 || size_change.height() <= 0) |
- return; |
- client_->OnVideoNaturalSizeChange( |
- gfx::Size(size_change.width(), size_change.height())); |
-} |
- |
-void RemoteRendererImpl::OnVideoOpacityChange( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- const bool opaque = message->boolean_value(); |
- VLOG(2) << __func__ |
- << ": Received RPC_RC_ONVIDEOOPACITYCHANGE with opaque=" << opaque; |
- client_->OnVideoOpacityChange(opaque); |
-} |
- |
-void RemoteRendererImpl::OnStatisticsUpdate( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- // Shutdown remoting session if receiving malformed RPC message. |
- if (!message->has_rendererclient_onstatisticsupdate_rpc()) { |
- VLOG(1) << __func__ << " missing required RPC message"; |
- OnFatalError(remoting::RPC_INVALID); |
- return; |
- } |
- const auto& rpc_message = message->rendererclient_onstatisticsupdate_rpc(); |
- ::media::PipelineStatistics stats; |
- // Note: Each |stats| value is a delta, not the aggregate amount. |
- stats.audio_bytes_decoded = rpc_message.audio_bytes_decoded(); |
- stats.video_bytes_decoded = rpc_message.video_bytes_decoded(); |
- stats.video_frames_decoded = rpc_message.video_frames_decoded(); |
- stats.video_frames_dropped = rpc_message.video_frames_dropped(); |
- stats.audio_memory_usage = rpc_message.audio_memory_usage(); |
- stats.video_memory_usage = rpc_message.video_memory_usage(); |
- VLOG(2) << __func__ |
- << ": Received RPC_RC_ONSTATISTICSUPDATE with audio_bytes_decoded=" |
- << stats.audio_bytes_decoded |
- << ", video_bytes_decoded=" << stats.video_bytes_decoded |
- << ", video_frames_decoded=" << stats.video_frames_decoded |
- << ", video_frames_dropped=" << stats.video_frames_dropped |
- << ", audio_memory_usage=" << stats.audio_memory_usage |
- << ", video_memory_usage=" << stats.video_memory_usage; |
- |
- if (stats.audio_bytes_decoded > 0 || stats.video_frames_decoded > 0 || |
- stats.video_frames_dropped > 0) { |
- metrics_recorder_.OnEvidenceOfPlayoutAtReceiver(); |
- } |
- UpdateVideoStatsQueue(stats.video_frames_decoded, stats.video_frames_dropped); |
- client_->OnStatisticsUpdate(stats); |
-} |
- |
-void RemoteRendererImpl::OnDurationChange( |
- std::unique_ptr<remoting::pb::RpcMessage> message) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK(message); |
- VLOG(2) << __func__ << ": Received RPC_RC_ONDURATIONCHANGE with usec=" |
- << message->integer64_value(); |
- if (message->integer64_value() < 0) |
- return; |
- client_->OnDurationChange( |
- base::TimeDelta::FromMicroseconds(message->integer64_value())); |
-} |
- |
-void RemoteRendererImpl::OnFatalError(remoting::StopTrigger stop_trigger) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- DCHECK_NE(remoting::UNKNOWN_STOP_TRIGGER, stop_trigger); |
- |
- VLOG(2) << __func__ << " with StopTrigger " << stop_trigger; |
- |
- // If this is the first error, notify the controller. It is expected the |
- // controller will shut down this renderer shortly. |
- if (state_ != STATE_ERROR) { |
- state_ = STATE_ERROR; |
- main_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&RemotingRendererController::OnRendererFatalError, |
- remoting_renderer_controller_, stop_trigger)); |
- } |
- |
- data_flow_poll_timer_.Stop(); |
- |
- if (!init_workflow_done_callback_.is_null()) { |
- base::ResetAndReturn(&init_workflow_done_callback_) |
- .Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
- return; |
- } |
- |
- if (!flush_cb_.is_null()) |
- base::ResetAndReturn(&flush_cb_).Run(); |
-} |
- |
-// static |
-void RemoteRendererImpl::RequestUpdateInterstitialOnMainThread( |
- scoped_refptr<base::SingleThreadTaskRunner> media_task_runner, |
- base::WeakPtr<RemoteRendererImpl> remote_renderer_impl, |
- const base::Optional<SkBitmap>& background_image, |
- const gfx::Size& canvas_size, |
- RemotingInterstitialType interstitial_type) { |
- media_task_runner->PostTask( |
- FROM_HERE, |
- base::Bind(&RemoteRendererImpl::UpdateInterstitial, remote_renderer_impl, |
- background_image, canvas_size, interstitial_type)); |
-} |
- |
-void RemoteRendererImpl::UpdateInterstitial( |
- const base::Optional<SkBitmap>& background_image, |
- const gfx::Size& canvas_size, |
- RemotingInterstitialType interstitial_type) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- if (background_image.has_value()) |
- interstitial_background_ = background_image.value(); |
- canvas_size_ = canvas_size; |
- PaintRemotingInterstitial(interstitial_background_, canvas_size_, |
- interstitial_type, video_renderer_sink_); |
-} |
- |
-void RemoteRendererImpl::OnMediaTimeUpdated() { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- if (!flush_cb_.is_null()) |
- return; // Don't manage and check the queue when Flush() is on-going. |
- |
- base::TimeTicks current_time = base::TimeTicks::Now(); |
- if (current_time < ignore_updates_until_time_) |
- return; // Not stable yet. |
- |
- media_time_queue_.push_back( |
- std::make_pair(current_time, current_media_time_)); |
- base::TimeDelta window_duration = |
- current_time - media_time_queue_.front().first; |
- if (window_duration < kTrackingWindow) |
- return; // Not enough data to make a reliable decision. |
- |
- base::TimeDelta media_duration = |
- media_time_queue_.back().second - media_time_queue_.front().second; |
- base::TimeDelta update_duration = |
- (media_time_queue_.back().first - media_time_queue_.front().first) * |
- playback_rate_; |
- if ((media_duration - update_duration).magnitude() >= |
- kMediaPlaybackDelayThreshold) { |
- VLOG(1) << "Irregular playback detected: Media playback delayed." |
- << " media_duration = " << media_duration |
- << " update_duration = " << update_duration; |
- ++times_playback_delayed_; |
- if (times_playback_delayed_ == kPlaybackDelayCountThreshold) |
- OnFatalError(remoting::PACING_TOO_SLOWLY); |
- } else { |
- times_playback_delayed_ = 0; |
- } |
- |
- // Prune |media_time_queue_|. |
- while (media_time_queue_.back().first - media_time_queue_.front().first >= |
- kTrackingWindow) |
- media_time_queue_.pop_front(); |
-} |
- |
-void RemoteRendererImpl::UpdateVideoStatsQueue(int video_frames_decoded, |
- int video_frames_dropped) { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- if (!flush_cb_.is_null()) |
- return; // Don't manage and check the queue when Flush() is on-going. |
- |
- if (!stats_updated_) { |
- if (video_frames_decoded) |
- stats_updated_ = true; |
- // Ignore the first stats since it may include the information during |
- // unstable period. |
- return; |
- } |
- |
- base::TimeTicks current_time = base::TimeTicks::Now(); |
- if (current_time < ignore_updates_until_time_) |
- return; // Not stable yet. |
- |
- video_stats_queue_.push_back(std::make_tuple( |
- current_time, video_frames_decoded, video_frames_dropped)); |
- sum_video_frames_decoded_ += video_frames_decoded; |
- sum_video_frames_dropped_ += video_frames_dropped; |
- base::TimeDelta window_duration = |
- current_time - std::get<0>(video_stats_queue_.front()); |
- if (window_duration < kTrackingWindow) |
- return; // Not enough data to make a reliable decision. |
- |
- if (sum_video_frames_decoded_ && |
- sum_video_frames_dropped_ * 100 > |
- sum_video_frames_decoded_ * kMaxNumVideoFramesDroppedPercentage) { |
- VLOG(1) << "Irregular playback detected: Too many video frames dropped." |
- << " video_frames_decoded= " << sum_video_frames_decoded_ |
- << " video_frames_dropped= " << sum_video_frames_dropped_; |
- OnFatalError(remoting::FRAME_DROP_RATE_HIGH); |
- } |
- // Prune |video_stats_queue_|. |
- while (std::get<0>(video_stats_queue_.back()) - |
- std::get<0>(video_stats_queue_.front()) >= |
- kTrackingWindow) { |
- sum_video_frames_decoded_ -= std::get<1>(video_stats_queue_.front()); |
- sum_video_frames_dropped_ -= std::get<2>(video_stats_queue_.front()); |
- video_stats_queue_.pop_front(); |
- } |
-} |
- |
-void RemoteRendererImpl::ResetMeasurements() { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- media_time_queue_.clear(); |
- video_stats_queue_.clear(); |
- sum_video_frames_dropped_ = 0; |
- sum_video_frames_decoded_ = 0; |
- stats_updated_ = false; |
- ignore_updates_until_time_ = base::TimeTicks::Now() + kStabilizationPeriod; |
- |
- if (state_ != STATE_ERROR && |
- (audio_demuxer_stream_adapter_ || video_demuxer_stream_adapter_)) { |
- data_flow_poll_timer_.Start(FROM_HERE, kDataFlowPollPeriod, this, |
- &RemoteRendererImpl::MeasureAndRecordDataRates); |
- } |
-} |
- |
-void RemoteRendererImpl::MeasureAndRecordDataRates() { |
- DCHECK(media_task_runner_->BelongsToCurrentThread()); |
- |
- // Whenever media is first started or flushed/seeked, there is a "burst |
- // bufferring" period as the remote device rapidly fills its buffer before |
- // resuming playback. Since the goal here is to measure the sustained content |
- // bitrates, ignore the byte counts the first time since the last |
- // ResetMeasurements() call. |
- const base::TimeTicks current_time = base::TimeTicks::Now(); |
- if (current_time < ignore_updates_until_time_ + kDataFlowPollPeriod) { |
- if (audio_demuxer_stream_adapter_) |
- audio_demuxer_stream_adapter_->GetBytesWrittenAndReset(); |
- if (video_demuxer_stream_adapter_) |
- video_demuxer_stream_adapter_->GetBytesWrittenAndReset(); |
- return; |
- } |
- |
- const int kBytesPerKilobit = 1024 / 8; |
- if (audio_demuxer_stream_adapter_) { |
- const double kilobits_per_second = |
- (audio_demuxer_stream_adapter_->GetBytesWrittenAndReset() / |
- kDataFlowPollPeriod.InSecondsF()) / |
- kBytesPerKilobit; |
- DCHECK_GE(kilobits_per_second, 0); |
- const base::CheckedNumeric<int> checked_kbps = kilobits_per_second; |
- metrics_recorder_.OnAudioRateEstimate( |
- checked_kbps.ValueOrDefault(std::numeric_limits<int>::max())); |
- } |
- if (video_demuxer_stream_adapter_) { |
- const double kilobits_per_second = |
- (video_demuxer_stream_adapter_->GetBytesWrittenAndReset() / |
- kDataFlowPollPeriod.InSecondsF()) / |
- kBytesPerKilobit; |
- DCHECK_GE(kilobits_per_second, 0); |
- const base::CheckedNumeric<int> checked_kbps = kilobits_per_second; |
- metrics_recorder_.OnVideoRateEstimate( |
- checked_kbps.ValueOrDefault(std::numeric_limits<int>::max())); |
- } |
-} |
- |
-} // namespace media |