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

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

Issue 2415723002: [Blink, RemotePlayback] watchAvailability() implementation. (Closed)
Patch Set: Added layout test for callback gc 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
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 "core/HTMLNames.h" 9 #include "core/HTMLNames.h"
9 #include "core/dom/DOMException.h" 10 #include "core/dom/DOMException.h"
10 #include "core/dom/Document.h" 11 #include "core/dom/Document.h"
12 #include "core/dom/ExecutionContextTask.h"
11 #include "core/events/Event.h" 13 #include "core/events/Event.h"
12 #include "core/html/HTMLMediaElement.h" 14 #include "core/html/HTMLMediaElement.h"
13 #include "modules/EventTargetModules.h" 15 #include "modules/EventTargetModules.h"
14 #include "modules/remoteplayback/RemotePlaybackAvailability.h"
15 #include "platform/UserGestureIndicator.h" 16 #include "platform/UserGestureIndicator.h"
16 17
17 namespace blink { 18 namespace blink {
18 19
19 namespace { 20 namespace {
20 21
21 const AtomicString& remotePlaybackStateToString(WebRemotePlaybackState state) { 22 const AtomicString& remotePlaybackStateToString(WebRemotePlaybackState state) {
22 DEFINE_STATIC_LOCAL(const AtomicString, connectingValue, ("connecting")); 23 DEFINE_STATIC_LOCAL(const AtomicString, connectingValue, ("connecting"));
23 DEFINE_STATIC_LOCAL(const AtomicString, connectedValue, ("connected")); 24 DEFINE_STATIC_LOCAL(const AtomicString, connectedValue, ("connected"));
24 DEFINE_STATIC_LOCAL(const AtomicString, disconnectedValue, ("disconnected")); 25 DEFINE_STATIC_LOCAL(const AtomicString, disconnectedValue, ("disconnected"));
25 26
26 switch (state) { 27 switch (state) {
27 case WebRemotePlaybackState::Connecting: 28 case WebRemotePlaybackState::Connecting:
28 return connectingValue; 29 return connectingValue;
29 case WebRemotePlaybackState::Connected: 30 case WebRemotePlaybackState::Connected:
30 return connectedValue; 31 return connectedValue;
31 case WebRemotePlaybackState::Disconnected: 32 case WebRemotePlaybackState::Disconnected:
32 return disconnectedValue; 33 return disconnectedValue;
33 } 34 }
34 35
35 ASSERT_NOT_REACHED(); 36 ASSERT_NOT_REACHED();
36 return disconnectedValue; 37 return disconnectedValue;
37 } 38 }
38 39
39 } // anonymous namespace 40 } // anonymous namespace
40 41
41 // static 42 // static
42 RemotePlayback* RemotePlayback::create(HTMLMediaElement& element) { 43 RemotePlayback* RemotePlayback::create(ScriptState* scriptState,
43 ASSERT(element.document().frame()); 44 HTMLMediaElement& element) {
45 DCHECK(element.document().frame());
46 DCHECK(scriptState);
44 47
45 RemotePlayback* remotePlayback = new RemotePlayback(element); 48 RemotePlayback* remotePlayback = new RemotePlayback(scriptState, element);
46 element.setRemotePlaybackClient(remotePlayback); 49 element.setRemotePlaybackClient(remotePlayback);
47 50
48 return remotePlayback; 51 return remotePlayback;
49 } 52 }
50 53
51 RemotePlayback::RemotePlayback(HTMLMediaElement& element) 54 RemotePlayback::RemotePlayback(ScriptState* scriptState,
55 HTMLMediaElement& element)
52 : ActiveScriptWrappable(this), 56 : ActiveScriptWrappable(this),
57 m_scriptState(scriptState),
53 m_state(element.isPlayingRemotely() 58 m_state(element.isPlayingRemotely()
54 ? WebRemotePlaybackState::Connected 59 ? WebRemotePlaybackState::Connected
55 : WebRemotePlaybackState::Disconnected), 60 : WebRemotePlaybackState::Disconnected),
56 m_availability(element.hasRemoteRoutes()), 61 m_availability(element.hasRemoteRoutes()),
57 m_mediaElement(&element) {} 62 m_mediaElement(&element) {}
58 63
59 const AtomicString& RemotePlayback::interfaceName() const { 64 const AtomicString& RemotePlayback::interfaceName() const {
60 return EventTargetNames::RemotePlayback; 65 return EventTargetNames::RemotePlayback;
61 } 66 }
62 67
63 ExecutionContext* RemotePlayback::getExecutionContext() const { 68 ExecutionContext* RemotePlayback::getExecutionContext() const {
64 return &m_mediaElement->document(); 69 return &m_mediaElement->document();
65 } 70 }
66 71
67 ScriptPromise RemotePlayback::getAvailability(ScriptState* scriptState) { 72 ScriptPromise RemotePlayback::watchAvailability(
68 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); 73 RemotePlaybackAvailabilityCallback* callback) {
74 ScriptPromiseResolver* resolver =
75 ScriptPromiseResolver::create(m_scriptState.get());
69 ScriptPromise promise = resolver->promise(); 76 ScriptPromise promise = resolver->promise();
70 77
78 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) {
79 resolver->reject(DOMException::create(
80 InvalidStateError, "disableRemotePlayback attribute is present."));
81 return promise;
82 }
83
84 // TODO(avayvod): implement steps 4 and 5 of the algorithm.
85 // https://crbug.com/655233
86 int id;
87 do {
88 id = getExecutionContext()->circularSequentialID();
89 } while (!m_availabilityCallbacks.add(id, callback).isNewEntry);
90
91 // Report the current availability via the callback.
92 getExecutionContext()->postTask(
93 BLINK_FROM_HERE,
94 createSameThreadTask(&RemotePlayback::notifyInitialAvailability,
95 wrapPersistent(this), id),
96 "watchAvailabilityCallback");
97
71 // TODO(avayvod): Currently the availability is tracked for each media element 98 // TODO(avayvod): Currently the availability is tracked for each media element
72 // as soon as it's created, we probably want to limit that to when the 99 // as soon as it's created, we probably want to limit that to when the
73 // page/element is visible (see https://crbug.com/597281) and has default 100 // page/element is visible (see https://crbug.com/597281) and has default
74 // controls. If there are no default controls, we should also start tracking 101 // controls. If there are no default controls, we should also start tracking
75 // availability on demand meaning the Promise returned by getAvailability() 102 // availability on demand meaning the Promise returned by watchAvailability()
76 // will be resolved asynchronously. 103 // will be resolved asynchronously.
77 RemotePlaybackAvailability* availability = 104 resolver->resolve(id);
78 RemotePlaybackAvailability::take(resolver, m_availability);
79 m_availabilityObjects.append(availability);
80 resolver->resolve(availability);
81 return promise; 105 return promise;
82 } 106 }
83 107
84 ScriptPromise RemotePlayback::prompt(ScriptState* scriptState) { 108 ScriptPromise RemotePlayback::cancelWatchAvailability(int id) {
85 // TODO(avayvod): implement steps 4, 5, 8, 9 of the algorithm. 109 ScriptPromiseResolver* resolver =
86 // https://crbug.com/647441 110 ScriptPromiseResolver::create(m_scriptState.get());
87 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
88 ScriptPromise promise = resolver->promise(); 111 ScriptPromise promise = resolver->promise();
89 112
90 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { 113 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) {
114 resolver->reject(DOMException::create(
115 InvalidStateError, "disableRemotePlayback attribute is present."));
116 return promise;
117 }
118
119 auto iter = m_availabilityCallbacks.find(id);
120 if (iter == m_availabilityCallbacks.end()) {
121 resolver->reject(DOMException::create(
122 NotFoundError, "A callback with the given id is not found."));
123 return promise;
124 }
125
126 m_availabilityCallbacks.remove(iter);
127
128 resolver->resolve();
129 return promise;
130 }
131
132 ScriptPromise RemotePlayback::cancelWatchAvailability() {
133 ScriptPromiseResolver* resolver =
134 ScriptPromiseResolver::create(m_scriptState.get());
135 ScriptPromise promise = resolver->promise();
136
137 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) {
138 resolver->reject(DOMException::create(
139 InvalidStateError, "disableRemotePlayback attribute is present."));
140 return promise;
141 }
142
143 m_availabilityCallbacks.clear();
144
145 resolver->resolve();
146 return promise;
147 }
148
149 ScriptPromise RemotePlayback::prompt() {
150 // TODO(avayvod): implement steps 5, 8, 9 of the algorithm.
151 // https://crbug.com/647441
152 ScriptPromiseResolver* resolver =
153 ScriptPromiseResolver::create(m_scriptState.get());
154 ScriptPromise promise = resolver->promise();
155
156 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) {
91 resolver->reject(DOMException::create( 157 resolver->reject(DOMException::create(
92 InvalidStateError, "disableRemotePlayback attribute is present.")); 158 InvalidStateError, "disableRemotePlayback attribute is present."));
93 return promise; 159 return promise;
94 } 160 }
95 161
96 if (m_promptPromiseResolver) { 162 if (m_promptPromiseResolver) {
97 resolver->reject(DOMException::create( 163 resolver->reject(DOMException::create(
98 OperationError, 164 OperationError,
99 "A prompt is already being shown for this media element.")); 165 "A prompt is already being shown for this media element."));
100 return promise; 166 return promise;
(...skipping 18 matching lines...) Expand all
119 } 185 }
120 186
121 return promise; 187 return promise;
122 } 188 }
123 189
124 String RemotePlayback::state() const { 190 String RemotePlayback::state() const {
125 return remotePlaybackStateToString(m_state); 191 return remotePlaybackStateToString(m_state);
126 } 192 }
127 193
128 bool RemotePlayback::hasPendingActivity() const { 194 bool RemotePlayback::hasPendingActivity() const {
129 return hasEventListeners() || !m_availabilityObjects.isEmpty() || 195 return hasEventListeners() || !m_availabilityCallbacks.isEmpty() ||
130 m_promptPromiseResolver; 196 m_promptPromiseResolver;
131 } 197 }
132 198
199 void RemotePlayback::notifyInitialAvailability(int callbackId) {
200 // May not find the callback if the website cancels it fast enough.
201 auto iter = m_availabilityCallbacks.find(callbackId);
202 if (iter == m_availabilityCallbacks.end())
203 return;
204
205 iter->value->call(m_scriptState.get(), this, m_availability);
206 }
207
133 void RemotePlayback::stateChanged(WebRemotePlaybackState state) { 208 void RemotePlayback::stateChanged(WebRemotePlaybackState state) {
134 // We may get a "disconnected" state change while in the "disconnected" 209 // We may get a "disconnected" state change while in the "disconnected"
135 // state if initiated connection fails. So cleanup the promise resolvers 210 // state if initiated connection fails. So cleanup the promise resolvers
136 // before checking if anything changed. 211 // before checking if anything changed.
137 // TODO(avayvod): cleanup this logic when we implementing the "connecting" 212 // TODO(avayvod): cleanup this logic when we implementing the "connecting"
138 // state. 213 // state.
139 if (m_promptPromiseResolver) { 214 if (m_promptPromiseResolver) {
140 if (state != WebRemotePlaybackState::Disconnected) 215 if (state != WebRemotePlaybackState::Disconnected)
141 m_promptPromiseResolver->resolve(); 216 m_promptPromiseResolver->resolve();
142 else 217 else
(...skipping 17 matching lines...) Expand all
160 dispatchEvent(Event::create(EventTypeNames::disconnect)); 235 dispatchEvent(Event::create(EventTypeNames::disconnect));
161 break; 236 break;
162 } 237 }
163 } 238 }
164 239
165 void RemotePlayback::availabilityChanged(bool available) { 240 void RemotePlayback::availabilityChanged(bool available) {
166 if (m_availability == available) 241 if (m_availability == available)
167 return; 242 return;
168 243
169 m_availability = available; 244 m_availability = available;
170 for (auto& availabilityObject : m_availabilityObjects) 245 for (auto& callback : m_availabilityCallbacks.values())
171 availabilityObject->availabilityChanged(available); 246 callback->call(m_scriptState.get(), this, m_availability);
172 } 247 }
173 248
174 void RemotePlayback::promptCancelled() { 249 void RemotePlayback::promptCancelled() {
175 if (!m_promptPromiseResolver) 250 if (!m_promptPromiseResolver)
176 return; 251 return;
177 252
178 m_promptPromiseResolver->reject( 253 m_promptPromiseResolver->reject(
179 DOMException::create(NotAllowedError, "The prompt was dismissed.")); 254 DOMException::create(NotAllowedError, "The prompt was dismissed."));
180 m_promptPromiseResolver = nullptr; 255 m_promptPromiseResolver = nullptr;
181 } 256 }
182 257
258 void RemotePlayback::setV8ReferencesForCallbacks(
259 v8::Isolate* isolate,
260 const v8::Persistent<v8::Object>& wrapper) {
261 for (auto callback : m_availabilityCallbacks.values())
262 callback->setWrapperReference(isolate, wrapper);
263 }
264
183 DEFINE_TRACE(RemotePlayback) { 265 DEFINE_TRACE(RemotePlayback) {
184 visitor->trace(m_availabilityObjects); 266 visitor->trace(m_availabilityCallbacks);
185 visitor->trace(m_promptPromiseResolver); 267 visitor->trace(m_promptPromiseResolver);
186 visitor->trace(m_mediaElement); 268 visitor->trace(m_mediaElement);
187 EventTargetWithInlineData::trace(visitor); 269 EventTargetWithInlineData::trace(visitor);
188 } 270 }
189 271
190 } // namespace blink 272 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698