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

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

Issue 2406483002: WIP - Add EME (Closed)
Patch Set: Add EME. Created 4 years, 2 months 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
(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 #include "media/remoting/remoting_cdm.h"
11
12 namespace media {
13
14 RemotingController::RemotingController(
15 mojom::RemotingSourceRequest source_request,
16 mojom::RemoterPtr remoter)
17 : binding_(this, std::move(source_request)),
18 remoter_(std::move(remoter)),
19 task_runner_(base::ThreadTaskRunnerHandle::Get()),
20 weak_factory_(this) {}
21
22 RemotingController::~RemotingController() {}
23
24 void RemotingController::OnSinkAvailable() {
25 DCHECK(task_runner_->BelongsToCurrentThread());
26
27 is_sink_available_ = true;
28 UpdateAndMaybeSwitch();
29 }
30
31 void RemotingController::OnSinkGone() {
32 DCHECK(task_runner_->BelongsToCurrentThread());
33
34 is_sink_available_ = false;
35 UpdateAndMaybeSwitch();
36 }
37
38 void RemotingController::OnStarted() {
39 DCHECK(task_runner_->BelongsToCurrentThread());
40
41 VLOG(1) << "Remoting started successively.";
42
43 // |switch_renderer_cb_| not being set indicates that this remoting session
44 // is started for creating CDM.
45 if (switch_renderer_cb_.is_null()) {
46 is_remoting_cdm_ = true;
47 DCHECK(!cdm_check_cb_.is_null());
48 cdm_check_cb_.Run(true);
49 } else if (is_remoting_) {
50 switch_renderer_cb_.Run();
51 } else {
52 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK);
53 }
54 }
55
56 void RemotingController::OnStartFailed(mojom::RemotingStartFailReason reason) {
57 DCHECK(task_runner_->BelongsToCurrentThread());
58
59 VLOG(1) << "Failed to start remoting:" << reason;
60
61 is_remoting_ = false;
62 if (switch_renderer_cb_.is_null()) {
63 DCHECK(!cdm_check_cb_.is_null());
64 is_remoting_cdm_ = false;
65 cdm_check_cb_.Run(false);
66 }
67 }
68
69 void RemotingController::OnMessageFromSink(
70 const std::vector<uint8_t>& message) {
71 DCHECK(task_runner_->BelongsToCurrentThread());
72
73 // TODO(xjz): Merge with Eric's CL to handle the RPC messages here.
74 NOTIMPLEMENTED();
75 }
76
77 void RemotingController::OnStopped(mojom::RemotingStopReason reason) {
78 DCHECK(task_runner_->BelongsToCurrentThread());
79
80 VLOG(1) << "Remoting stopped: " << reason;
81
82 is_remoting_ = false;
83 if (is_remoting_cdm_)
84 is_remoting_failed_ = true;
85 }
86
87 void RemotingController::OnEnteredFullscreen() {
88 DCHECK(task_runner_->BelongsToCurrentThread());
89
90 is_fullscreen_ = true;
91 UpdateAndMaybeSwitch();
92 }
93
94 void RemotingController::OnExitedFullscreen() {
95 DCHECK(task_runner_->BelongsToCurrentThread());
96
97 is_fullscreen_ = false;
98 UpdateAndMaybeSwitch();
99 }
100
101 void RemotingController::OnSetCdm(CdmContext* cdm_context) {
102 DCHECK(task_runner_->BelongsToCurrentThread());
103
104 if (auto* cdm = RemotingCdm::From(cdm_context)) {
miu 2016/10/08 01:06:16 Possible edge-case issue: What if a remoting sessi
xjz 2016/10/20 21:25:28 This seems not a problem now. If a remoting sessio
105 cdm_remoting_controller_ = cdm->remoting_controller();
106 if (!cdm_remoting_controller_)
107 return;
108 cdm_remoting_controller_->SetSwitchRendererCallback(switch_renderer_cb_);
109 // This may trigger the switching renderer call in
110 // |cdm_remoting_controller_|.
111 cdm_remoting_controller_->OnMetadataChanged(metadata_);
112 }
113 }
114
115 void RemotingController::SetSwitchRendererCallback(
116 const SwitchRendererCallback& cb) {
117 DCHECK(task_runner_->BelongsToCurrentThread());
118 DCHECK(!cb.is_null());
119
120 switch_renderer_cb_ = cb;
121 }
122
123 void RemotingController::OnMetadataChanged(const PipelineMetadata& metadata) {
124 DCHECK(task_runner_->BelongsToCurrentThread());
125
126 if (cdm_remoting_controller_) {
127 cdm_remoting_controller_->OnMetadataChanged(metadata);
128 return;
129 }
130
131 metadata_ = metadata;
132 has_video_ = metadata.has_video;
133 has_audio_ = metadata.has_audio;
134 if (!has_video_ && !has_audio_)
135 return;
136
137 if (has_video_) {
138 DCHECK(metadata.video_decoder_config.IsValidConfig());
139 video_decoder_config_ = metadata.video_decoder_config;
140 is_encrypted_ |= video_decoder_config_.is_encrypted();
141 }
142 if (has_audio_) {
143 DCHECK(metadata.audio_decoder_config.IsValidConfig());
144 audio_decoder_config_ = metadata.audio_decoder_config;
145 is_encrypted_ |= audio_decoder_config_.is_encrypted();
146 }
147 UpdateAndMaybeSwitch();
148 }
149
150 bool RemotingController::IsVideoCodecSupported() {
151 DCHECK(task_runner_->BelongsToCurrentThread());
152 DCHECK(has_video_);
153
154 switch (video_decoder_config_.codec()) {
155 case VideoCodec::kCodecH264:
156 case VideoCodec::kCodecVP8:
157 return true;
158 default:
159 VLOG(2) << "Remoting does not support video codec: "
160 << video_decoder_config_.codec();
161 return false;
162 }
163 }
164
165 bool RemotingController::IsAudioCodecSupported() {
166 DCHECK(task_runner_->BelongsToCurrentThread());
167 DCHECK(has_audio_);
168
169 switch (audio_decoder_config_.codec()) {
170 case AudioCodec::kCodecAAC:
171 case AudioCodec::kCodecMP3:
172 case AudioCodec::kCodecPCM:
173 case AudioCodec::kCodecVorbis:
174 case AudioCodec::kCodecFLAC:
175 case AudioCodec::kCodecAMR_NB:
176 case AudioCodec::kCodecAMR_WB:
177 case AudioCodec::kCodecPCM_MULAW:
178 case AudioCodec::kCodecGSM_MS:
179 case AudioCodec::kCodecPCM_S16BE:
180 case AudioCodec::kCodecPCM_S24BE:
181 case AudioCodec::kCodecOpus:
182 case AudioCodec::kCodecEAC3:
183 case AudioCodec::kCodecPCM_ALAW:
184 case AudioCodec::kCodecALAC:
185 case AudioCodec::kCodecAC3:
186 return true;
187 default:
188 VLOG(2) << "Remoting does not support audio codec: "
189 << audio_decoder_config_.codec();
190 return false;
191 }
192 }
193
194 bool RemotingController::ShouldBeRemoting() {
195 DCHECK(task_runner_->BelongsToCurrentThread());
196
197 if (has_video_ && !IsVideoCodecSupported())
198 return false;
199 if (has_audio_ && !IsAudioCodecSupported())
200 return false;
201
202 if (is_encrypted_) {
203 DCHECK(!cdm_remoting_controller_);
204 return is_remoting_cdm_ && is_sink_available_;
205 }
206
207 if (!is_sink_available_)
208 return false;
209 if (!is_fullscreen_)
210 return false;
211 return true;
212 }
213
214 void RemotingController::UpdateAndMaybeSwitch() {
215 DCHECK(task_runner_->BelongsToCurrentThread());
216
217 // Demuxer is not initialized yet.
218 if (!has_audio_ && !has_video_)
219 return;
220
221 // This RemotingController is created when creating CDM, and is not attached
222 // to media element yet.
223 if (switch_renderer_cb_.is_null())
224 return;
225
226 // When cdm is attached, renderer switching will only happen in
227 // |cdm_remoting_controller_| instead of here.
228 if (cdm_remoting_controller_)
229 return;
230
231 // Remoting was failed and is not able to be restarted until user explicitly
232 // reloads the page.
233 if (is_remoting_failed_)
234 return;
235
236 bool should_be_remoting = ShouldBeRemoting();
237 if (is_remoting_ == should_be_remoting)
238 return;
239
240 // Switch between local renderer and remoting renderer.
241 is_remoting_ = should_be_remoting;
242 if (is_remoting_) {
243 if (!is_remoting_cdm_)
244 // |swithc_renderer_cb_.Run()| will be called after remoting is started
245 // successfully for non-encrypted contents.
246 remoter_->Start();
247 else
248 // Remoting was already started for encrypted contents. Calling
249 // |switch_renderer_cb_| to switch to remoting renderer.
250 switch_renderer_cb_.Run();
251 } else {
252 switch_renderer_cb_.Run();
253 remoter_->Stop(mojom::RemotingStopReason::LOCAL_PLAYBACK);
254 if (is_remoting_cdm_)
255 // This is also set in OnStopped().
256 is_remoting_failed_ = true;
257 }
258 }
259
260 void RemotingController::ShouldCreateRemotingCdm(const CdmCheckCallback& cb) {
261 DCHECK(task_runner_->BelongsToCurrentThread());
262 DCHECK(!cb.is_null());
263 DCHECK(switch_renderer_cb_.is_null());
264
265 cdm_check_cb_ = cb;
266 if (!is_sink_available_) {
267 cdm_check_cb_.Run(false);
miu 2016/10/08 01:06:16 What if the sink becomes available later? Say, in
xjz 2016/10/20 21:25:28 Can we just consider simple case? If the sink is n
268 is_remoting_cdm_ = false;
269 } else {
270 // Will run |cdm_check_cb_| in OnStarted() or OnStartFailed.
271 remoter_->Start();
272 }
273 }
274
275 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698