Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(450)

Side by Side Diff: media/remoting/remoting_renderer_controller.cc

Issue 2406483002: WIP - Add EME (Closed)
Patch Set: Addressed miu's comments. Added more tests. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_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/single_thread_task_runner.h" 9 #include "base/threading/thread_checker.h"
10 #include "media/remoting/remoting_cdm.h"
10 11
11 namespace media { 12 namespace media {
12 13
13 RemotingController::RemotingController( 14 RemotingRendererController::RemotingRendererController(
14 mojom::RemotingSourceRequest source_request, 15 scoped_refptr<RemotingSourceImpl> remoting_source)
15 mojom::RemoterPtr remoter) 16 : remoting_source_(remoting_source), weak_factory_(this) {
16 : binding_(this, std::move(source_request)), 17 remoting_source_->AddClient(this);
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 } 18 }
29 19
30 void RemotingController::OnSinkGone() { 20 RemotingRendererController::~RemotingRendererController() {
31 DCHECK(task_runner_->BelongsToCurrentThread()); 21 DCHECK(thread_checker_.CalledOnValidThread());
32 22 remoting_source_->RemoveClient(this);
33 is_sink_available_ = false;
34 UpdateAndMaybeSwitch();
35 } 23 }
36 24
37 void RemotingController::OnStarted() { 25 void RemotingRendererController::OnStarted(bool success) {
38 DCHECK(task_runner_->BelongsToCurrentThread()); 26 DCHECK(thread_checker_.CalledOnValidThread());
39 27
40 VLOG(1) << "Remoting started successively."; 28 DCHECK(!switch_renderer_cb_.is_null());
41 if (is_remoting_) 29 if (success) {
42 switch_renderer_cb_.Run(); 30 VLOG(1) << "Remoting started successively.";
43 else 31 if (remote_rendering_started_)
44 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); 32 switch_renderer_cb_.Run();
33 else
34 remoting_source_->StopRemoting(this);
35 } else {
36 VLOG(1) << "Failed to start remoting.";
37 remote_rendering_started_ = false;
38 }
45 } 39 }
46 40
47 void RemotingController::OnStartFailed(mojom::RemotingStartFailReason reason) { 41 void RemotingRendererController::OnSessionStateChanged() {
48 DCHECK(task_runner_->BelongsToCurrentThread()); 42 DCHECK(thread_checker_.CalledOnValidThread());
49 43
50 VLOG(1) << "Failed to start remoting:" << reason; 44 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state();
51 is_remoting_ = false; 45 bool session_could_remote = session_can_remote_;
46 switch (remoting_source_->state()) {
47 case SESSION_CAN_START:
48 case SESSION_STARTING:
49 case SESSION_STARTED:
50 session_can_remote_ = true;
51 break;
52 case SESSION_STOPPING:
53 case SESSION_UNAVAILABLE:
54 case SESSION_PERMANENTLY_STOPPED:
55 session_can_remote_ = false;
56 break;
57 }
58 if (session_can_remote_ != session_could_remote)
59 UpdateAndMaybeSwitch();
52 } 60 }
53 61
54 void RemotingController::OnMessageFromSink( 62 void RemotingRendererController::OnEnteredFullscreen() {
55 const std::vector<uint8_t>& message) { 63 DCHECK(thread_checker_.CalledOnValidThread());
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 64
72 is_fullscreen_ = true; 65 is_fullscreen_ = true;
73 UpdateAndMaybeSwitch(); 66 UpdateAndMaybeSwitch();
74 } 67 }
75 68
76 void RemotingController::OnExitedFullscreen() { 69 void RemotingRendererController::OnExitedFullscreen() {
77 DCHECK(task_runner_->BelongsToCurrentThread()); 70 DCHECK(thread_checker_.CalledOnValidThread());
78 71
79 is_fullscreen_ = false; 72 is_fullscreen_ = false;
80 UpdateAndMaybeSwitch(); 73 UpdateAndMaybeSwitch();
81 } 74 }
82 75
83 void RemotingController::OnSetCdm(CdmContext* cdm_context) { 76 void RemotingRendererController::OnSetCdm(CdmContext* cdm_context) {
84 DCHECK(task_runner_->BelongsToCurrentThread()); 77 DCHECK(thread_checker_.CalledOnValidThread());
85 78
86 // TODO(xjz): Not implemented. Will add in up-coming change. 79 auto* cdm = RemotingCdm::From(cdm_context);
87 NOTIMPLEMENTED(); 80 if (!cdm)
81 return;
82
83 remoting_source_->RemoveClient(this);
84 remoting_source_ = cdm->GetRemotingSource();
85 remoting_source_->AddClient(this); // Calls OnSessionStateChanged().
86 UpdateAndMaybeSwitch();
88 } 87 }
89 88
90 void RemotingController::SetSwitchRendererCallback( 89 void RemotingRendererController::SetSwitchRendererCallback(
91 const SwitchRendererCallback& cb) { 90 const base::Closure& cb) {
92 DCHECK(task_runner_->BelongsToCurrentThread()); 91 DCHECK(thread_checker_.CalledOnValidThread());
93 DCHECK(!cb.is_null()); 92 DCHECK(!cb.is_null());
94 93
95 switch_renderer_cb_ = cb; 94 switch_renderer_cb_ = cb;
95 UpdateAndMaybeSwitch();
96 } 96 }
97 97
98 void RemotingController::OnMetadataChanged(const PipelineMetadata& metadata) { 98 void RemotingRendererController::OnMetadataChanged(
99 DCHECK(task_runner_->BelongsToCurrentThread()); 99 const PipelineMetadata& metadata) {
100 DCHECK(thread_checker_.CalledOnValidThread());
100 101
101 has_video_ = metadata.has_video; 102 has_video_ =
102 has_audio_ = metadata.has_audio; 103 metadata.has_video && metadata.video_decoder_config.IsValidConfig();
103 if (!has_video_ && !has_audio_) 104 has_audio_ =
104 return; 105 metadata.has_audio && metadata.audio_decoder_config.IsValidConfig();
105 106
106 // On Android, when using the MediaPlayerRenderer, |has_video_| and 107 is_encrypted_ = false;
107 // |has_audio_| will be true, but the respective configs will be empty.
108 // We cannot make any assumptions on the validity of configs.
109 if (has_video_) { 108 if (has_video_) {
110 video_decoder_config_ = metadata.video_decoder_config; 109 video_decoder_config_ = metadata.video_decoder_config;
111 is_encrypted_ |= video_decoder_config_.is_encrypted(); 110 is_encrypted_ |= video_decoder_config_.is_encrypted();
112 } 111 }
113 if (has_audio_) { 112 if (has_audio_) {
114 audio_decoder_config_ = metadata.audio_decoder_config; 113 audio_decoder_config_ = metadata.audio_decoder_config;
115 is_encrypted_ |= audio_decoder_config_.is_encrypted(); 114 is_encrypted_ |= audio_decoder_config_.is_encrypted();
116 } 115 }
117 UpdateAndMaybeSwitch(); 116 UpdateAndMaybeSwitch();
118 } 117 }
119 118
120 bool RemotingController::IsVideoCodecSupported() { 119 bool RemotingRendererController::IsVideoCodecSupported() {
121 DCHECK(task_runner_->BelongsToCurrentThread()); 120 DCHECK(thread_checker_.CalledOnValidThread());
122 DCHECK(has_video_); 121 DCHECK(has_video_);
123 122
124 switch (video_decoder_config_.codec()) { 123 switch (video_decoder_config_.codec()) {
125 case VideoCodec::kCodecH264: 124 case VideoCodec::kCodecH264:
126 case VideoCodec::kCodecVP8: 125 case VideoCodec::kCodecVP8:
127 return true; 126 return true;
128 default: 127 default:
129 VLOG(2) << "Remoting does not support video codec: " 128 VLOG(2) << "Remoting does not support video codec: "
130 << video_decoder_config_.codec(); 129 << video_decoder_config_.codec();
131 return false; 130 return false;
132 } 131 }
133 } 132 }
134 133
135 bool RemotingController::IsAudioCodecSupported() { 134 bool RemotingRendererController::IsAudioCodecSupported() {
136 DCHECK(task_runner_->BelongsToCurrentThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
137 DCHECK(has_audio_); 136 DCHECK(has_audio_);
138 137
139 switch (audio_decoder_config_.codec()) { 138 switch (audio_decoder_config_.codec()) {
140 case AudioCodec::kCodecAAC: 139 case AudioCodec::kCodecAAC:
141 case AudioCodec::kCodecMP3: 140 case AudioCodec::kCodecMP3:
142 case AudioCodec::kCodecPCM: 141 case AudioCodec::kCodecPCM:
143 case AudioCodec::kCodecVorbis: 142 case AudioCodec::kCodecVorbis:
144 case AudioCodec::kCodecFLAC: 143 case AudioCodec::kCodecFLAC:
145 case AudioCodec::kCodecAMR_NB: 144 case AudioCodec::kCodecAMR_NB:
146 case AudioCodec::kCodecAMR_WB: 145 case AudioCodec::kCodecAMR_WB:
147 case AudioCodec::kCodecPCM_MULAW: 146 case AudioCodec::kCodecPCM_MULAW:
148 case AudioCodec::kCodecGSM_MS: 147 case AudioCodec::kCodecGSM_MS:
149 case AudioCodec::kCodecPCM_S16BE: 148 case AudioCodec::kCodecPCM_S16BE:
150 case AudioCodec::kCodecPCM_S24BE: 149 case AudioCodec::kCodecPCM_S24BE:
151 case AudioCodec::kCodecOpus: 150 case AudioCodec::kCodecOpus:
152 case AudioCodec::kCodecEAC3: 151 case AudioCodec::kCodecEAC3:
153 case AudioCodec::kCodecPCM_ALAW: 152 case AudioCodec::kCodecPCM_ALAW:
154 case AudioCodec::kCodecALAC: 153 case AudioCodec::kCodecALAC:
155 case AudioCodec::kCodecAC3: 154 case AudioCodec::kCodecAC3:
156 return true; 155 return true;
157 default: 156 default:
158 VLOG(2) << "Remoting does not support audio codec: " 157 VLOG(2) << "Remoting does not support audio codec: "
159 << audio_decoder_config_.codec(); 158 << audio_decoder_config_.codec();
160 return false; 159 return false;
161 } 160 }
162 } 161 }
163 162
164 bool RemotingController::ShouldBeRemoting() { 163 bool RemotingRendererController::ShouldBeRemoting() {
165 DCHECK(task_runner_->BelongsToCurrentThread()); 164 DCHECK(thread_checker_.CalledOnValidThread());
166 165
167 // TODO(xjz): The control logic for EME will be added in a later CL. 166 if (!session_can_remote_)
168 if (is_encrypted_)
169 return false; 167 return false;
170 168 if (switch_renderer_cb_.is_null())
171 if (!is_sink_available_)
172 return false; 169 return false;
173 if (!is_fullscreen_) 170 if (!has_audio_ && !has_video_)
174 return false; 171 return false;
175 if (has_video_ && !IsVideoCodecSupported()) 172 if (has_video_ && !IsVideoCodecSupported())
176 return false; 173 return false;
177 if (has_audio_ && !IsAudioCodecSupported()) 174 if (has_audio_ && !IsAudioCodecSupported())
178 return false; 175 return false;
179 return true; 176
177 // Explicitly ignoring |is_fullscreen_| since all EME content should trigger
178 // the start of remoting immediately, and not later after switching into
179 // fullscreen. This is required by current technical limitations.
180 if (is_encrypted_)
181 return remoting_source_->state() == RemotingSessionState::SESSION_STARTED;
182
183 return is_fullscreen_;
180 } 184 }
181 185
182 void RemotingController::UpdateAndMaybeSwitch() { 186 void RemotingRendererController::UpdateAndMaybeSwitch() {
183 DCHECK(task_runner_->BelongsToCurrentThread()); 187 DCHECK(thread_checker_.CalledOnValidThread());
184 188
185 // TODO(xjz): The switching logic for encrypted content will be added in a 189 bool should_be_remoting = ShouldBeRemoting();
186 // later CL.
187 190
188 // Demuxer is not initialized yet. 191 // When OnSetCdm() is called, if the session that creates CDM remotely was
189 if (!has_audio_ && !has_video_) 192 // permanently terminated, we need to render the failure page.
193 if (!remote_rendering_started_ && IsTerminated() &&
194 !session_permanently_terminated_) {
195 session_permanently_terminated_ = IsTerminated();
196 DCHECK(!switch_renderer_cb_.is_null());
197 switch_renderer_cb_.Run();
198 return;
199 }
200
201 if (remote_rendering_started_ == should_be_remoting)
190 return; 202 return;
191 203
192 DCHECK(!switch_renderer_cb_.is_null()); 204 // Switch between local renderer and remoting renderer.
205 remote_rendering_started_ = should_be_remoting;
193 206
194 bool should_be_remoting = ShouldBeRemoting(); 207 if (remote_rendering_started_) {
195 if (is_remoting_ == should_be_remoting) 208 // |switch_renderer_cb_.Run()| will be called after remoting is started
196 return;
197
198 // Switch between local and remoting.
199 is_remoting_ = should_be_remoting;
200 if (is_remoting_) {
201 // |swithc_renderer_cb_.Run()| will be called after remoting is started
202 // successfully. 209 // successfully.
203 remoter_->Start(); 210 remoting_source_->StartRemoting(this);
204 } else { 211 } else {
205 switch_renderer_cb_.Run(); 212 switch_renderer_cb_.Run();
206 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK); 213 remoting_source_->StopRemoting(this);
207 } 214 }
208 } 215 }
209 216
217 bool RemotingRendererController::IsRenderingRemotely() const {
218 DCHECK(thread_checker_.CalledOnValidThread());
219
220 return remote_rendering_started_;
221 }
222
223 bool RemotingRendererController::IsTerminated() const {
224 DCHECK(thread_checker_.CalledOnValidThread());
225
226 return remoting_source_->state() ==
227 RemotingSessionState::SESSION_PERMANENTLY_STOPPED;
228 }
229
210 } // namespace media 230 } // namespace media
OLDNEW
« no previous file with comments | « media/remoting/remoting_renderer_controller.h ('k') | media/remoting/remoting_renderer_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698