blob: f0554b43be569b0c5dc84e625b649ce0737c69ab [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.h"
#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("")
{
}
String HTMLMediaElementAudioOutputDevice::sinkId(HTMLMediaElement& element)
{
HTMLMediaElementAudioOutputDevice& aodElement = HTMLMediaElementAudioOutputDevice::from(element);
return aodElement.m_sinkId;
}
void HTMLMediaElementAudioOutputDevice::setSinkId(const String& sinkId)
{
m_sinkId = sinkId;
}
ScriptPromise HTMLMediaElementAudioOutputDevice::setSinkId(ScriptState* scriptState, HTMLMediaElement& element, const String& sinkId)
{
SetSinkIdResolver* resolver = SetSinkIdResolver::create(scriptState, element, sinkId);
ScriptPromise promise = resolver->promise();
if (sinkId == HTMLMediaElementAudioOutputDevice::sinkId(element))
resolver->resolve();
else
resolver->startAsync();
return promise;
}
const char* HTMLMediaElementAudioOutputDevice::supplementName()
{
return "HTMLMediaElementAudioOutputDevice";
}
HTMLMediaElementAudioOutputDevice& HTMLMediaElementAudioOutputDevice::from(HTMLMediaElement& element)
{
HTMLMediaElementAudioOutputDevice* supplement = static_cast<HTMLMediaElementAudioOutputDevice*>(WillBeHeapSupplement<HTMLMediaElement>::from(element, supplementName()));
if (!supplement) {
supplement = new HTMLMediaElementAudioOutputDevice();
provideTo(element, supplementName(), adoptPtrWillBeNoop(supplement));
}
return *supplement;
}
DEFINE_TRACE(HTMLMediaElementAudioOutputDevice)
{
WillBeHeapSupplement<HTMLMediaElement>::trace(visitor);
}
} // namespace blink