| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/remoting/remoting_renderer_controller.h" | 5 #include "media/remoting/remoting_renderer_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/threading/thread_checker.h" | 9 #include "base/threading/thread_checker.h" |
| 10 #include "media/base/video_util.h" |
| 10 #include "media/remoting/remoting_cdm_context.h" | 11 #include "media/remoting/remoting_cdm_context.h" |
| 11 | 12 |
| 12 namespace media { | 13 namespace media { |
| 13 | 14 |
| 15 namespace { |
| 16 |
| 17 gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) { |
| 18 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270) |
| 19 return gfx::Size(natural_size.height(), natural_size.width()); |
| 20 return natural_size; |
| 21 } |
| 22 |
| 23 } // namespace |
| 24 |
| 14 RemotingRendererController::RemotingRendererController( | 25 RemotingRendererController::RemotingRendererController( |
| 15 scoped_refptr<RemotingSourceImpl> remoting_source) | 26 scoped_refptr<RemotingSourceImpl> remoting_source) |
| 16 : remoting_source_(remoting_source), weak_factory_(this) { | 27 : remoting_source_(remoting_source), weak_factory_(this) { |
| 17 remoting_source_->AddClient(this); | 28 remoting_source_->AddClient(this); |
| 18 } | 29 } |
| 19 | 30 |
| 20 RemotingRendererController::~RemotingRendererController() { | 31 RemotingRendererController::~RemotingRendererController() { |
| 21 DCHECK(thread_checker_.CalledOnValidThread()); | 32 DCHECK(thread_checker_.CalledOnValidThread()); |
| 22 remoting_source_->RemoveClient(this); | 33 remoting_source_->RemoveClient(this); |
| 23 } | 34 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 39 } | 50 } |
| 40 } | 51 } |
| 41 | 52 |
| 42 void RemotingRendererController::OnSessionStateChanged() { | 53 void RemotingRendererController::OnSessionStateChanged() { |
| 43 DCHECK(thread_checker_.CalledOnValidThread()); | 54 DCHECK(thread_checker_.CalledOnValidThread()); |
| 44 | 55 |
| 45 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state(); | 56 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state(); |
| 46 if (!sink_available_changed_cb_.is_null()) | 57 if (!sink_available_changed_cb_.is_null()) |
| 47 sink_available_changed_cb_.Run(IsRemoteSinkAvailable()); | 58 sink_available_changed_cb_.Run(IsRemoteSinkAvailable()); |
| 48 | 59 |
| 60 UpdateInterstitial(); |
| 49 UpdateAndMaybeSwitch(); | 61 UpdateAndMaybeSwitch(); |
| 50 } | 62 } |
| 51 | 63 |
| 52 bool RemotingRendererController::IsRemoteSinkAvailable() { | 64 bool RemotingRendererController::IsRemoteSinkAvailable() { |
| 53 DCHECK(thread_checker_.CalledOnValidThread()); | 65 DCHECK(thread_checker_.CalledOnValidThread()); |
| 54 | 66 |
| 55 switch (remoting_source_->state()) { | 67 switch (remoting_source_->state()) { |
| 56 case SESSION_CAN_START: | 68 case SESSION_CAN_START: |
| 57 case SESSION_STARTING: | 69 case SESSION_STARTING: |
| 58 case SESSION_STARTED: | 70 case SESSION_STARTED: |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 DCHECK(thread_checker_.CalledOnValidThread()); | 151 DCHECK(thread_checker_.CalledOnValidThread()); |
| 140 | 152 |
| 141 remoting_source_->StartDataPipe(std::move(audio_data_pipe), | 153 remoting_source_->StartDataPipe(std::move(audio_data_pipe), |
| 142 std::move(video_data_pipe), done_callback); | 154 std::move(video_data_pipe), done_callback); |
| 143 } | 155 } |
| 144 | 156 |
| 145 void RemotingRendererController::OnMetadataChanged( | 157 void RemotingRendererController::OnMetadataChanged( |
| 146 const PipelineMetadata& metadata) { | 158 const PipelineMetadata& metadata) { |
| 147 DCHECK(thread_checker_.CalledOnValidThread()); | 159 DCHECK(thread_checker_.CalledOnValidThread()); |
| 148 | 160 |
| 161 const gfx::Size old_size = pipeline_metadata_.natural_size; |
| 149 pipeline_metadata_ = metadata; | 162 pipeline_metadata_ = metadata; |
| 150 | 163 |
| 151 is_encrypted_ = false; | 164 is_encrypted_ = false; |
| 152 if (has_video()) { | 165 if (has_video()) { |
| 153 video_decoder_config_ = metadata.video_decoder_config; | 166 is_encrypted_ |= metadata.video_decoder_config.is_encrypted(); |
| 154 is_encrypted_ |= video_decoder_config_.is_encrypted(); | 167 pipeline_metadata_.natural_size = GetRotatedVideoSize( |
| 168 pipeline_metadata_.video_rotation, pipeline_metadata_.natural_size); |
| 155 } | 169 } |
| 156 if (has_audio()) { | 170 if (has_audio()) { |
| 157 audio_decoder_config_ = metadata.audio_decoder_config; | 171 is_encrypted_ |= metadata.audio_decoder_config.is_encrypted(); |
| 158 is_encrypted_ |= audio_decoder_config_.is_encrypted(); | |
| 159 } | 172 } |
| 173 |
| 174 if (pipeline_metadata_.natural_size != old_size) |
| 175 UpdateInterstitial(); |
| 176 |
| 160 UpdateAndMaybeSwitch(); | 177 UpdateAndMaybeSwitch(); |
| 161 } | 178 } |
| 162 | 179 |
| 163 bool RemotingRendererController::IsVideoCodecSupported() { | 180 bool RemotingRendererController::IsVideoCodecSupported() { |
| 164 DCHECK(thread_checker_.CalledOnValidThread()); | 181 DCHECK(thread_checker_.CalledOnValidThread()); |
| 165 DCHECK(has_video()); | 182 DCHECK(has_video()); |
| 166 | 183 |
| 167 switch (video_decoder_config_.codec()) { | 184 switch (pipeline_metadata_.video_decoder_config.codec()) { |
| 168 case VideoCodec::kCodecH264: | 185 case VideoCodec::kCodecH264: |
| 169 case VideoCodec::kCodecVP8: | 186 case VideoCodec::kCodecVP8: |
| 170 return true; | 187 return true; |
| 171 default: | 188 default: |
| 172 VLOG(2) << "Remoting does not support video codec: " | 189 VLOG(2) << "Remoting does not support video codec: " |
| 173 << video_decoder_config_.codec(); | 190 << pipeline_metadata_.video_decoder_config.codec(); |
| 174 return false; | 191 return false; |
| 175 } | 192 } |
| 176 } | 193 } |
| 177 | 194 |
| 178 bool RemotingRendererController::IsAudioCodecSupported() { | 195 bool RemotingRendererController::IsAudioCodecSupported() { |
| 179 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
| 180 DCHECK(has_audio()); | 197 DCHECK(has_audio()); |
| 181 | 198 |
| 182 switch (audio_decoder_config_.codec()) { | 199 switch (pipeline_metadata_.audio_decoder_config.codec()) { |
| 183 case AudioCodec::kCodecAAC: | 200 case AudioCodec::kCodecAAC: |
| 184 case AudioCodec::kCodecMP3: | 201 case AudioCodec::kCodecMP3: |
| 185 case AudioCodec::kCodecPCM: | 202 case AudioCodec::kCodecPCM: |
| 186 case AudioCodec::kCodecVorbis: | 203 case AudioCodec::kCodecVorbis: |
| 187 case AudioCodec::kCodecFLAC: | 204 case AudioCodec::kCodecFLAC: |
| 188 case AudioCodec::kCodecAMR_NB: | 205 case AudioCodec::kCodecAMR_NB: |
| 189 case AudioCodec::kCodecAMR_WB: | 206 case AudioCodec::kCodecAMR_WB: |
| 190 case AudioCodec::kCodecPCM_MULAW: | 207 case AudioCodec::kCodecPCM_MULAW: |
| 191 case AudioCodec::kCodecGSM_MS: | 208 case AudioCodec::kCodecGSM_MS: |
| 192 case AudioCodec::kCodecPCM_S16BE: | 209 case AudioCodec::kCodecPCM_S16BE: |
| 193 case AudioCodec::kCodecPCM_S24BE: | 210 case AudioCodec::kCodecPCM_S24BE: |
| 194 case AudioCodec::kCodecOpus: | 211 case AudioCodec::kCodecOpus: |
| 195 case AudioCodec::kCodecEAC3: | 212 case AudioCodec::kCodecEAC3: |
| 196 case AudioCodec::kCodecPCM_ALAW: | 213 case AudioCodec::kCodecPCM_ALAW: |
| 197 case AudioCodec::kCodecALAC: | 214 case AudioCodec::kCodecALAC: |
| 198 case AudioCodec::kCodecAC3: | 215 case AudioCodec::kCodecAC3: |
| 199 return true; | 216 return true; |
| 200 default: | 217 default: |
| 201 VLOG(2) << "Remoting does not support audio codec: " | 218 VLOG(2) << "Remoting does not support audio codec: " |
| 202 << audio_decoder_config_.codec(); | 219 << pipeline_metadata_.audio_decoder_config.codec(); |
| 203 return false; | 220 return false; |
| 204 } | 221 } |
| 205 } | 222 } |
| 206 | 223 |
| 207 void RemotingRendererController::OnPlaying() { | 224 void RemotingRendererController::OnPlaying() { |
| 208 DCHECK(thread_checker_.CalledOnValidThread()); | 225 DCHECK(thread_checker_.CalledOnValidThread()); |
| 209 | 226 |
| 210 is_paused_ = false; | 227 is_paused_ = false; |
| 211 UpdateAndMaybeSwitch(); | 228 UpdateAndMaybeSwitch(); |
| 212 } | 229 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 // For encrypted content, it's only valid to switch to remoting renderer, | 319 // For encrypted content, it's only valid to switch to remoting renderer, |
| 303 // and never back to the local renderer. The RemotingCdmController will | 320 // and never back to the local renderer. The RemotingCdmController will |
| 304 // force-stop the session when remoting has ended; so no need to call | 321 // force-stop the session when remoting has ended; so no need to call |
| 305 // StopRemoting() from here. | 322 // StopRemoting() from here. |
| 306 DCHECK(!is_encrypted_); | 323 DCHECK(!is_encrypted_); |
| 307 switch_renderer_cb_.Run(); | 324 switch_renderer_cb_.Run(); |
| 308 remoting_source_->StopRemoting(this); | 325 remoting_source_->StopRemoting(this); |
| 309 } | 326 } |
| 310 } | 327 } |
| 311 | 328 |
| 329 void RemotingRendererController::SetShowInterstitialCallback( |
| 330 const ShowInterstitialCallback& cb) { |
| 331 DCHECK(thread_checker_.CalledOnValidThread()); |
| 332 show_interstitial_cb_ = cb; |
| 333 UpdateInterstitial(); |
| 334 } |
| 335 |
| 336 void RemotingRendererController::UpdateInterstitial() { |
| 337 DCHECK(thread_checker_.CalledOnValidThread()); |
| 338 if (show_interstitial_cb_.is_null() || |
| 339 pipeline_metadata_.natural_size.IsEmpty()) |
| 340 return; |
| 341 |
| 342 RemotingInterstitialType type = RemotingInterstitialType::BETWEEN_SESSIONS; |
| 343 switch (remoting_source_->state()) { |
| 344 case SESSION_STARTED: |
| 345 type = RemotingInterstitialType::IN_SESSION; |
| 346 break; |
| 347 case SESSION_PERMANENTLY_STOPPED: |
| 348 type = RemotingInterstitialType::ENCRYPTED_MEDIA_FATAL_ERROR; |
| 349 break; |
| 350 case SESSION_UNAVAILABLE: |
| 351 case SESSION_CAN_START: |
| 352 case SESSION_STARTING: |
| 353 case SESSION_STOPPING: |
| 354 break; |
| 355 } |
| 356 |
| 357 // TODO(xjz): Download poster image when available. |
| 358 show_interstitial_cb_.Run(SkBitmap(), pipeline_metadata_.natural_size, type); |
| 359 } |
| 360 |
| 312 } // namespace media | 361 } // namespace media |
| OLD | NEW |