Index: media/remoting/remoting_source_impl.cc |
diff --git a/media/remoting/remoting_controller.cc b/media/remoting/remoting_source_impl.cc |
similarity index 33% |
rename from media/remoting/remoting_controller.cc |
rename to media/remoting/remoting_source_impl.cc |
index 73c372f68673518e429677979a24dbd83fd66864..e2ab82fd76a76b7ba4b4cc44797babaf653f43ca 100644 |
--- a/media/remoting/remoting_controller.cc |
+++ b/media/remoting/remoting_source_impl.cc |
@@ -2,271 +2,225 @@ |
// 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) { |
+ : 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()))); |
+ rpc_broker_.reset(new remoting::RpcBroker( |
miu
2016/11/05 04:05:16
Please move this to the initializer list.
xjz
2016/11/07 19:03:55
Done.
|
+ base::Bind(&RemotingSourceImpl::OnSendMessageToSink, this))); |
} |
-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"; |
miu
2016/11/05 04:05:16
We should shut down remoting if a message is corru
xjz
2016/11/07 19:03:55
Done.
|
return; |
} |
- |
rpc_broker_->ProcessMessageFromRemote(std::move(rpc)); |
} |
-void RemotingController::OnStopped(mojom::RemotingStopReason reason) { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
+void RemotingSourceImpl::UpdateAndNotifyState(RemotingSessionState state) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- VLOG(1) << "Remoting stopped: " << reason; |
- is_remoting_ = false; |
-} |
- |
-void RemotingController::OnEnteredFullscreen() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- 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()); |
- |
- has_video_ = metadata.has_video; |
- has_audio_ = metadata.has_audio; |
- if (!has_video_ && !has_audio_) |
- return; |
+void RemotingSourceImpl::RemoveClient(Client* client) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- // 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. |
- |
- // Demuxer is not initialized yet. |
- if (!has_audio_ && !has_video_) |
- return; |
- |
- DCHECK(!switch_renderer_cb_.is_null()); |
+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()); |
- bool should_be_remoting = ShouldBeRemoting(); |
- if (is_remoting_ == should_be_remoting) |
+ 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; |
- |
- // 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); |
} |
+ 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> RemotingSourceImpl::GetRpcBroker() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ return rpc_broker_->GetWeakPtr(); |
+} |
+void RemotingSourceImpl::OnSendMessageToSink( |
miu
2016/11/05 04:05:16
naming nit: Just "SendMessageToSink()" since this
xjz
2016/11/07 19:03:55
Done.
|
+ std::unique_ptr<std::vector<uint8_t>> message) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ remoter_->SendMessageToSink(*message); |
} |
} // namespace media |