OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "config.h" | 5 #include "config.h" |
6 #include "modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.h" | 6 #include "modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.h" |
7 | 7 |
8 #include "bindings/core/v8/ScriptPromiseResolver.h" | 8 #include "bindings/core/v8/ScriptPromiseResolver.h" |
9 #include "bindings/core/v8/ScriptState.h" | 9 #include "bindings/core/v8/ScriptState.h" |
10 #include "core/dom/ExecutionContext.h" | 10 #include "core/dom/ExecutionContext.h" |
| 11 #include "modules/audio_output_devices/AudioOutputDeviceClient.h" |
11 #include "modules/audio_output_devices/SetSinkIdCallbacks.h" | 12 #include "modules/audio_output_devices/SetSinkIdCallbacks.h" |
12 #include "public/platform/WebSecurityOrigin.h" | 13 #include "public/platform/WebSecurityOrigin.h" |
13 | 14 |
14 namespace blink { | 15 namespace blink { |
15 | 16 |
| 17 namespace { |
| 18 |
| 19 class SetSinkIdResolver : public ScriptPromiseResolver { |
| 20 WTF_MAKE_NONCOPYABLE(SetSinkIdResolver); |
| 21 public: |
| 22 static SetSinkIdResolver* create(ScriptState*, HTMLMediaElement&, const Stri
ng& sinkId); |
| 23 ~SetSinkIdResolver() override = default; |
| 24 void startAsync(); |
| 25 |
| 26 DECLARE_VIRTUAL_TRACE(); |
| 27 |
| 28 private: |
| 29 SetSinkIdResolver(ScriptState*, HTMLMediaElement&, const String& sinkId); |
| 30 void timerFired(Timer<SetSinkIdResolver>*); |
| 31 |
| 32 RefPtrWillBeMember<HTMLMediaElement> m_element; |
| 33 String m_sinkId; |
| 34 Timer<SetSinkIdResolver> m_timer; |
| 35 }; |
| 36 |
| 37 SetSinkIdResolver* SetSinkIdResolver::create(ScriptState* scriptState, HTMLMedia
Element& element, const String& sinkId) |
| 38 { |
| 39 SetSinkIdResolver* resolver = new SetSinkIdResolver(scriptState, element, si
nkId); |
| 40 resolver->suspendIfNeeded(); |
| 41 resolver->keepAliveWhilePending(); |
| 42 return resolver; |
| 43 } |
| 44 |
| 45 SetSinkIdResolver::SetSinkIdResolver(ScriptState* scriptState, HTMLMediaElement&
element, const String& sinkId) |
| 46 : ScriptPromiseResolver(scriptState) |
| 47 , m_element(element) |
| 48 , m_sinkId(sinkId) |
| 49 , m_timer(this, &SetSinkIdResolver::timerFired) |
| 50 { |
| 51 } |
| 52 |
| 53 void SetSinkIdResolver::startAsync() |
| 54 { |
| 55 m_timer.startOneShot(0, BLINK_FROM_HERE); |
| 56 } |
| 57 |
| 58 void SetSinkIdResolver::timerFired(Timer<SetSinkIdResolver>* timer) |
| 59 { |
| 60 ExecutionContext* context = executionContext(); |
| 61 ASSERT(context && context->isDocument()); |
| 62 OwnPtr<SetSinkIdCallbacks> callbacks = adoptPtr(new SetSinkIdCallbacks(this,
*m_element, m_sinkId)); |
| 63 WebMediaPlayer* webMediaPlayer = m_element->webMediaPlayer(); |
| 64 if (webMediaPlayer) { |
| 65 // Using leakPtr() to transfer ownership because |webMediaPlayer| is a p
latform object that takes raw pointers |
| 66 webMediaPlayer->setSinkId(m_sinkId, WebSecurityOrigin(context->securityO
rigin()), callbacks.leakPtr()); |
| 67 } else { |
| 68 if (AudioOutputDeviceClient* client = AudioOutputDeviceClient::from(cont
ext)) { |
| 69 client->checkIfAudioSinkExistsAndIsAuthorized(context, m_sinkId, cal
lbacks.release()); |
| 70 } else { |
| 71 // The context has been detached. Impossible to get a security origi
n to check. |
| 72 ASSERT(context->activeDOMObjectsAreStopped()); |
| 73 reject(DOMException::create(SecurityError, "Impossible to authorize
device for detached context")); |
| 74 } |
| 75 } |
| 76 } |
| 77 |
| 78 DEFINE_TRACE(SetSinkIdResolver) |
| 79 { |
| 80 visitor->trace(m_element); |
| 81 ScriptPromiseResolver::trace(visitor); |
| 82 } |
| 83 |
| 84 } // namespace |
| 85 |
16 HTMLMediaElementAudioOutputDevice::HTMLMediaElementAudioOutputDevice() | 86 HTMLMediaElementAudioOutputDevice::HTMLMediaElementAudioOutputDevice() |
17 : m_sinkId("") | 87 : m_sinkId("") |
18 { | 88 { |
19 } | 89 } |
20 | 90 |
21 String HTMLMediaElementAudioOutputDevice::sinkId(HTMLMediaElement& element) | 91 String HTMLMediaElementAudioOutputDevice::sinkId(HTMLMediaElement& element) |
22 { | 92 { |
23 HTMLMediaElementAudioOutputDevice& aodElement = HTMLMediaElementAudioOutputD
evice::from(element); | 93 HTMLMediaElementAudioOutputDevice& aodElement = HTMLMediaElementAudioOutputD
evice::from(element); |
24 return aodElement.m_sinkId; | 94 return aodElement.m_sinkId; |
25 } | 95 } |
26 | 96 |
27 void HTMLMediaElementAudioOutputDevice::setSinkId(const String& sinkId) | 97 void HTMLMediaElementAudioOutputDevice::setSinkId(const String& sinkId) |
28 { | 98 { |
29 m_sinkId = sinkId; | 99 m_sinkId = sinkId; |
30 } | 100 } |
31 | 101 |
32 ScriptPromise HTMLMediaElementAudioOutputDevice::setSinkId(ScriptState* scriptSt
ate, HTMLMediaElement& element, const String& sinkId) | 102 ScriptPromise HTMLMediaElementAudioOutputDevice::setSinkId(ScriptState* scriptSt
ate, HTMLMediaElement& element, const String& sinkId) |
33 { | 103 { |
34 ASSERT(scriptState); | 104 SetSinkIdResolver* resolver = SetSinkIdResolver::create(scriptState, element
, sinkId); |
| 105 ScriptPromise promise = resolver->promise(); |
| 106 if (sinkId == HTMLMediaElementAudioOutputDevice::sinkId(element)) |
| 107 resolver->resolve(); |
| 108 else |
| 109 resolver->startAsync(); |
35 | 110 |
36 WebMediaPlayer* webMediaPlayer = element.webMediaPlayer(); | 111 return promise; |
37 if (!webMediaPlayer) | |
38 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(AbortError, "No media player available")); | |
39 | |
40 ExecutionContext* context = scriptState->executionContext(); | |
41 ASSERT(context && context->isDocument()); | |
42 | |
43 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | |
44 webMediaPlayer->setSinkId(sinkId, WebSecurityOrigin(context->securityOrigin(
)), new SetSinkIdCallbacks(resolver, element, sinkId)); | |
45 return resolver->promise(); | |
46 } | 112 } |
47 | 113 |
48 const char* HTMLMediaElementAudioOutputDevice::supplementName() | 114 const char* HTMLMediaElementAudioOutputDevice::supplementName() |
49 { | 115 { |
50 return "HTMLMediaElementAudioOutputDevice"; | 116 return "HTMLMediaElementAudioOutputDevice"; |
51 } | 117 } |
52 | 118 |
53 HTMLMediaElementAudioOutputDevice& HTMLMediaElementAudioOutputDevice::from(HTMLM
ediaElement& element) | 119 HTMLMediaElementAudioOutputDevice& HTMLMediaElementAudioOutputDevice::from(HTMLM
ediaElement& element) |
54 { | 120 { |
55 HTMLMediaElementAudioOutputDevice* supplement = static_cast<HTMLMediaElement
AudioOutputDevice*>(WillBeHeapSupplement<HTMLMediaElement>::from(element, supple
mentName())); | 121 HTMLMediaElementAudioOutputDevice* supplement = static_cast<HTMLMediaElement
AudioOutputDevice*>(WillBeHeapSupplement<HTMLMediaElement>::from(element, supple
mentName())); |
56 if (!supplement) { | 122 if (!supplement) { |
57 supplement = new HTMLMediaElementAudioOutputDevice(); | 123 supplement = new HTMLMediaElementAudioOutputDevice(); |
58 provideTo(element, supplementName(), adoptPtrWillBeNoop(supplement)); | 124 provideTo(element, supplementName(), adoptPtrWillBeNoop(supplement)); |
59 } | 125 } |
60 return *supplement; | 126 return *supplement; |
61 } | 127 } |
62 | 128 |
63 DEFINE_TRACE(HTMLMediaElementAudioOutputDevice) | 129 DEFINE_TRACE(HTMLMediaElementAudioOutputDevice) |
64 { | 130 { |
65 WillBeHeapSupplement<HTMLMediaElement>::trace(visitor); | 131 WillBeHeapSupplement<HTMLMediaElement>::trace(visitor); |
66 } | 132 } |
67 | 133 |
68 } // namespace blink | 134 } // namespace blink |
OLD | NEW |