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/events/Event.h" | 13 #include "core/events/Event.h" |
14 #include "core/html/HTMLMediaElement.h" | 14 #include "core/html/HTMLMediaElement.h" |
15 #include "core/probe/CoreProbes.h" | 15 #include "core/probe/CoreProbes.h" |
16 #include "modules/EventTargetModules.h" | 16 #include "modules/EventTargetModules.h" |
| 17 #include "modules/remoteplayback/AvailabilityCallbackWrapper.h" |
17 #include "platform/MemoryCoordinator.h" | 18 #include "platform/MemoryCoordinator.h" |
18 #include "platform/UserGestureIndicator.h" | 19 #include "platform/UserGestureIndicator.h" |
19 | 20 |
20 namespace blink { | 21 namespace blink { |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
24 const AtomicString& RemotePlaybackStateToString(WebRemotePlaybackState state) { | 25 const AtomicString& RemotePlaybackStateToString(WebRemotePlaybackState state) { |
25 DEFINE_STATIC_LOCAL(const AtomicString, connecting_value, ("connecting")); | 26 DEFINE_STATIC_LOCAL(const AtomicString, connecting_value, ("connecting")); |
26 DEFINE_STATIC_LOCAL(const AtomicString, connected_value, ("connected")); | 27 DEFINE_STATIC_LOCAL(const AtomicString, connected_value, ("connected")); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 return promise; | 80 return promise; |
80 } | 81 } |
81 | 82 |
82 if (MemoryCoordinator::IsLowEndDevice()) { | 83 if (MemoryCoordinator::IsLowEndDevice()) { |
83 resolver->Reject(DOMException::Create( | 84 resolver->Reject(DOMException::Create( |
84 kNotSupportedError, | 85 kNotSupportedError, |
85 "Availability monitoring is not supported on this device.")); | 86 "Availability monitoring is not supported on this device.")); |
86 return promise; | 87 return promise; |
87 } | 88 } |
88 | 89 |
89 int id; | 90 int id = WatchAvailabilityInternal(new AvailabilityCallbackWrapper(callback)); |
90 do { | |
91 id = GetExecutionContext()->CircularSequentialID(); | |
92 } while ( | |
93 !availability_callbacks_ | |
94 .insert(id, TraceWrapperMember<RemotePlaybackAvailabilityCallback>( | |
95 this, callback)) | |
96 .is_new_entry); | |
97 | |
98 // Report the current availability via the callback. | |
99 // TODO(yuryu): Wrapping notifyInitialAvailability with WTF::Closure as | |
100 // InspectorInstrumentation requires a globally unique pointer to track tasks. | |
101 // We can remove the wrapper if InspectorInstrumentation returns a task id. | |
102 std::unique_ptr<WTF::Closure> task = WTF::Bind( | |
103 &RemotePlayback::NotifyInitialAvailability, WrapPersistent(this), id); | |
104 probe::AsyncTaskScheduled(GetExecutionContext(), "watchAvailabilityCallback", | |
105 task.get()); | |
106 TaskRunnerHelper::Get(TaskType::kMediaElementEvent, GetExecutionContext()) | |
107 ->PostTask(BLINK_FROM_HERE, | |
108 WTF::Bind(RunNotifyInitialAvailabilityTask, | |
109 WrapPersistent(GetExecutionContext()), | |
110 WTF::Passed(std::move(task)))); | |
111 | 91 |
112 // TODO(avayvod): Currently the availability is tracked for each media element | 92 // TODO(avayvod): Currently the availability is tracked for each media element |
113 // as soon as it's created, we probably want to limit that to when the | 93 // as soon as it's created, we probably want to limit that to when the |
114 // page/element is visible (see https://crbug.com/597281) and has default | 94 // page/element is visible (see https://crbug.com/597281) and has default |
115 // controls. If there are no default controls, we should also start tracking | 95 // controls. If there are no default controls, we should also start tracking |
116 // availability on demand meaning the Promise returned by watchAvailability() | 96 // availability on demand meaning the Promise returned by watchAvailability() |
117 // will be resolved asynchronously. | 97 // will be resolved asynchronously. |
118 resolver->Resolve(id); | 98 resolver->Resolve(id); |
119 return promise; | 99 return promise; |
120 } | 100 } |
121 | 101 |
122 ScriptPromise RemotePlayback::cancelWatchAvailability(ScriptState* script_state, | 102 ScriptPromise RemotePlayback::cancelWatchAvailability(ScriptState* script_state, |
123 int id) { | 103 int id) { |
124 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); | 104 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
125 ScriptPromise promise = resolver->Promise(); | 105 ScriptPromise promise = resolver->Promise(); |
126 | 106 |
127 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { | 107 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { |
128 resolver->Reject(DOMException::Create( | 108 resolver->Reject(DOMException::Create( |
129 kInvalidStateError, "disableRemotePlayback attribute is present.")); | 109 kInvalidStateError, "disableRemotePlayback attribute is present.")); |
130 return promise; | 110 return promise; |
131 } | 111 } |
132 | 112 |
133 auto iter = availability_callbacks_.find(id); | 113 if (!CancelWatchAvailabilityInternal(id)) { |
134 if (iter == availability_callbacks_.end()) { | |
135 resolver->Reject(DOMException::Create( | 114 resolver->Reject(DOMException::Create( |
136 kNotFoundError, "A callback with the given id is not found.")); | 115 kNotFoundError, "A callback with the given id is not found.")); |
137 return promise; | 116 return promise; |
138 } | 117 } |
139 | 118 |
140 availability_callbacks_.erase(iter); | |
141 | |
142 resolver->Resolve(); | 119 resolver->Resolve(); |
143 return promise; | 120 return promise; |
144 } | 121 } |
145 | 122 |
146 ScriptPromise RemotePlayback::cancelWatchAvailability( | 123 ScriptPromise RemotePlayback::cancelWatchAvailability( |
147 ScriptState* script_state) { | 124 ScriptState* script_state) { |
148 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); | 125 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
149 ScriptPromise promise = resolver->Promise(); | 126 ScriptPromise promise = resolver->Promise(); |
150 | 127 |
151 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { | 128 if (media_element_->FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 } | 170 } |
194 | 171 |
195 if (availability_ == WebRemotePlaybackAvailability::kSourceNotSupported || | 172 if (availability_ == WebRemotePlaybackAvailability::kSourceNotSupported || |
196 availability_ == WebRemotePlaybackAvailability::kSourceNotCompatible) { | 173 availability_ == WebRemotePlaybackAvailability::kSourceNotCompatible) { |
197 resolver->Reject(DOMException::Create( | 174 resolver->Reject(DOMException::Create( |
198 kNotSupportedError, | 175 kNotSupportedError, |
199 "The currentSrc is not compatible with remote playback")); | 176 "The currentSrc is not compatible with remote playback")); |
200 return promise; | 177 return promise; |
201 } | 178 } |
202 | 179 |
203 if (state_ == WebRemotePlaybackState::kDisconnected) { | 180 prompt_promise_resolver_ = resolver; |
204 prompt_promise_resolver_ = resolver; | 181 PromptInternal(); |
205 media_element_->RequestRemotePlayback(); | |
206 } else { | |
207 prompt_promise_resolver_ = resolver; | |
208 media_element_->RequestRemotePlaybackControl(); | |
209 } | |
210 | 182 |
211 return promise; | 183 return promise; |
212 } | 184 } |
213 | 185 |
214 String RemotePlayback::state() const { | 186 String RemotePlayback::state() const { |
215 return RemotePlaybackStateToString(state_); | 187 return RemotePlaybackStateToString(state_); |
216 } | 188 } |
217 | 189 |
218 bool RemotePlayback::HasPendingActivity() const { | 190 bool RemotePlayback::HasPendingActivity() const { |
219 return HasEventListeners() || !availability_callbacks_.IsEmpty() || | 191 return HasEventListeners() || !availability_callbacks_.IsEmpty() || |
220 prompt_promise_resolver_; | 192 prompt_promise_resolver_; |
221 } | 193 } |
222 | 194 |
| 195 void RemotePlayback::PromptInternal() { |
| 196 if (state_ == WebRemotePlaybackState::kDisconnected) |
| 197 media_element_->RequestRemotePlayback(); |
| 198 else |
| 199 media_element_->RequestRemotePlaybackControl(); |
| 200 } |
| 201 |
| 202 int RemotePlayback::WatchAvailabilityInternal( |
| 203 AvailabilityCallbackWrapper* callback) { |
| 204 int id; |
| 205 do { |
| 206 id = GetExecutionContext()->CircularSequentialID(); |
| 207 } while (!availability_callbacks_ |
| 208 .insert(id, TraceWrapperMember<AvailabilityCallbackWrapper>( |
| 209 this, callback)) |
| 210 .is_new_entry); |
| 211 |
| 212 // Report the current availability via the callback. |
| 213 // TODO(yuryu): Wrapping notifyInitialAvailability with WTF::Closure as |
| 214 // InspectorInstrumentation requires a globally unique pointer to track tasks. |
| 215 // We can remove the wrapper if InspectorInstrumentation returns a task id. |
| 216 std::unique_ptr<WTF::Closure> task = WTF::Bind( |
| 217 &RemotePlayback::NotifyInitialAvailability, WrapPersistent(this), id); |
| 218 probe::AsyncTaskScheduled(GetExecutionContext(), "watchAvailabilityCallback", |
| 219 task.get()); |
| 220 TaskRunnerHelper::Get(TaskType::kMediaElementEvent, GetExecutionContext()) |
| 221 ->PostTask(BLINK_FROM_HERE, |
| 222 WTF::Bind(RunNotifyInitialAvailabilityTask, |
| 223 WrapPersistent(GetExecutionContext()), |
| 224 WTF::Passed(std::move(task)))); |
| 225 return id; |
| 226 } |
| 227 |
| 228 bool RemotePlayback::CancelWatchAvailabilityInternal(int id) { |
| 229 auto iter = availability_callbacks_.find(id); |
| 230 if (iter == availability_callbacks_.end()) |
| 231 return false; |
| 232 availability_callbacks_.erase(iter); |
| 233 return true; |
| 234 } |
| 235 |
223 void RemotePlayback::NotifyInitialAvailability(int callback_id) { | 236 void RemotePlayback::NotifyInitialAvailability(int callback_id) { |
224 // May not find the callback if the website cancels it fast enough. | 237 // May not find the callback if the website cancels it fast enough. |
225 auto iter = availability_callbacks_.find(callback_id); | 238 auto iter = availability_callbacks_.find(callback_id); |
226 if (iter == availability_callbacks_.end()) | 239 if (iter == availability_callbacks_.end()) |
227 return; | 240 return; |
228 | 241 |
229 iter->value->call(this, RemotePlaybackAvailable()); | 242 iter->value->Run(this, RemotePlaybackAvailable()); |
230 } | 243 } |
231 | 244 |
232 void RemotePlayback::StateChanged(WebRemotePlaybackState state) { | 245 void RemotePlayback::StateChanged(WebRemotePlaybackState state) { |
233 if (state_ == state) | 246 if (state_ == state) |
234 return; | 247 return; |
235 | 248 |
236 if (prompt_promise_resolver_) { | 249 if (prompt_promise_resolver_) { |
237 // Changing state to Disconnected from "disconnected" or "connecting" means | 250 // Changing state to Disconnected from "disconnected" or "connecting" means |
238 // that establishing connection with remote playback device failed. | 251 // that establishing connection with remote playback device failed. |
239 // Changing state to anything else means the state change intended by | 252 // Changing state to anything else means the state change intended by |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 if (availability_ == availability) | 284 if (availability_ == availability) |
272 return; | 285 return; |
273 | 286 |
274 bool old_availability = RemotePlaybackAvailable(); | 287 bool old_availability = RemotePlaybackAvailable(); |
275 availability_ = availability; | 288 availability_ = availability; |
276 bool new_availability = RemotePlaybackAvailable(); | 289 bool new_availability = RemotePlaybackAvailable(); |
277 if (new_availability == old_availability) | 290 if (new_availability == old_availability) |
278 return; | 291 return; |
279 | 292 |
280 for (auto& callback : availability_callbacks_.Values()) | 293 for (auto& callback : availability_callbacks_.Values()) |
281 callback->call(this, new_availability); | 294 callback->Run(this, new_availability); |
282 } | 295 } |
283 | 296 |
284 void RemotePlayback::PromptCancelled() { | 297 void RemotePlayback::PromptCancelled() { |
285 if (!prompt_promise_resolver_) | 298 if (!prompt_promise_resolver_) |
286 return; | 299 return; |
287 | 300 |
288 prompt_promise_resolver_->Reject( | 301 prompt_promise_resolver_->Reject( |
289 DOMException::Create(kNotAllowedError, "The prompt was dismissed.")); | 302 DOMException::Create(kNotAllowedError, "The prompt was dismissed.")); |
290 prompt_promise_resolver_ = nullptr; | 303 prompt_promise_resolver_ = nullptr; |
291 } | 304 } |
(...skipping 16 matching lines...) Expand all Loading... |
308 } | 321 } |
309 | 322 |
310 DEFINE_TRACE(RemotePlayback) { | 323 DEFINE_TRACE(RemotePlayback) { |
311 visitor->Trace(availability_callbacks_); | 324 visitor->Trace(availability_callbacks_); |
312 visitor->Trace(prompt_promise_resolver_); | 325 visitor->Trace(prompt_promise_resolver_); |
313 visitor->Trace(media_element_); | 326 visitor->Trace(media_element_); |
314 EventTargetWithInlineData::Trace(visitor); | 327 EventTargetWithInlineData::Trace(visitor); |
315 } | 328 } |
316 | 329 |
317 DEFINE_TRACE_WRAPPERS(RemotePlayback) { | 330 DEFINE_TRACE_WRAPPERS(RemotePlayback) { |
318 for (auto callback : availability_callbacks_.Values()) { | 331 for (auto callback : availability_callbacks_.Values()) |
319 visitor->TraceWrappers(callback); | 332 visitor->TraceWrappers(callback); |
320 } | |
321 EventTargetWithInlineData::TraceWrappers(visitor); | 333 EventTargetWithInlineData::TraceWrappers(visitor); |
322 } | 334 } |
323 | 335 |
324 } // namespace blink | 336 } // namespace blink |
OLD | NEW |