Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/remoting_controller.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/single_thread_task_runner.h" | |
| 10 | |
| 11 namespace media { | |
| 12 | |
| 13 RemotingController::RemotingController( | |
| 14 mojom::RemotingSourceRequest source_request, | |
| 15 mojom::RemoterPtr remoter) | |
| 16 : binding_(this, std::move(source_request)), | |
| 17 remoter_(std::move(remoter)), | |
| 18 task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 19 weak_factory_(this) {} | |
| 20 | |
| 21 RemotingController::~RemotingController() {} | |
| 22 | |
| 23 void RemotingController::OnSinkAvailable() { | |
| 24 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 25 | |
| 26 is_sink_available_ = true; | |
| 27 UpdateAndMaybeSwitch(); | |
| 28 } | |
| 29 | |
| 30 void RemotingController::OnSinkGone() { | |
| 31 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 32 | |
| 33 is_sink_available_ = false; | |
| 34 UpdateAndMaybeSwitch(); | |
| 35 } | |
| 36 | |
| 37 void RemotingController::OnStarted() { | |
| 38 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 39 | |
| 40 VLOG(1) << "Remoting started successively."; | |
| 41 if (is_remoting_) | |
| 42 switch_renderer_cb_.Run(); | |
| 43 else | |
| 44 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); | |
| 45 } | |
| 46 | |
| 47 void RemotingController::OnStartFailed(mojom::RemotingStartFailReason reason) { | |
| 48 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 49 | |
| 50 VLOG(1) << "Failed to start remoting:" << reason; | |
| 51 is_remoting_ = false; | |
| 52 } | |
| 53 | |
| 54 void RemotingController::OnMessageFromSink( | |
| 55 const std::vector<uint8_t>& message) { | |
| 56 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 57 | |
| 58 // TODO(xjz): Merge with Eric's CL to handle the RPC messages here. | |
| 59 NOTIMPLEMENTED(); | |
| 60 } | |
| 61 | |
| 62 void RemotingController::OnStopped(mojom::RemotingStopReason reason) { | |
| 63 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 64 | |
| 65 VLOG(1) << "Remoting stopped: " << reason; | |
| 66 is_remoting_ = false; | |
| 67 } | |
| 68 | |
| 69 void RemotingController::OnEnteredFullscreen() { | |
| 70 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 71 | |
| 72 is_fullscreen_ = true; | |
| 73 UpdateAndMaybeSwitch(); | |
| 74 } | |
| 75 | |
| 76 void RemotingController::OnExitedFullscreen() { | |
| 77 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 78 | |
| 79 is_fullscreen_ = false; | |
| 80 UpdateAndMaybeSwitch(); | |
| 81 } | |
| 82 | |
| 83 void RemotingController::OnSetCdm(CdmContext* cdm_context) { | |
| 84 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 85 | |
| 86 // TODO(xjz): Not implemented. Will add in up-coming change. | |
| 87 NOTIMPLEMENTED(); | |
| 88 } | |
| 89 | |
| 90 void RemotingController::SetSwitchRendererCallback( | |
| 91 const SwitchRendererCallback& cb) { | |
| 92 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 93 DCHECK(!cb.is_null()); | |
| 94 | |
| 95 switch_renderer_cb_ = cb; | |
| 96 } | |
| 97 | |
| 98 void RemotingController::OnMetadata(const PipelineMetadata& metadata) { | |
| 99 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 100 | |
| 101 has_video_ = metadata.has_video; | |
| 102 has_audio_ = metadata.has_audio; | |
| 103 if (!has_video_ && !has_audio_) | |
| 104 return; | |
| 105 | |
| 106 if (has_video_) { | |
| 107 DCHECK(metadata.video_decoder_config.IsValidConfig()); | |
| 108 video_decoder_config_ = metadata.video_decoder_config; | |
| 109 } | |
| 110 if (has_audio_) { | |
| 111 DCHECK(metadata.audio_decoder_config.IsValidConfig()); | |
| 112 audio_decoder_config_ = metadata.audio_decoder_config; | |
| 113 } | |
| 114 UpdateAndMaybeSwitch(); | |
| 115 } | |
| 116 | |
| 117 bool RemotingController::IsVideoConfigSupported() { | |
| 118 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 119 DCHECK(has_video_); | |
| 120 | |
| 121 switch (video_decoder_config_.codec()) { | |
| 122 case VideoCodec::kCodecH264: | |
| 123 case VideoCodec::kCodecVP8: | |
| 124 return true; | |
| 125 default: | |
| 126 VLOG(2) << "Remoting does not support video codec: " | |
| 127 << video_decoder_config_.codec(); | |
| 128 return false; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 bool RemotingController::IsAudioConfigSupported() { | |
| 133 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 134 DCHECK(has_audio_); | |
| 135 | |
| 136 switch (audio_decoder_config_.codec()) { | |
| 137 case AudioCodec::kCodecAAC: | |
| 138 case AudioCodec::kCodecMP3: | |
| 139 case AudioCodec::kCodecPCM: | |
| 140 case AudioCodec::kCodecVorbis: | |
| 141 case AudioCodec::kCodecFLAC: | |
| 142 case AudioCodec::kCodecAMR_NB: | |
| 143 case AudioCodec::kCodecAMR_WB: | |
| 144 case AudioCodec::kCodecPCM_MULAW: | |
| 145 case AudioCodec::kCodecGSM_MS: | |
| 146 case AudioCodec::kCodecPCM_S16BE: | |
| 147 case AudioCodec::kCodecPCM_S24BE: | |
| 148 case AudioCodec::kCodecOpus: | |
| 149 case AudioCodec::kCodecEAC3: | |
| 150 case AudioCodec::kCodecPCM_ALAW: | |
| 151 case AudioCodec::kCodecALAC: | |
| 152 case AudioCodec::kCodecAC3: | |
| 153 return true; | |
| 154 default: | |
| 155 VLOG(2) << "Remoting does not support audio codec: " | |
| 156 << audio_decoder_config_.codec(); | |
| 157 return false; | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 bool RemotingController::ShouldBeRemoting() { | |
| 162 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 163 | |
| 164 // TODO(xjz): The control logic for EME will be added in a later CL. | |
| 165 if (video_decoder_config_.is_encrypted()) | |
|
xhwang
2016/10/05 05:27:53
How about make this check part of IsVideoConfigSup
xjz
2016/10/05 17:24:23
I would leave this check here for now. It will cha
xhwang
2016/10/05 17:36:41
Then please at least check |has_video_| before che
xjz
2016/10/05 23:39:01
Done.
| |
| 166 return false; | |
| 167 if (audio_decoder_config_.is_encrypted()) | |
| 168 return false; | |
| 169 if (!is_sink_available_) | |
| 170 return false; | |
| 171 if (!is_fullscreen_) | |
| 172 return false; | |
| 173 if (has_video_ && !IsVideoConfigSupported()) | |
| 174 return false; | |
| 175 if (has_audio_ && !IsAudioConfigSupported()) | |
| 176 return false; | |
| 177 return true; | |
| 178 } | |
| 179 | |
| 180 void RemotingController::UpdateAndMaybeSwitch() { | |
| 181 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 182 | |
| 183 // TODO(xjz): The switching logic for encrypted content will be added in a | |
| 184 // later CL. | |
| 185 | |
| 186 // Demuxer is not initialized yet. | |
| 187 if (!has_audio_ && !has_video_) | |
| 188 return; | |
| 189 | |
| 190 DCHECK(!switch_renderer_cb_.is_null()); | |
| 191 | |
| 192 bool should_be_remoting = ShouldBeRemoting(); | |
| 193 if (is_remoting_ == should_be_remoting) | |
| 194 return; | |
| 195 | |
| 196 // Switch between local and remoting. | |
| 197 is_remoting_ = should_be_remoting; | |
| 198 if (is_remoting_) { | |
| 199 // |swithc_renderer_cb_.Run()| will be called after remoting is started | |
| 200 // successfully. | |
| 201 remoter_->Start(); | |
| 202 } else { | |
| 203 switch_renderer_cb_.Run(); | |
| 204 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 } // namespace media | |
| OLD | NEW |