blob: c693ee65faf33747d617e25d9c60c93ea104be40 [file] [log] [blame]
// Copyright 2014 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/webmidi/MIDIAccessInitializer.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "core/dom/Document.h"
#include "core/dom/ExceptionCode.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Navigator.h"
#include "modules/webmidi/MIDIAccess.h"
#include "modules/webmidi/MIDIOptions.h"
#include "modules/webmidi/MIDIPort.h"
#include "platform/UserGestureIndicator.h"
#include "platform/mojo/MojoHelper.h"
#include "public/platform/ServiceRegistry.h"
#include "third_party/WebKit/public/platform/modules/permissions/permission.mojom-blink.h"
namespace blink {
using PortState = WebMIDIAccessorClient::MIDIPortState;
using mojom::blink::PermissionName;
using mojom::blink::PermissionStatus;
MIDIAccessInitializer::MIDIAccessInitializer(ScriptState* scriptState, const MIDIOptions& options)
: ScriptPromiseResolver(scriptState)
, m_options(options)
{
}
void MIDIAccessInitializer::contextDestroyed()
{
m_permissionService.reset();
LifecycleObserver::contextDestroyed();
}
ScriptPromise MIDIAccessInitializer::start()
{
ScriptPromise promise = this->promise();
m_accessor = MIDIAccessor::create(this);
Document* document = toDocument(getExecutionContext());
DCHECK(document);
document->frame()->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_permissionService));
bool requestSysEx = m_options.hasSysex() && m_options.sysex();
Vector<PermissionName> permissions;
permissions.resize(requestSysEx ? 2 : 1);
permissions[0] = PermissionName::MIDI;
if (requestSysEx)
permissions[1] = PermissionName::MIDI_SYSEX;
m_permissionService->RequestPermissions(
mojo::WTFArray<PermissionName>(std::move(permissions)),
getExecutionContext()->getSecurityOrigin()->toString(),
UserGestureIndicator::processingUserGesture(),
convertToBaseCallback(WTF::bind(&MIDIAccessInitializer::onPermissionsUpdated, wrapPersistent(this))));
return promise;
}
void MIDIAccessInitializer::didAddInputPort(const String& id, const String& manufacturer, const String& name, const String& version, PortState state)
{
DCHECK(m_accessor);
m_portDescriptors.append(PortDescriptor(id, manufacturer, name, MIDIPort::TypeInput, version, state));
}
void MIDIAccessInitializer::didAddOutputPort(const String& id, const String& manufacturer, const String& name, const String& version, PortState state)
{
DCHECK(m_accessor);
m_portDescriptors.append(PortDescriptor(id, manufacturer, name, MIDIPort::TypeOutput, version, state));
}
void MIDIAccessInitializer::didSetInputPortState(unsigned portIndex, PortState state)
{
// didSetInputPortState() is not allowed to call before didStartSession()
// is called. Once didStartSession() is called, MIDIAccessorClient methods
// are delegated to MIDIAccess. See constructor of MIDIAccess.
NOTREACHED();
}
void MIDIAccessInitializer::didSetOutputPortState(unsigned portIndex, PortState state)
{
// See comments on didSetInputPortState().
NOTREACHED();
}
void MIDIAccessInitializer::didStartSession(bool success, const String& error, const String& message)
{
DCHECK(m_accessor);
if (success) {
resolve(MIDIAccess::create(std::move(m_accessor), m_options.hasSysex() && m_options.sysex(), m_portDescriptors, getExecutionContext()));
} else {
// The spec says the name is one of
// - SecurityError
// - AbortError
// - InvalidStateError
// - NotSupportedError
// TODO(toyoshim): Do not rely on |error| string. Instead an enum
// representing an ExceptionCode should be defined and deliverred.
ExceptionCode ec = InvalidStateError;
if (error == DOMException::getErrorName(SecurityError)) {
ec = SecurityError;
} else if (error == DOMException::getErrorName(AbortError)) {
ec = AbortError;
} else if (error == DOMException::getErrorName(InvalidStateError)) {
ec = InvalidStateError;
} else if (error == DOMException::getErrorName(NotSupportedError)) {
ec = NotSupportedError;
}
reject(DOMException::create(ec, message));
}
}
ExecutionContext* MIDIAccessInitializer::getExecutionContext() const
{
return getScriptState()->getExecutionContext();
}
void MIDIAccessInitializer::onPermissionsUpdated(mojo::WTFArray<PermissionStatus> statusArray)
{
bool allowed = true;
for (const auto status : statusArray.storage()) {
if (status != PermissionStatus::GRANTED) {
allowed = false;
break;
}
}
m_permissionService.reset();
if (allowed)
m_accessor->startSession();
else
reject(DOMException::create(SecurityError));
}
void MIDIAccessInitializer::onPermissionUpdated(PermissionStatus status)
{
m_permissionService.reset();
if (status == PermissionStatus::GRANTED)
m_accessor->startSession();
else
reject(DOMException::create(SecurityError));
}
} // namespace blink