Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/blink/webmediaplayer_impl.h" | 5 #include "media/blink/webmediaplayer_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 media_task_runner_(params.media_task_runner()), | 193 media_task_runner_(params.media_task_runner()), |
| 194 worker_task_runner_(params.worker_task_runner()), | 194 worker_task_runner_(params.worker_task_runner()), |
| 195 media_log_(params.media_log()), | 195 media_log_(params.media_log()), |
| 196 pipeline_(media_task_runner_, media_log_.get()), | 196 pipeline_(media_task_runner_, media_log_.get()), |
| 197 pipeline_controller_( | 197 pipeline_controller_( |
| 198 &pipeline_, | 198 &pipeline_, |
| 199 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | 199 base::Bind(&WebMediaPlayerImpl::CreateRenderer, |
| 200 base::Unretained(this)), | 200 base::Unretained(this)), |
| 201 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), | 201 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), |
| 202 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), | 202 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), |
| 203 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()), | |
| 204 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()), | |
| 203 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())), | 205 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())), |
| 204 load_type_(LoadTypeURL), | 206 load_type_(LoadTypeURL), |
| 205 opaque_(false), | 207 opaque_(false), |
| 206 playback_rate_(0.0), | 208 playback_rate_(0.0), |
| 207 paused_(true), | 209 paused_(true), |
| 208 paused_when_hidden_(false), | 210 paused_when_hidden_(false), |
| 209 seeking_(false), | 211 seeking_(false), |
| 210 pending_suspend_resume_cycle_(false), | 212 pending_suspend_resume_cycle_(false), |
| 211 ended_(false), | 213 ended_(false), |
| 212 should_notify_time_changed_(false), | 214 should_notify_time_changed_(false), |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 467 // incorrectly discard what it thinks is a seek to the existing time. | 469 // incorrectly discard what it thinks is a seek to the existing time. |
| 468 paused_time_ = | 470 paused_time_ = |
| 469 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | 471 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); |
| 470 | 472 |
| 471 if (observer_) | 473 if (observer_) |
| 472 observer_->OnPaused(); | 474 observer_->OnPaused(); |
| 473 | 475 |
| 474 DCHECK(watch_time_reporter_); | 476 DCHECK(watch_time_reporter_); |
| 475 watch_time_reporter_->OnPaused(); | 477 watch_time_reporter_->OnPaused(); |
| 476 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 478 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
| 479 | |
| 477 UpdatePlayState(); | 480 UpdatePlayState(); |
| 478 } | 481 } |
| 479 | 482 |
| 480 bool WebMediaPlayerImpl::supportsSave() const { | 483 bool WebMediaPlayerImpl::supportsSave() const { |
| 481 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 484 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 482 return supports_save_; | 485 return supports_save_; |
| 483 } | 486 } |
| 484 | 487 |
| 485 void WebMediaPlayerImpl::seek(double seconds) { | 488 void WebMediaPlayerImpl::seek(double seconds) { |
| 486 DVLOG(1) << __func__ << "(" << seconds << "s)"; | 489 DVLOG(1) << __func__ << "(" << seconds << "s)"; |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 664 << "]"; | 667 << "]"; |
| 665 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds); | 668 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds); |
| 666 } | 669 } |
| 667 | 670 |
| 668 void WebMediaPlayerImpl::selectedVideoTrackChanged( | 671 void WebMediaPlayerImpl::selectedVideoTrackChanged( |
| 669 blink::WebMediaPlayer::TrackId* selectedTrackId) { | 672 blink::WebMediaPlayer::TrackId* selectedTrackId) { |
| 670 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 673 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 671 | 674 |
| 672 std::ostringstream logstr; | 675 std::ostringstream logstr; |
| 673 std::vector<MediaTrack::Id> selectedVideoMediaTrackId; | 676 std::vector<MediaTrack::Id> selectedVideoMediaTrackId; |
| 674 bool canAddVideoTrack = | 677 if (selectedTrackId && !video_track_disabled_) { |
| 675 !IsBackgroundVideoTrackOptimizationEnabled() || !IsHidden(); | |
| 676 if (selectedTrackId && canAddVideoTrack) { | |
| 677 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data()); | 678 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data()); |
| 678 logstr << selectedVideoMediaTrackId[0]; | 679 logstr << selectedVideoMediaTrackId[0]; |
| 679 } | 680 } |
| 680 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str() | 681 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str() |
| 681 << "]"; | 682 << "]"; |
| 682 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId); | 683 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId); |
| 683 } | 684 } |
| 684 | 685 |
| 685 blink::WebSize WebMediaPlayerImpl::naturalSize() const { | 686 blink::WebSize WebMediaPlayerImpl::naturalSize() const { |
| 686 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 687 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1057 set_cdm_result_->completeWithError( | 1058 set_cdm_result_->completeWithError( |
| 1058 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 1059 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
| 1059 "Unable to set ContentDecryptionModule object"); | 1060 "Unable to set ContentDecryptionModule object"); |
| 1060 set_cdm_result_.reset(); | 1061 set_cdm_result_.reset(); |
| 1061 } | 1062 } |
| 1062 } | 1063 } |
| 1063 | 1064 |
| 1064 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { | 1065 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { |
| 1065 seeking_ = false; | 1066 seeking_ = false; |
| 1066 seek_time_ = base::TimeDelta(); | 1067 seek_time_ = base::TimeDelta(); |
| 1068 | |
| 1067 if (paused_) { | 1069 if (paused_) { |
| 1068 #if defined(OS_ANDROID) // WMPI_CAST | 1070 #if defined(OS_ANDROID) // WMPI_CAST |
| 1069 if (isRemote()) { | 1071 if (isRemote()) { |
| 1070 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime()); | 1072 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime()); |
| 1071 } else { | 1073 } else { |
| 1072 paused_time_ = pipeline_.GetMediaTime(); | 1074 paused_time_ = pipeline_.GetMediaTime(); |
| 1073 } | 1075 } |
| 1074 #else | 1076 #else |
| 1075 paused_time_ = pipeline_.GetMediaTime(); | 1077 paused_time_ = pipeline_.GetMediaTime(); |
| 1076 #endif | 1078 #endif |
| 1077 } else { | 1079 } else { |
| 1078 DCHECK(watch_time_reporter_); | 1080 DCHECK(watch_time_reporter_); |
| 1079 watch_time_reporter_->OnPlaying(); | 1081 watch_time_reporter_->OnPlaying(); |
| 1080 } | 1082 } |
| 1081 if (time_updated) | 1083 if (time_updated) |
| 1082 should_notify_time_changed_ = true; | 1084 should_notify_time_changed_ = true; |
| 1083 | 1085 |
| 1084 // Reset underflow count upon seek; this prevents looping videos and user | 1086 // Reset underflow count upon seek; this prevents looping videos and user |
| 1085 // actions from artificially inflating the underflow count. | 1087 // actions from artificially inflating the underflow count. |
| 1086 underflow_count_ = 0; | 1088 underflow_count_ = 0; |
| 1089 | |
| 1090 // Apply optimizations for the hidden videos if hidden. | |
| 1091 if (IsHidden()) | |
| 1092 OnHidden(); | |
|
sandersd (OOO until July 31)
2017/01/10 21:34:37
OnHidden() does a bit more than what is requested,
whywhat
2017/01/11 19:41:30
I think that's the point of it, no? We initialize
sandersd (OOO until July 31)
2017/01/11 21:54:51
The target state for this code is that OnHidden()
| |
| 1087 } | 1093 } |
| 1088 | 1094 |
| 1089 void WebMediaPlayerImpl::OnPipelineSuspended() { | 1095 void WebMediaPlayerImpl::OnPipelineSuspended() { |
| 1090 #if defined(OS_ANDROID) | 1096 #if defined(OS_ANDROID) |
| 1091 if (isRemote()) { | 1097 if (isRemote()) { |
| 1092 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1098 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 1093 if (frame) | 1099 if (frame) |
| 1094 compositor_->PaintSingleFrame(frame); | 1100 compositor_->PaintSingleFrame(frame); |
| 1095 } | 1101 } |
| 1096 #endif | 1102 #endif |
| 1097 | 1103 |
| 1098 // If we're not in an aggressive buffering state, tell the data source we have | 1104 // If we're not in an aggressive buffering state, tell the data source we have |
| 1099 // enough data so that it may release the connection. | 1105 // enough data so that it may release the connection. |
| 1100 if (buffering_strategy_ != | 1106 if (buffering_strategy_ != |
| 1101 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { | 1107 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { |
| 1102 if (data_source_) | 1108 if (data_source_) |
| 1103 data_source_->OnBufferingHaveEnough(true); | 1109 data_source_->OnBufferingHaveEnough(true); |
| 1104 } | 1110 } |
| 1105 | 1111 |
| 1106 ReportMemoryUsage(); | 1112 ReportMemoryUsage(); |
| 1107 | 1113 |
| 1108 if (pending_suspend_resume_cycle_) { | 1114 if (pending_suspend_resume_cycle_) { |
| 1109 pending_suspend_resume_cycle_ = false; | 1115 pending_suspend_resume_cycle_ = false; |
| 1110 UpdatePlayState(); | 1116 UpdatePlayState(); |
| 1111 } | 1117 } |
| 1112 } | 1118 } |
| 1113 | 1119 |
| 1120 void WebMediaPlayerImpl::OnBeforePipelineResume() { | |
| 1121 // Enable video track if we disabled it in the background - this way the new | |
| 1122 // renderer will attach its callbacks to the video stream properly. | |
| 1123 // TODO(avayvod): Remove this when disabling and enabling video tracks in | |
| 1124 // non-playing state works correctly. See https://crbug.com/678374. | |
| 1125 EnableVideoTrackIfNeeded(); | |
| 1126 is_pipeline_resuming_ = true; | |
| 1127 } | |
| 1128 | |
| 1129 void WebMediaPlayerImpl::OnPipelineResumed() { | |
| 1130 is_pipeline_resuming_ = false; | |
| 1131 | |
| 1132 if (IsHidden()) { | |
| 1133 DisableVideoTrackIfNeeded(); | |
| 1134 return; | |
|
sandersd (OOO until July 31)
2017/01/10 21:34:37
Nit: This may be a case where early return is more
whywhat
2017/01/11 19:41:30
Done. For some reason, I expect lint to complain t
| |
| 1135 } | |
| 1136 | |
| 1137 EnableVideoTrackIfNeeded(); | |
| 1138 } | |
| 1139 | |
| 1114 void WebMediaPlayerImpl::OnDemuxerOpened() { | 1140 void WebMediaPlayerImpl::OnDemuxerOpened() { |
| 1115 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1141 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1116 client_->mediaSourceOpened( | 1142 client_->mediaSourceOpened( |
| 1117 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); | 1143 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); |
| 1118 } | 1144 } |
| 1119 | 1145 |
| 1120 void WebMediaPlayerImpl::OnError(PipelineStatus status) { | 1146 void WebMediaPlayerImpl::OnError(PipelineStatus status) { |
| 1121 DVLOG(1) << __func__; | 1147 DVLOG(1) << __func__; |
| 1122 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1148 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1123 DCHECK_NE(status, PIPELINE_OK); | 1149 DCHECK_NE(status, PIPELINE_OK); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1346 if (video_weblayer_) | 1372 if (video_weblayer_) |
| 1347 video_weblayer_->layer()->SetContentsOpaque(opaque_); | 1373 video_weblayer_->layer()->SetContentsOpaque(opaque_); |
| 1348 } | 1374 } |
| 1349 | 1375 |
| 1350 void WebMediaPlayerImpl::OnHidden() { | 1376 void WebMediaPlayerImpl::OnHidden() { |
| 1351 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1377 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1352 | 1378 |
| 1353 if (watch_time_reporter_) | 1379 if (watch_time_reporter_) |
| 1354 watch_time_reporter_->OnHidden(); | 1380 watch_time_reporter_->OnHidden(); |
| 1355 | 1381 |
| 1356 if (!IsStreaming() && IsBackgroundVideoTrackOptimizationEnabled()) { | 1382 if (!paused_when_hidden_ && ShouldPauseWhenHidden()) { |
|
sandersd (OOO until July 31)
2017/01/10 21:34:37
As a matter of style, I prefer idempotency whereve
whywhat
2017/01/11 19:41:30
I think it won't because ShouldPauseWhenHidden and
| |
| 1357 if (ShouldPauseWhenHidden()) { | 1383 // OnPause() will set |paused_when_hidden_| to false and call |
| 1358 // OnPause() will set |paused_when_hidden_| to false and call | 1384 // UpdatePlayState(), so set the flag to true after and then return. |
| 1359 // UpdatePlayState(), so set the flag to true after and then return. | 1385 OnPause(); |
| 1360 OnPause(); | 1386 paused_when_hidden_ = true; |
| 1361 paused_when_hidden_ = true; | 1387 return; |
| 1362 return; | 1388 } |
| 1363 } | |
| 1364 | 1389 |
| 1365 selectedVideoTrackChanged(nullptr); | 1390 DisableVideoTrackIfNeeded(); |
| 1366 } | |
| 1367 | 1391 |
| 1368 UpdatePlayState(); | 1392 UpdatePlayState(); |
| 1369 | 1393 |
| 1370 // Schedule suspended playing media to be paused if the user doesn't come back | 1394 // Schedule suspended playing media to be paused if the user doesn't come back |
| 1371 // to it within some timeout period to avoid any autoplay surprises. | 1395 // to it within some timeout period to avoid any autoplay surprises. |
| 1372 ScheduleIdlePauseTimer(); | 1396 ScheduleIdlePauseTimer(); |
| 1373 } | 1397 } |
| 1374 | 1398 |
| 1375 void WebMediaPlayerImpl::OnShown() { | 1399 void WebMediaPlayerImpl::OnShown() { |
| 1376 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1400 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1377 if (watch_time_reporter_) | 1401 if (watch_time_reporter_) |
| 1378 watch_time_reporter_->OnShown(); | 1402 watch_time_reporter_->OnShown(); |
| 1379 | 1403 |
| 1380 compositor_task_runner_->PostTask( | 1404 compositor_task_runner_->PostTask( |
| 1381 FROM_HERE, | 1405 FROM_HERE, |
| 1382 base::Bind(&VideoFrameCompositor::SetForegroundTime, | 1406 base::Bind(&VideoFrameCompositor::SetForegroundTime, |
| 1383 base::Unretained(compositor_), base::TimeTicks::Now())); | 1407 base::Unretained(compositor_), base::TimeTicks::Now())); |
| 1384 | 1408 |
| 1385 if (!IsStreaming() && IsBackgroundVideoTrackOptimizationEnabled()) { | 1409 if (paused_when_hidden_) { |
|
sandersd (OOO until July 31)
2017/01/10 21:34:37
By the same reasoning, this should go right before
whywhat
2017/01/11 19:41:30
Moved the state update above the new logic.
I don
| |
| 1386 if (paused_when_hidden_) { | 1410 paused_when_hidden_ = false; |
| 1387 paused_when_hidden_ = false; | 1411 OnPlay(); // Calls UpdatePlayState() so return afterwards. |
| 1388 OnPlay(); // Calls UpdatePlayState() so return afterwards. | 1412 return; |
| 1389 return; | 1413 } |
| 1390 } | |
| 1391 | 1414 |
| 1392 if (client_->hasSelectedVideoTrack()) { | 1415 EnableVideoTrackIfNeeded(); |
| 1393 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId(); | |
| 1394 selectedVideoTrackChanged(&trackId); | |
| 1395 } | |
| 1396 } | |
| 1397 | 1416 |
| 1398 must_suspend_ = false; | 1417 must_suspend_ = false; |
| 1399 background_pause_timer_.Stop(); | 1418 background_pause_timer_.Stop(); |
| 1400 | 1419 |
| 1401 UpdatePlayState(); | 1420 UpdatePlayState(); |
| 1402 } | 1421 } |
| 1403 | 1422 |
| 1404 bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { | 1423 bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { |
| 1405 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1424 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1406 | 1425 |
| (...skipping 666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2073 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0; | 2092 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0; |
| 2074 } | 2093 } |
| 2075 | 2094 |
| 2076 void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) { | 2095 void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) { |
| 2077 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 2096 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 2078 | 2097 |
| 2079 client_->activateViewportIntersectionMonitoring(activate); | 2098 client_->activateViewportIntersectionMonitoring(activate); |
| 2080 } | 2099 } |
| 2081 | 2100 |
| 2082 bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const { | 2101 bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const { |
| 2102 DCHECK(IsHidden()); | |
| 2103 // Don't pause videos being Cast (Android only) or if the background video | |
| 2104 // optimizations are off (desktop only). | |
| 2083 #if defined(OS_ANDROID) // WMPI_CAST | 2105 #if defined(OS_ANDROID) // WMPI_CAST |
| 2084 if (isRemote()) | 2106 if (isRemote()) |
| 2085 return false; | 2107 return false; |
| 2086 #endif // defined(OS_ANDROID) // WMPI_CAST | 2108 #else // defined(OS_ANDROID) |
| 2109 if (!IsBackgroundVideoTrackOptimizationEnabled()) | |
| 2110 return false; | |
| 2111 #endif // defined(OS_ANDROID) | |
| 2087 | 2112 |
| 2088 return hasVideo() && !hasAudio(); | 2113 return hasVideo() && !hasAudio(); |
|
sandersd (OOO until July 31)
2017/01/10 21:34:37
Probably worth a comment somewhere: these conditio
whywhat
2017/01/11 19:41:30
Should I make an even stronger comment that they w
sandersd (OOO until July 31)
2017/01/11 21:54:51
OnMetadata is called after demuxer initialization,
| |
| 2089 } | 2114 } |
| 2090 | 2115 |
| 2116 bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const { | |
| 2117 DCHECK(IsHidden()); | |
| 2118 return IsBackgroundVideoTrackOptimizationEnabled() && hasVideo() && | |
| 2119 hasAudio() && !IsStreaming(); | |
| 2120 } | |
| 2121 | |
| 2122 void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() { | |
| 2123 DCHECK(!IsHidden()); | |
| 2124 | |
| 2125 // Don't change video track while the pipeline is resuming or seeking. | |
| 2126 if (is_pipeline_resuming_ || seeking_) | |
| 2127 return; | |
| 2128 | |
| 2129 if (video_track_disabled_) { | |
| 2130 video_track_disabled_ = false; | |
| 2131 if (client_->hasSelectedVideoTrack()) { | |
| 2132 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId(); | |
| 2133 selectedVideoTrackChanged(&trackId); | |
| 2134 } | |
| 2135 } | |
| 2136 } | |
| 2137 | |
| 2138 void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() { | |
| 2139 DCHECK(IsHidden()); | |
| 2140 | |
| 2141 // Don't change video track while the pipeline is resuming or seeking. | |
| 2142 if (is_pipeline_resuming_ || seeking_) | |
| 2143 return; | |
| 2144 | |
| 2145 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) { | |
| 2146 video_track_disabled_ = true; | |
| 2147 selectedVideoTrackChanged(nullptr); | |
| 2148 } | |
| 2149 } | |
| 2150 | |
| 2091 } // namespace media | 2151 } // namespace media |
| OLD | NEW |