Index: third_party/WebKit/Source/modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.cpp |
diff --git a/third_party/WebKit/Source/modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.cpp b/third_party/WebKit/Source/modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.cpp |
index 930dc3c40b88e366c893b33e4f2691cb812f706b..c17ad637f413f75e0d050bb46d93a66df538593d 100644 |
--- a/third_party/WebKit/Source/modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.cpp |
+++ b/third_party/WebKit/Source/modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.cpp |
@@ -8,11 +8,81 @@ |
#include "bindings/core/v8/ScriptPromiseResolver.h" |
#include "bindings/core/v8/ScriptState.h" |
#include "core/dom/ExecutionContext.h" |
+#include "modules/audio_output_devices/AudioOutputDeviceClient.h" |
#include "modules/audio_output_devices/SetSinkIdCallbacks.h" |
#include "public/platform/WebSecurityOrigin.h" |
namespace blink { |
+namespace { |
+ |
+class SetSinkIdResolver : public ScriptPromiseResolver { |
+ WTF_MAKE_NONCOPYABLE(SetSinkIdResolver); |
+public: |
+ static SetSinkIdResolver* create(ScriptState*, HTMLMediaElement&, const String& sinkId); |
+ ~SetSinkIdResolver() override = default; |
+ void startAsync(); |
+ |
+ DECLARE_VIRTUAL_TRACE(); |
+ |
+private: |
+ SetSinkIdResolver(ScriptState*, HTMLMediaElement&, const String& sinkId); |
+ void timerFired(Timer<SetSinkIdResolver>*); |
+ |
+ RefPtrWillBeMember<HTMLMediaElement> m_element; |
+ String m_sinkId; |
+ Timer<SetSinkIdResolver> m_timer; |
+}; |
+ |
+SetSinkIdResolver* SetSinkIdResolver::create(ScriptState* scriptState, HTMLMediaElement& element, const String& sinkId) |
+{ |
+ SetSinkIdResolver* resolver = new SetSinkIdResolver(scriptState, element, sinkId); |
+ resolver->suspendIfNeeded(); |
+ resolver->keepAliveWhilePending(); |
+ return resolver; |
+} |
+ |
+SetSinkIdResolver::SetSinkIdResolver(ScriptState* scriptState, HTMLMediaElement& element, const String& sinkId) |
+ : ScriptPromiseResolver(scriptState) |
+ , m_element(element) |
+ , m_sinkId(sinkId) |
+ , m_timer(this, &SetSinkIdResolver::timerFired) |
+{ |
+} |
+ |
+void SetSinkIdResolver::startAsync() |
+{ |
+ m_timer.startOneShot(0, BLINK_FROM_HERE); |
+} |
+ |
+void SetSinkIdResolver::timerFired(Timer<SetSinkIdResolver>* timer) |
+{ |
+ ExecutionContext* context = executionContext(); |
+ ASSERT(context && context->isDocument()); |
+ OwnPtr<SetSinkIdCallbacks> callbacks = adoptPtr(new SetSinkIdCallbacks(this, *m_element, m_sinkId)); |
+ WebMediaPlayer* webMediaPlayer = m_element->webMediaPlayer(); |
+ if (webMediaPlayer) { |
+ // Using leakPtr() to transfer ownership because |webMediaPlayer| is a platform object that takes raw pointers |
+ webMediaPlayer->setSinkId(m_sinkId, WebSecurityOrigin(context->securityOrigin()), callbacks.leakPtr()); |
+ } else { |
+ if (AudioOutputDeviceClient* client = AudioOutputDeviceClient::from(context)) { |
+ client->checkIfAudioSinkExistsAndIsAuthorized(context, m_sinkId, callbacks.release()); |
+ } else { |
+ // The context has been detached. Impossible to get a security origin to check. |
+ ASSERT(context->activeDOMObjectsAreStopped()); |
+ reject(DOMException::create(SecurityError, "Impossible to authorize device for detached context")); |
+ } |
+ } |
+} |
+ |
+DEFINE_TRACE(SetSinkIdResolver) |
+{ |
+ visitor->trace(m_element); |
+ ScriptPromiseResolver::trace(visitor); |
+} |
+ |
+} // namespace |
+ |
HTMLMediaElementAudioOutputDevice::HTMLMediaElementAudioOutputDevice() |
: m_sinkId("") |
{ |
@@ -31,18 +101,14 @@ void HTMLMediaElementAudioOutputDevice::setSinkId(const String& sinkId) |
ScriptPromise HTMLMediaElementAudioOutputDevice::setSinkId(ScriptState* scriptState, HTMLMediaElement& element, const String& sinkId) |
{ |
- ASSERT(scriptState); |
- |
- WebMediaPlayer* webMediaPlayer = element.webMediaPlayer(); |
- if (!webMediaPlayer) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(AbortError, "No media player available")); |
- |
- ExecutionContext* context = scriptState->executionContext(); |
- ASSERT(context && context->isDocument()); |
+ SetSinkIdResolver* resolver = SetSinkIdResolver::create(scriptState, element, sinkId); |
+ ScriptPromise promise = resolver->promise(); |
+ if (sinkId == HTMLMediaElementAudioOutputDevice::sinkId(element)) |
+ resolver->resolve(); |
+ else |
+ resolver->startAsync(); |
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
- webMediaPlayer->setSinkId(sinkId, WebSecurityOrigin(context->securityOrigin()), new SetSinkIdCallbacks(resolver, element, sinkId)); |
- return resolver->promise(); |
+ return promise; |
} |
const char* HTMLMediaElementAudioOutputDevice::supplementName() |