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

Side by Side Diff: third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp

Issue 2890633003: [Blink,RemotePlayback] Use PresentationController for availability (Closed)
Patch Set: Limited to Blink only, rebased Created 3 years, 6 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
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 "modules/remoteplayback/RemotePlayback.h" 5 #include "modules/remoteplayback/RemotePlayback.h"
6 6
7 #include "bindings/core/v8/ScriptPromiseResolver.h" 7 #include "bindings/core/v8/ScriptPromiseResolver.h"
8 #include "bindings/modules/v8/RemotePlaybackAvailabilityCallback.h" 8 #include "bindings/modules/v8/RemotePlaybackAvailabilityCallback.h"
9 #include "core/HTMLNames.h" 9 #include "core/HTMLNames.h"
10 #include "core/dom/DOMException.h" 10 #include "core/dom/DOMException.h"
11 #include "core/dom/Document.h" 11 #include "core/dom/Document.h"
12 #include "core/dom/TaskRunnerHelper.h" 12 #include "core/dom/TaskRunnerHelper.h"
13 #include "core/dom/UserGestureIndicator.h" 13 #include "core/dom/UserGestureIndicator.h"
14 #include "core/events/Event.h" 14 #include "core/events/Event.h"
15 #include "core/html/HTMLMediaElement.h" 15 #include "core/html/HTMLMediaElement.h"
16 #include "core/html/HTMLVideoElement.h" 16 #include "core/html/HTMLVideoElement.h"
17 #include "core/probe/CoreProbes.h" 17 #include "core/probe/CoreProbes.h"
18 #include "modules/EventTargetModules.h" 18 #include "modules/EventTargetModules.h"
19 #include "modules/presentation/PresentationController.h"
19 #include "modules/remoteplayback/AvailabilityCallbackWrapper.h" 20 #include "modules/remoteplayback/AvailabilityCallbackWrapper.h"
20 #include "platform/MemoryCoordinator.h" 21 #include "platform/MemoryCoordinator.h"
22 #include "platform/json/JSONValues.h"
23 #include "platform/wtf/text/Base64.h"
21 24
22 namespace blink { 25 namespace blink {
23 26
24 namespace { 27 namespace {
25 28
26 const AtomicString& RemotePlaybackStateToString(WebRemotePlaybackState state) { 29 const AtomicString& RemotePlaybackStateToString(WebRemotePlaybackState state) {
27 DEFINE_STATIC_LOCAL(const AtomicString, connecting_value, ("connecting")); 30 DEFINE_STATIC_LOCAL(const AtomicString, connecting_value, ("connecting"));
28 DEFINE_STATIC_LOCAL(const AtomicString, connected_value, ("connected")); 31 DEFINE_STATIC_LOCAL(const AtomicString, connected_value, ("connected"));
29 DEFINE_STATIC_LOCAL(const AtomicString, disconnected_value, ("disconnected")); 32 DEFINE_STATIC_LOCAL(const AtomicString, disconnected_value, ("disconnected"));
30 33
(...skipping 21 matching lines...) Expand all
52 // static 55 // static
53 RemotePlayback* RemotePlayback::Create(HTMLMediaElement& element) { 56 RemotePlayback* RemotePlayback::Create(HTMLMediaElement& element) {
54 return new RemotePlayback(element); 57 return new RemotePlayback(element);
55 } 58 }
56 59
57 RemotePlayback::RemotePlayback(HTMLMediaElement& element) 60 RemotePlayback::RemotePlayback(HTMLMediaElement& element)
58 : state_(element.IsPlayingRemotely() 61 : state_(element.IsPlayingRemotely()
59 ? WebRemotePlaybackState::kConnected 62 ? WebRemotePlaybackState::kConnected
60 : WebRemotePlaybackState::kDisconnected), 63 : WebRemotePlaybackState::kDisconnected),
61 availability_(WebRemotePlaybackAvailability::kUnknown), 64 availability_(WebRemotePlaybackAvailability::kUnknown),
62 media_element_(&element) {} 65 media_element_(&element),
66 is_listening_(false) {}
63 67
64 const AtomicString& RemotePlayback::InterfaceName() const { 68 const AtomicString& RemotePlayback::InterfaceName() const {
65 return EventTargetNames::RemotePlayback; 69 return EventTargetNames::RemotePlayback;
66 } 70 }
67 71
68 ExecutionContext* RemotePlayback::GetExecutionContext() const { 72 ExecutionContext* RemotePlayback::GetExecutionContext() const {
69 return &media_element_->GetDocument(); 73 return &media_element_->GetDocument();
70 } 74 }
71 75
72 ScriptPromise RemotePlayback::watchAvailability( 76 ScriptPromise RemotePlayback::watchAvailability(
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); 131 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
128 ScriptPromise promise = resolver->Promise(); 132 ScriptPromise promise = resolver->Promise();
129 133
130 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { 134 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) {
131 resolver->Reject(DOMException::Create( 135 resolver->Reject(DOMException::Create(
132 kInvalidStateError, "disableRemotePlayback attribute is present.")); 136 kInvalidStateError, "disableRemotePlayback attribute is present."));
133 return promise; 137 return promise;
134 } 138 }
135 139
136 availability_callbacks_.clear(); 140 availability_callbacks_.clear();
141 UpdateListeningState();
137 142
138 resolver->Resolve(); 143 resolver->Resolve();
139 return promise; 144 return promise;
140 } 145 }
141 146
142 ScriptPromise RemotePlayback::prompt(ScriptState* script_state) { 147 ScriptPromise RemotePlayback::prompt(ScriptState* script_state) {
143 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); 148 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
144 ScriptPromise promise = resolver->Promise(); 149 ScriptPromise promise = resolver->Promise();
145 150
146 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { 151 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) {
(...skipping 16 matching lines...) Expand all
163 return promise; 168 return promise;
164 } 169 }
165 170
166 if (!RuntimeEnabledFeatures::remotePlaybackBackendEnabled() || 171 if (!RuntimeEnabledFeatures::remotePlaybackBackendEnabled() ||
167 availability_ == WebRemotePlaybackAvailability::kDeviceNotAvailable) { 172 availability_ == WebRemotePlaybackAvailability::kDeviceNotAvailable) {
168 resolver->Reject(DOMException::Create(kNotFoundError, 173 resolver->Reject(DOMException::Create(kNotFoundError,
169 "No remote playback devices found.")); 174 "No remote playback devices found."));
170 return promise; 175 return promise;
171 } 176 }
172 177
178 // TODO(avayvod): none of these two states is propagated with the new
179 // pipeline.
mark a. foltz 2017/05/31 21:16:41 So kNotSupported error will not be thrown going fo
173 if (availability_ == WebRemotePlaybackAvailability::kSourceNotSupported || 180 if (availability_ == WebRemotePlaybackAvailability::kSourceNotSupported ||
174 availability_ == WebRemotePlaybackAvailability::kSourceNotCompatible) { 181 availability_ == WebRemotePlaybackAvailability::kSourceNotCompatible) {
175 resolver->Reject(DOMException::Create( 182 resolver->Reject(DOMException::Create(
176 kNotSupportedError, 183 kNotSupportedError,
177 "The currentSrc is not compatible with remote playback")); 184 "The currentSrc is not compatible with remote playback"));
178 return promise; 185 return promise;
179 } 186 }
180 187
181 prompt_promise_resolver_ = resolver; 188 prompt_promise_resolver_ = resolver;
182 PromptInternal(); 189 PromptInternal();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 // We can remove the wrapper if InspectorInstrumentation returns a task id. 223 // We can remove the wrapper if InspectorInstrumentation returns a task id.
217 std::unique_ptr<WTF::Closure> task = WTF::Bind( 224 std::unique_ptr<WTF::Closure> task = WTF::Bind(
218 &RemotePlayback::NotifyInitialAvailability, WrapPersistent(this), id); 225 &RemotePlayback::NotifyInitialAvailability, WrapPersistent(this), id);
219 probe::AsyncTaskScheduled(GetExecutionContext(), "watchAvailabilityCallback", 226 probe::AsyncTaskScheduled(GetExecutionContext(), "watchAvailabilityCallback",
220 task.get()); 227 task.get());
221 TaskRunnerHelper::Get(TaskType::kMediaElementEvent, GetExecutionContext()) 228 TaskRunnerHelper::Get(TaskType::kMediaElementEvent, GetExecutionContext())
222 ->PostTask(BLINK_FROM_HERE, 229 ->PostTask(BLINK_FROM_HERE,
223 WTF::Bind(RunNotifyInitialAvailabilityTask, 230 WTF::Bind(RunNotifyInitialAvailabilityTask,
224 WrapPersistent(GetExecutionContext()), 231 WrapPersistent(GetExecutionContext()),
225 WTF::Passed(std::move(task)))); 232 WTF::Passed(std::move(task))));
233
234 UpdateListeningState();
226 return id; 235 return id;
227 } 236 }
228 237
229 bool RemotePlayback::CancelWatchAvailabilityInternal(int id) { 238 bool RemotePlayback::CancelWatchAvailabilityInternal(int id) {
230 auto iter = availability_callbacks_.find(id); 239 auto iter = availability_callbacks_.find(id);
231 if (iter == availability_callbacks_.end()) 240 if (iter == availability_callbacks_.end())
232 return false; 241 return false;
233 availability_callbacks_.erase(iter); 242 availability_callbacks_.erase(iter);
243 UpdateListeningState();
244
234 return true; 245 return true;
235 } 246 }
236 247
237 void RemotePlayback::NotifyInitialAvailability(int callback_id) { 248 void RemotePlayback::NotifyInitialAvailability(int callback_id) {
238 // May not find the callback if the website cancels it fast enough. 249 // May not find the callback if the website cancels it fast enough.
239 auto iter = availability_callbacks_.find(callback_id); 250 auto iter = availability_callbacks_.find(callback_id);
240 if (iter == availability_callbacks_.end()) 251 if (iter == availability_callbacks_.end())
241 return; 252 return;
242 253
243 iter->value->Run(this, RemotePlaybackAvailable()); 254 iter->value->Run(this, RemotePlaybackAvailable());
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 316
306 void RemotePlayback::PromptCancelled() { 317 void RemotePlayback::PromptCancelled() {
307 if (!prompt_promise_resolver_) 318 if (!prompt_promise_resolver_)
308 return; 319 return;
309 320
310 prompt_promise_resolver_->Reject( 321 prompt_promise_resolver_->Reject(
311 DOMException::Create(kNotAllowedError, "The prompt was dismissed.")); 322 DOMException::Create(kNotAllowedError, "The prompt was dismissed."));
312 prompt_promise_resolver_ = nullptr; 323 prompt_promise_resolver_ = nullptr;
313 } 324 }
314 325
326 void RemotePlayback::SourceChanged(const WebURL& source) {
327 DCHECK(RuntimeEnabledFeatures::newRemotePlaybackPipelineEnabled());
328
329 // If we're listening for the previous source, we should stop listening to
mark a. foltz 2017/05/31 21:16:41 Do you want to restrict source URLs considered to
330 // update the source for the WebPresentationClient.
331 if (!availability_urls_.empty()) {
332 WebVector<WebURL> empty_urls;
333 availability_urls_.Swap(empty_urls);
334 UpdateListeningState();
335 }
336
337 // Ignore the new source if it's not meaningful.
338 if (!source.IsEmpty() && source.IsValid()) {
339 UpdateAvailabilityUrls(source);
340 UpdateListeningState();
341 }
342 }
343
315 bool RemotePlayback::RemotePlaybackAvailable() const { 344 bool RemotePlayback::RemotePlaybackAvailable() const {
316 return availability_ == WebRemotePlaybackAvailability::kDeviceAvailable; 345 return availability_ == WebRemotePlaybackAvailability::kDeviceAvailable;
317 } 346 }
318 347
319 void RemotePlayback::RemotePlaybackDisabled() { 348 void RemotePlayback::RemotePlaybackDisabled() {
320 if (prompt_promise_resolver_) { 349 if (prompt_promise_resolver_) {
321 prompt_promise_resolver_->Reject(DOMException::Create( 350 prompt_promise_resolver_->Reject(DOMException::Create(
322 kInvalidStateError, "disableRemotePlayback attribute is present.")); 351 kInvalidStateError, "disableRemotePlayback attribute is present."));
323 prompt_promise_resolver_ = nullptr; 352 prompt_promise_resolver_ = nullptr;
324 } 353 }
325 354
326 availability_callbacks_.clear(); 355 availability_callbacks_.clear();
356 UpdateListeningState();
327 357
328 if (state_ != WebRemotePlaybackState::kDisconnected) 358 if (state_ != WebRemotePlaybackState::kDisconnected)
329 media_element_->RequestRemotePlaybackStop(); 359 media_element_->RequestRemotePlaybackStop();
330 } 360 }
331 361
362 void RemotePlayback::AvailabilityChanged(bool availability) {
363 DCHECK(RuntimeEnabledFeatures::newRemotePlaybackPipelineEnabled());
364 AvailabilityChanged(availability
365 ? WebRemotePlaybackAvailability::kDeviceAvailable
366 : WebRemotePlaybackAvailability::kDeviceNotAvailable);
367 }
368
369 const WebVector<WebURL>& RemotePlayback::Urls() const {
370 DCHECK(RuntimeEnabledFeatures::newRemotePlaybackPipelineEnabled());
371 // TODO(avayvod): update the URL format and add frame url, mime type and
372 // response headers when available.
373 return availability_urls_;
374 }
375
376 void RemotePlayback::UpdateListeningState() {
377 if (!RuntimeEnabledFeatures::newRemotePlaybackPipelineEnabled())
378 return;
379
380 bool will_be_listening =
381 !availability_urls_.empty() && !availability_callbacks_.IsEmpty();
382 if (is_listening_ == will_be_listening)
383 return;
384
385 WebPresentationClient* client =
386 PresentationController::ClientFromContext(GetExecutionContext());
387 if (!client)
388 return;
389
390 if (will_be_listening) {
391 client->StartListening(this);
392 } else {
393 client->StopListening(this);
394 }
395 is_listening_ = will_be_listening;
396 }
397
398 void RemotePlayback::UpdateAvailabilityUrls(const WebURL& source) {
399 // The URL for each media element's source looks like the following:
400 // chrome-media-source://<encoded-data> where |encoded-data| is base64 URL
401 // encoded string representation of a JSON structure with various information
402 // about the media element's source that looks like this:
403 // {
404 // "sourceUrl": "<sourceUrl>",
405 // }
406 // TODO(avayvod): add and fill more info to the JSON structure.
mark a. foltz 2017/05/31 21:16:41 Can you explain why URL-encoding is not sufficient
407 std::unique_ptr<JSONObject> source_info = JSONObject::Create();
408 source_info->SetString("sourceUrl", source.GetString());
409 CString json_source_info = source_info->ToJSONString().Utf8();
410 String encoded_source_info =
411 WTF::Base64URLEncode(json_source_info.data(), json_source_info.length());
412
413 WebVector<WebURL> new_availability_urls((size_t)1);
414 new_availability_urls[0] =
415 KURL(kParsedURLString, "chrome-media-source://" + encoded_source_info);
416 availability_urls_.Swap(new_availability_urls);
417 }
418
332 DEFINE_TRACE(RemotePlayback) { 419 DEFINE_TRACE(RemotePlayback) {
333 visitor->Trace(availability_callbacks_); 420 visitor->Trace(availability_callbacks_);
334 visitor->Trace(prompt_promise_resolver_); 421 visitor->Trace(prompt_promise_resolver_);
335 visitor->Trace(media_element_); 422 visitor->Trace(media_element_);
336 EventTargetWithInlineData::Trace(visitor); 423 EventTargetWithInlineData::Trace(visitor);
337 } 424 }
338 425
339 DEFINE_TRACE_WRAPPERS(RemotePlayback) { 426 DEFINE_TRACE_WRAPPERS(RemotePlayback) {
340 for (auto callback : availability_callbacks_.Values()) 427 for (auto callback : availability_callbacks_.Values())
341 visitor->TraceWrappers(callback); 428 visitor->TraceWrappers(callback);
342 EventTargetWithInlineData::TraceWrappers(visitor); 429 EventTargetWithInlineData::TraceWrappers(visitor);
343 } 430 }
344 431
345 } // namespace blink 432 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698