| 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" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 // static | 42 // static |
| 43 RemotePlayback* RemotePlayback::create(HTMLMediaElement& element) { | 43 RemotePlayback* RemotePlayback::create(HTMLMediaElement& element) { |
| 44 return new RemotePlayback(element); | 44 return new RemotePlayback(element); |
| 45 } | 45 } |
| 46 | 46 |
| 47 RemotePlayback::RemotePlayback(HTMLMediaElement& element) | 47 RemotePlayback::RemotePlayback(HTMLMediaElement& element) |
| 48 : ActiveScriptWrappable(this), | 48 : ActiveScriptWrappable(this), |
| 49 m_state(element.isPlayingRemotely() | 49 m_state(element.isPlayingRemotely() |
| 50 ? WebRemotePlaybackState::Connected | 50 ? WebRemotePlaybackState::Connected |
| 51 : WebRemotePlaybackState::Disconnected), | 51 : WebRemotePlaybackState::Disconnected), |
| 52 m_availability(element.hasRemoteRoutes()), | 52 m_availability(WebRemotePlaybackAvailability::Unknown), |
| 53 m_mediaElement(&element) {} | 53 m_mediaElement(&element) {} |
| 54 | 54 |
| 55 const AtomicString& RemotePlayback::interfaceName() const { | 55 const AtomicString& RemotePlayback::interfaceName() const { |
| 56 return EventTargetNames::RemotePlayback; | 56 return EventTargetNames::RemotePlayback; |
| 57 } | 57 } |
| 58 | 58 |
| 59 ExecutionContext* RemotePlayback::getExecutionContext() const { | 59 ExecutionContext* RemotePlayback::getExecutionContext() const { |
| 60 return &m_mediaElement->document(); | 60 return &m_mediaElement->document(); |
| 61 } | 61 } |
| 62 | 62 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 return promise; | 134 return promise; |
| 135 } | 135 } |
| 136 | 136 |
| 137 m_availabilityCallbacks.clear(); | 137 m_availabilityCallbacks.clear(); |
| 138 | 138 |
| 139 resolver->resolve(); | 139 resolver->resolve(); |
| 140 return promise; | 140 return promise; |
| 141 } | 141 } |
| 142 | 142 |
| 143 ScriptPromise RemotePlayback::prompt(ScriptState* scriptState) { | 143 ScriptPromise RemotePlayback::prompt(ScriptState* scriptState) { |
| 144 // TODO(avayvod): implement steps 5, 8, 9 of the algorithm. | |
| 145 // https://crbug.com/647441 | |
| 146 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 144 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 147 ScriptPromise promise = resolver->promise(); | 145 ScriptPromise promise = resolver->promise(); |
| 148 | 146 |
| 149 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { | 147 if (m_mediaElement->fastHasAttribute(HTMLNames::disableremoteplaybackAttr)) { |
| 150 resolver->reject(DOMException::create( | 148 resolver->reject(DOMException::create( |
| 151 InvalidStateError, "disableRemotePlayback attribute is present.")); | 149 InvalidStateError, "disableRemotePlayback attribute is present.")); |
| 152 return promise; | 150 return promise; |
| 153 } | 151 } |
| 154 | 152 |
| 155 if (m_promptPromiseResolver) { | 153 if (m_promptPromiseResolver) { |
| 156 resolver->reject(DOMException::create( | 154 resolver->reject(DOMException::create( |
| 157 OperationError, | 155 OperationError, |
| 158 "A prompt is already being shown for this media element.")); | 156 "A prompt is already being shown for this media element.")); |
| 159 return promise; | 157 return promise; |
| 160 } | 158 } |
| 161 | 159 |
| 162 if (!UserGestureIndicator::utilizeUserGesture()) { | 160 if (!UserGestureIndicator::utilizeUserGesture()) { |
| 163 resolver->reject(DOMException::create( | 161 resolver->reject(DOMException::create( |
| 164 InvalidAccessError, "RemotePlayback::prompt() requires user gesture.")); | 162 InvalidAccessError, "RemotePlayback::prompt() requires user gesture.")); |
| 165 return promise; | 163 return promise; |
| 166 } | 164 } |
| 167 | 165 |
| 166 // TODO(avayvod): don't do this check on low-end devices - merge with |
| 167 // https://codereview.chromium.org/2475293003 |
| 168 if (m_availability == WebRemotePlaybackAvailability::DeviceNotAvailable) { |
| 169 resolver->reject(DOMException::create(NotFoundError, |
| 170 "No remote playback devices found.")); |
| 171 return promise; |
| 172 } |
| 173 |
| 174 if (m_availability == WebRemotePlaybackAvailability::SourceNotSupported || |
| 175 m_availability == WebRemotePlaybackAvailability::SourceNotCompatible) { |
| 176 resolver->reject(DOMException::create( |
| 177 NotSupportedError, |
| 178 "The currentSrc is not compatible with remote playback")); |
| 179 return promise; |
| 180 } |
| 181 |
| 168 if (m_state == WebRemotePlaybackState::Disconnected) { | 182 if (m_state == WebRemotePlaybackState::Disconnected) { |
| 169 m_promptPromiseResolver = resolver; | 183 m_promptPromiseResolver = resolver; |
| 170 m_mediaElement->requestRemotePlayback(); | 184 m_mediaElement->requestRemotePlayback(); |
| 171 } else { | 185 } else { |
| 172 m_promptPromiseResolver = resolver; | 186 m_promptPromiseResolver = resolver; |
| 173 m_mediaElement->requestRemotePlaybackControl(); | 187 m_mediaElement->requestRemotePlaybackControl(); |
| 174 } | 188 } |
| 175 | 189 |
| 176 return promise; | 190 return promise; |
| 177 } | 191 } |
| 178 | 192 |
| 179 String RemotePlayback::state() const { | 193 String RemotePlayback::state() const { |
| 180 return remotePlaybackStateToString(m_state); | 194 return remotePlaybackStateToString(m_state); |
| 181 } | 195 } |
| 182 | 196 |
| 183 bool RemotePlayback::hasPendingActivity() const { | 197 bool RemotePlayback::hasPendingActivity() const { |
| 184 return hasEventListeners() || !m_availabilityCallbacks.isEmpty() || | 198 return hasEventListeners() || !m_availabilityCallbacks.isEmpty() || |
| 185 m_promptPromiseResolver; | 199 m_promptPromiseResolver; |
| 186 } | 200 } |
| 187 | 201 |
| 188 void RemotePlayback::notifyInitialAvailability(int callbackId) { | 202 void RemotePlayback::notifyInitialAvailability(int callbackId) { |
| 189 // May not find the callback if the website cancels it fast enough. | 203 // May not find the callback if the website cancels it fast enough. |
| 190 auto iter = m_availabilityCallbacks.find(callbackId); | 204 auto iter = m_availabilityCallbacks.find(callbackId); |
| 191 if (iter == m_availabilityCallbacks.end()) | 205 if (iter == m_availabilityCallbacks.end()) |
| 192 return; | 206 return; |
| 193 | 207 |
| 194 iter->value->call(this, m_availability); | 208 iter->value->call(this, remotePlaybackAvailable()); |
| 195 } | 209 } |
| 196 | 210 |
| 197 void RemotePlayback::stateChanged(WebRemotePlaybackState state) { | 211 void RemotePlayback::stateChanged(WebRemotePlaybackState state) { |
| 198 if (m_state == state) | 212 if (m_state == state) |
| 199 return; | 213 return; |
| 200 | 214 |
| 201 if (m_promptPromiseResolver) { | 215 if (m_promptPromiseResolver) { |
| 202 // Changing state to Disconnected from "disconnected" or "connecting" means | 216 // Changing state to Disconnected from "disconnected" or "connecting" means |
| 203 // that establishing connection with remote playback device failed. | 217 // that establishing connection with remote playback device failed. |
| 204 // Changing state to anything else means the state change intended by | 218 // Changing state to anything else means the state change intended by |
| (...skipping 19 matching lines...) Expand all Loading... |
| 224 break; | 238 break; |
| 225 case WebRemotePlaybackState::Connected: | 239 case WebRemotePlaybackState::Connected: |
| 226 dispatchEvent(Event::create(EventTypeNames::connect)); | 240 dispatchEvent(Event::create(EventTypeNames::connect)); |
| 227 break; | 241 break; |
| 228 case WebRemotePlaybackState::Disconnected: | 242 case WebRemotePlaybackState::Disconnected: |
| 229 dispatchEvent(Event::create(EventTypeNames::disconnect)); | 243 dispatchEvent(Event::create(EventTypeNames::disconnect)); |
| 230 break; | 244 break; |
| 231 } | 245 } |
| 232 } | 246 } |
| 233 | 247 |
| 234 void RemotePlayback::availabilityChanged(bool available) { | 248 void RemotePlayback::availabilityChanged( |
| 235 if (m_availability == available) | 249 WebRemotePlaybackAvailability availability) { |
| 250 if (m_availability == availability) |
| 236 return; | 251 return; |
| 237 | 252 |
| 238 m_availability = available; | 253 bool oldAvailability = remotePlaybackAvailable(); |
| 254 m_availability = availability; |
| 255 bool newAvailability = remotePlaybackAvailable(); |
| 256 if (newAvailability == oldAvailability) |
| 257 return; |
| 258 |
| 239 for (auto& callback : m_availabilityCallbacks.values()) | 259 for (auto& callback : m_availabilityCallbacks.values()) |
| 240 callback->call(this, m_availability); | 260 callback->call(this, newAvailability); |
| 241 } | 261 } |
| 242 | 262 |
| 243 void RemotePlayback::promptCancelled() { | 263 void RemotePlayback::promptCancelled() { |
| 244 if (!m_promptPromiseResolver) | 264 if (!m_promptPromiseResolver) |
| 245 return; | 265 return; |
| 246 | 266 |
| 247 m_promptPromiseResolver->reject( | 267 m_promptPromiseResolver->reject( |
| 248 DOMException::create(NotAllowedError, "The prompt was dismissed.")); | 268 DOMException::create(NotAllowedError, "The prompt was dismissed.")); |
| 249 m_promptPromiseResolver = nullptr; | 269 m_promptPromiseResolver = nullptr; |
| 250 } | 270 } |
| 251 | 271 |
| 272 bool RemotePlayback::remotePlaybackAvailable() const { |
| 273 return m_availability == WebRemotePlaybackAvailability::DeviceAvailable; |
| 274 } |
| 275 |
| 252 void RemotePlayback::remotePlaybackDisabled() { | 276 void RemotePlayback::remotePlaybackDisabled() { |
| 253 if (m_promptPromiseResolver) { | 277 if (m_promptPromiseResolver) { |
| 254 m_promptPromiseResolver->reject(DOMException::create( | 278 m_promptPromiseResolver->reject(DOMException::create( |
| 255 InvalidStateError, "disableRemotePlayback attribute is present.")); | 279 InvalidStateError, "disableRemotePlayback attribute is present.")); |
| 256 m_promptPromiseResolver = nullptr; | 280 m_promptPromiseResolver = nullptr; |
| 257 } | 281 } |
| 258 | 282 |
| 259 m_availabilityCallbacks.clear(); | 283 m_availabilityCallbacks.clear(); |
| 260 | 284 |
| 261 if (m_state != WebRemotePlaybackState::Disconnected) | 285 if (m_state != WebRemotePlaybackState::Disconnected) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 277 } | 301 } |
| 278 | 302 |
| 279 DEFINE_TRACE_WRAPPERS(RemotePlayback) { | 303 DEFINE_TRACE_WRAPPERS(RemotePlayback) { |
| 280 for (auto callback : m_availabilityCallbacks.values()) { | 304 for (auto callback : m_availabilityCallbacks.values()) { |
| 281 visitor->traceWrappers(callback); | 305 visitor->traceWrappers(callback); |
| 282 } | 306 } |
| 283 EventTargetWithInlineData::traceWrappers(visitor); | 307 EventTargetWithInlineData::traceWrappers(visitor); |
| 284 } | 308 } |
| 285 | 309 |
| 286 } // namespace blink | 310 } // namespace blink |
| OLD | NEW |