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 "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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |