Chromium Code Reviews| Index: media/remoting/remoting_source_impl.cc |
| diff --git a/media/remoting/remoting_controller.cc b/media/remoting/remoting_source_impl.cc |
| similarity index 31% |
| rename from media/remoting/remoting_controller.cc |
| rename to media/remoting/remoting_source_impl.cc |
| index 73c372f68673518e429677979a24dbd83fd66864..4180f84b67495674acc771d39aed311ff463eda5 100644 |
| --- a/media/remoting/remoting_controller.cc |
| +++ b/media/remoting/remoting_source_impl.cc |
| @@ -2,271 +2,226 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "media/remoting/remoting_controller.h" |
| +#include "media/remoting/remoting_source_impl.h" |
| #include "base/bind.h" |
| -#include "base/bind_helpers.h" |
| -#include "base/callback_helpers.h" |
| #include "base/logging.h" |
| -#include "base/single_thread_task_runner.h" |
| #include "media/remoting/rpc/proto_utils.h" |
| -#include "media/remoting/rpc/rpc_broker.h" |
| namespace media { |
| -RemotingController::RemotingController( |
| +RemotingSourceImpl::RemotingSourceImpl( |
| mojom::RemotingSourceRequest source_request, |
| mojom::RemoterPtr remoter) |
| - : binding_(this, std::move(source_request)), |
| - remoter_(std::move(remoter)), |
| - task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| - weak_factory_(this) { |
| + : rpc_broker_(base::Bind(&RemotingSourceImpl::SendMessageToSink, this)), |
| + binding_(this, std::move(source_request)), |
| + remoter_(std::move(remoter)) { |
| DCHECK(remoter_); |
| - rpc_broker_.reset(new remoting::RpcBroker(base::Bind( |
| - &RemotingController::OnSendMessageToSink, weak_factory_.GetWeakPtr()))); |
| } |
| -RemotingController::~RemotingController() {} |
| +RemotingSourceImpl::~RemotingSourceImpl() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| -void RemotingController::StartDataPipe( |
| - std::unique_ptr<mojo::DataPipe> audio_data_pipe, |
| - std::unique_ptr<mojo::DataPipe> video_data_pipe, |
| - const DataPipeStartCallback& done_callback) { |
| - VLOG(2) << __FUNCTION__; |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(!done_callback.is_null()); |
| - bool audio = audio_data_pipe != nullptr; |
| - bool video = video_data_pipe != nullptr; |
| - |
| - if (!audio && !video) { |
| - LOG(ERROR) << "No audio and video to establish data pipe"; |
| - done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(), |
| - mojom::RemotingDataStreamSenderPtrInfo(), |
| - mojo::ScopedDataPipeProducerHandle(), |
| - mojo::ScopedDataPipeProducerHandle()); |
| - return; |
| + if (!clients_.empty()) { |
| + Shutdown(); |
| + clients_.clear(); |
| } |
| - |
| - mojom::RemotingDataStreamSenderPtr audio_stream_sender; |
| - mojom::RemotingDataStreamSenderPtr video_stream_sender; |
| - remoter_->StartDataStreams( |
| - audio ? std::move(audio_data_pipe->consumer_handle) |
| - : mojo::ScopedDataPipeConsumerHandle(), |
| - video ? std::move(video_data_pipe->consumer_handle) |
| - : mojo::ScopedDataPipeConsumerHandle(), |
| - audio ? mojo::GetProxy(&audio_stream_sender) |
| - : media::mojom::RemotingDataStreamSenderRequest(), |
| - video ? mojo::GetProxy(&video_stream_sender) |
| - : media::mojom::RemotingDataStreamSenderRequest()); |
| - |
| - done_callback.Run(audio_stream_sender.PassInterface(), |
| - video_stream_sender.PassInterface(), |
| - audio ? std::move(audio_data_pipe->producer_handle) |
| - : mojo::ScopedDataPipeProducerHandle(), |
| - video ? std::move(video_data_pipe->producer_handle) |
| - : mojo::ScopedDataPipeProducerHandle()); |
| } |
| -base::WeakPtr<remoting::RpcBroker> RemotingController::GetRpcBroker() const { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - return rpc_broker_->GetWeakPtr(); |
| -} |
| +void RemotingSourceImpl::OnSinkAvailable() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| -void RemotingController::OnSendMessageToSink( |
| - std::unique_ptr<std::vector<uint8_t>> message) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - remoter_->SendMessageToSink(*message); |
| + if (state_ == RemotingSessionState::SESSION_UNAVAILABLE) |
| + UpdateAndNotifyState(RemotingSessionState::SESSION_CAN_START); |
| } |
| -void RemotingController::OnSinkAvailable() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::OnSinkGone() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| - is_sink_available_ = true; |
| - UpdateAndMaybeSwitch(); |
| + if (state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED) |
| + return; |
| + if (state_ == RemotingSessionState::SESSION_CAN_START) { |
| + UpdateAndNotifyState(RemotingSessionState::SESSION_UNAVAILABLE); |
| + return; |
| + } |
| + if (state_ == RemotingSessionState::SESSION_STARTED || |
| + state_ == RemotingSessionState::SESSION_STARTING) { |
| + VLOG(1) << "Sink is gone in a remoting session."; |
| + // Remoting is being stopped by Remoter. |
| + UpdateAndNotifyState(RemotingSessionState::SESSION_STOPPING); |
| + } |
| } |
| -void RemotingController::OnSinkGone() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::OnStarted() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| - is_sink_available_ = false; |
| - UpdateAndMaybeSwitch(); |
| + VLOG(1) << "Remoting started successively."; |
| + if (clients_.empty() || |
| + state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED || |
| + state_ == RemotingSessionState::SESSION_STOPPING) { |
| + for (Client* client : clients_) |
| + client->OnStarted(false); |
| + return; |
| + } |
| + for (Client* client : clients_) |
| + client->OnStarted(true); |
| + state_ = RemotingSessionState::SESSION_STARTED; |
| } |
| -void RemotingController::OnStarted() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::OnStartFailed(mojom::RemotingStartFailReason reason) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| - VLOG(1) << "Remoting started successively."; |
| - if (is_remoting_) |
| - switch_renderer_cb_.Run(); |
| - else |
| - remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); |
| + VLOG(1) << "Failed to start remoting:" << reason; |
| + for (Client* client : clients_) |
| + client->OnStarted(false); |
| + if (state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED) |
| + return; |
| + state_ = RemotingSessionState::SESSION_UNAVAILABLE; |
| } |
| -void RemotingController::OnStartFailed(mojom::RemotingStartFailReason reason) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::OnStopped(mojom::RemotingStopReason reason) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| - VLOG(1) << "Failed to start remoting:" << reason; |
| - is_remoting_ = false; |
| + VLOG(1) << "Remoting stopped: " << reason; |
| + if (state_ == RemotingSessionState::SESSION_PERMANENTLY_STOPPED) |
| + return; |
| + RemotingSessionState state = RemotingSessionState::SESSION_UNAVAILABLE; |
| + UpdateAndNotifyState(state); |
| } |
| -void RemotingController::OnMessageFromSink( |
| +void RemotingSourceImpl::OnMessageFromSink( |
| const std::vector<uint8_t>& message) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| std::unique_ptr<remoting::pb::RpcMessage> rpc(new remoting::pb::RpcMessage()); |
| if (!rpc->ParseFromArray(message.data(), message.size())) { |
| LOG(ERROR) << "corrupted Rpc message"; |
| + Shutdown(); |
| return; |
| } |
| - |
| - rpc_broker_->ProcessMessageFromRemote(std::move(rpc)); |
| -} |
| - |
| -void RemotingController::OnStopped(mojom::RemotingStopReason reason) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - |
| - VLOG(1) << "Remoting stopped: " << reason; |
| - is_remoting_ = false; |
| + rpc_broker_.ProcessMessageFromRemote(std::move(rpc)); |
| } |
| -void RemotingController::OnEnteredFullscreen() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::UpdateAndNotifyState(RemotingSessionState state) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| - is_fullscreen_ = true; |
| - UpdateAndMaybeSwitch(); |
| + if (state_ == state) |
| + return; |
| + state_ = state; |
| + for (Client* client : clients_) |
| + client->OnSessionStateChanged(); |
| +} |
| + |
| +void RemotingSourceImpl::StartRemoting(Client* client) { |
| + DCHECK(std::find(clients_.begin(), clients_.end(), client) != clients_.end()); |
| + |
| + switch (state_) { |
| + case SESSION_CAN_START: |
| + remoter_->Start(); |
| + UpdateAndNotifyState(RemotingSessionState::SESSION_STARTING); |
| + break; |
| + case SESSION_STARTING: |
| + break; |
| + case SESSION_STARTED: |
| + client->OnStarted(true); |
| + break; |
| + case SESSION_STOPPING: |
| + case SESSION_UNAVAILABLE: |
| + case SESSION_PERMANENTLY_STOPPED: |
| + client->OnStarted(false); |
| + break; |
| + } |
| } |
| -void RemotingController::OnExitedFullscreen() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::StopRemoting(Client* client) { |
| + DCHECK(std::find(clients_.begin(), clients_.end(), client) != clients_.end()); |
| - is_fullscreen_ = false; |
| - UpdateAndMaybeSwitch(); |
| -} |
| + VLOG(1) << "RemotingSourceImpl::StopRemoting: " << state_; |
| -void RemotingController::OnSetCdm(CdmContext* cdm_context) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + if (state_ != RemotingSessionState::SESSION_STARTING && |
| + state_ != RemotingSessionState::SESSION_STARTED) |
| + return; |
| - // TODO(xjz): Not implemented. Will add in up-coming change. |
| - NOTIMPLEMENTED(); |
| + remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); |
| + UpdateAndNotifyState(RemotingSessionState::SESSION_STOPPING); |
| } |
| -void RemotingController::SetSwitchRendererCallback( |
| - const SwitchRendererCallback& cb) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(!cb.is_null()); |
| +void RemotingSourceImpl::AddClient(Client* client) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(std::find(clients_.begin(), clients_.end(), client) == clients_.end()); |
| - switch_renderer_cb_ = cb; |
| + clients_.push_back(client); |
| + client->OnSessionStateChanged(); |
| } |
| -void RemotingController::OnMetadataChanged(const PipelineMetadata& metadata) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| +void RemotingSourceImpl::RemoveClient(Client* client) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| - has_video_ = metadata.has_video; |
| - has_audio_ = metadata.has_audio; |
| - if (!has_video_ && !has_audio_) |
| - return; |
| - |
| - // On Android, when using the MediaPlayerRenderer, |has_video_| and |
| - // |has_audio_| will be true, but the respective configs will be empty. |
| - // We cannot make any assumptions on the validity of configs. |
| - if (has_video_) { |
| - video_decoder_config_ = metadata.video_decoder_config; |
| - is_encrypted_ |= video_decoder_config_.is_encrypted(); |
| - } |
| - if (has_audio_) { |
| - audio_decoder_config_ = metadata.audio_decoder_config; |
| - is_encrypted_ |= audio_decoder_config_.is_encrypted(); |
| - } |
| - UpdateAndMaybeSwitch(); |
| -} |
| + auto it = std::find(clients_.begin(), clients_.end(), client); |
| + DCHECK(it != clients_.end()); |
| -bool RemotingController::IsVideoCodecSupported() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(has_video_); |
| - |
| - switch (video_decoder_config_.codec()) { |
| - case VideoCodec::kCodecH264: |
| - case VideoCodec::kCodecVP8: |
| - return true; |
| - default: |
| - VLOG(2) << "Remoting does not support video codec: " |
| - << video_decoder_config_.codec(); |
| - return false; |
| + clients_.erase(it); |
| + if (clients_.empty() && (state_ == RemotingSessionState::SESSION_STARTED || |
| + state_ == RemotingSessionState::SESSION_STARTING)) { |
| + remoter_->Stop(mojom::RemotingStopReason::SOURCE_GONE); |
| + state_ = RemotingSessionState::SESSION_STOPPING; |
| } |
| } |
| -bool RemotingController::IsAudioCodecSupported() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(has_audio_); |
| - |
| - switch (audio_decoder_config_.codec()) { |
| - case AudioCodec::kCodecAAC: |
| - case AudioCodec::kCodecMP3: |
| - case AudioCodec::kCodecPCM: |
| - case AudioCodec::kCodecVorbis: |
| - case AudioCodec::kCodecFLAC: |
| - case AudioCodec::kCodecAMR_NB: |
| - case AudioCodec::kCodecAMR_WB: |
| - case AudioCodec::kCodecPCM_MULAW: |
| - case AudioCodec::kCodecGSM_MS: |
| - case AudioCodec::kCodecPCM_S16BE: |
| - case AudioCodec::kCodecPCM_S24BE: |
| - case AudioCodec::kCodecOpus: |
| - case AudioCodec::kCodecEAC3: |
| - case AudioCodec::kCodecPCM_ALAW: |
| - case AudioCodec::kCodecALAC: |
| - case AudioCodec::kCodecAC3: |
| - return true; |
| - default: |
| - VLOG(2) << "Remoting does not support audio codec: " |
| - << audio_decoder_config_.codec(); |
| - return false; |
| - } |
| -} |
| +void RemotingSourceImpl::Shutdown() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| -bool RemotingController::ShouldBeRemoting() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - |
| - // TODO(xjz): The control logic for EME will be added in a later CL. |
| - if (is_encrypted_) |
| - return false; |
| - |
| - if (!is_sink_available_) |
| - return false; |
| - if (!is_fullscreen_) |
| - return false; |
| - if (has_video_ && !IsVideoCodecSupported()) |
| - return false; |
| - if (has_audio_ && !IsAudioCodecSupported()) |
| - return false; |
| - return true; |
| + if (state_ == RemotingSessionState::SESSION_STARTED || |
| + state_ == RemotingSessionState::SESSION_STARTING) |
| + remoter_->Stop(mojom::RemotingStopReason::UNEXPECTED_FAILURE); |
| + UpdateAndNotifyState(RemotingSessionState::SESSION_PERMANENTLY_STOPPED); |
| } |
| -void RemotingController::UpdateAndMaybeSwitch() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - |
| - // TODO(xjz): The switching logic for encrypted content will be added in a |
| - // later CL. |
| +void RemotingSourceImpl::StartDataPipe( |
| + std::unique_ptr<mojo::DataPipe> audio_data_pipe, |
| + std::unique_ptr<mojo::DataPipe> video_data_pipe, |
| + const DataPipeStartCallback& done_callback) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(!done_callback.is_null()); |
| - // Demuxer is not initialized yet. |
| - if (!has_audio_ && !has_video_) |
| + bool audio = audio_data_pipe != nullptr; |
| + bool video = video_data_pipe != nullptr; |
| + if (!audio && !video) { |
| + LOG(ERROR) << "No audio and video to establish data pipe"; |
| + done_callback.Run(mojom::RemotingDataStreamSenderPtrInfo(), |
| + mojom::RemotingDataStreamSenderPtrInfo(), |
| + mojo::ScopedDataPipeProducerHandle(), |
| + mojo::ScopedDataPipeProducerHandle()); |
| return; |
| + } |
| + mojom::RemotingDataStreamSenderPtr audio_stream_sender; |
| + mojom::RemotingDataStreamSenderPtr video_stream_sender; |
| + remoter_->StartDataStreams( |
| + audio ? std::move(audio_data_pipe->consumer_handle) |
| + : mojo::ScopedDataPipeConsumerHandle(), |
| + video ? std::move(video_data_pipe->consumer_handle) |
| + : mojo::ScopedDataPipeConsumerHandle(), |
| + audio ? mojo::GetProxy(&audio_stream_sender) |
| + : media::mojom::RemotingDataStreamSenderRequest(), |
| + video ? mojo::GetProxy(&video_stream_sender) |
| + : media::mojom::RemotingDataStreamSenderRequest()); |
| + done_callback.Run(audio_stream_sender.PassInterface(), |
| + video_stream_sender.PassInterface(), |
| + audio ? std::move(audio_data_pipe->producer_handle) |
| + : mojo::ScopedDataPipeProducerHandle(), |
| + video ? std::move(video_data_pipe->producer_handle) |
| + : mojo::ScopedDataPipeProducerHandle()); |
| +} |
| - DCHECK(!switch_renderer_cb_.is_null()); |
| - |
| - bool should_be_remoting = ShouldBeRemoting(); |
| - if (is_remoting_ == should_be_remoting) |
| - return; |
| +remoting::RpcBroker* RemotingSourceImpl::GetRpcBroker() const { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + return const_cast<remoting::RpcBroker*>(&rpc_broker_); |
|
miu
2016/11/07 21:54:02
nit: Please add a TODO comment for fixing const-co
xjz
2016/11/08 00:59:06
Done.
|
| +} |
| - // Switch between local and remoting. |
| - is_remoting_ = should_be_remoting; |
| - if (is_remoting_) { |
| - // |swithc_renderer_cb_.Run()| will be called after remoting is started |
| - // successfully. |
| - remoter_->Start(); |
| - } else { |
| - switch_renderer_cb_.Run(); |
| - remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); |
| - } |
| +void RemotingSourceImpl::SendMessageToSink( |
| + std::unique_ptr<std::vector<uint8_t>> message) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + remoter_->SendMessageToSink(*message); |
| } |
| } // namespace media |