blob: e47baa473dcef7cd5f5809bb6c03c7fb979543a6 [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 "third_party/blink/renderer/modules/webmidi/midi_access_initializer.h"
#include "third_party/blink/public/platform/interface_provider.h"
#include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
#include "third_party/blink/renderer/modules/webmidi/midi_access.h"
#include "third_party/blink/renderer/modules/webmidi/midi_options.h"
#include "third_party/blink/renderer/modules/webmidi/midi_port.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
namespace blink {
using midi::mojom::PortState;
using midi::mojom::Result;
using mojom::blink::PermissionStatus;
MIDIAccessInitializer::MIDIAccessInitializer(ScriptState* script_state,
const MIDIOptions* options)
: ScriptPromiseResolver(script_state), options_(options) {}
void MIDIAccessInitializer::ContextDestroyed(ExecutionContext* context) {
accessor_.reset();
permission_service_.reset();
ScriptPromiseResolver::ContextDestroyed(context);
}
ScriptPromise MIDIAccessInitializer::Start() {
ScriptPromise promise = this->Promise();
accessor_ = MIDIAccessor::Create(this);
// See https://bit.ly/2S0zRAS for task types.
ConnectToPermissionService(
GetExecutionContext(),
mojo::MakeRequest(
&permission_service_,
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
Document& doc = To<Document>(*GetExecutionContext());
permission_service_->RequestPermission(
CreateMidiPermissionDescriptor(options_->hasSysex() && options_->sysex()),
LocalFrame::HasTransientUserActivation(doc.GetFrame()),
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(accessor_);
port_descriptors_.push_back(PortDescriptor(
id, manufacturer, name, MIDIPort::kTypeInput, version, state));
}
void MIDIAccessInitializer::DidAddOutputPort(const String& id,
const String& manufacturer,
const String& name,
const String& version,
PortState state) {
DCHECK(accessor_);
port_descriptors_.push_back(PortDescriptor(
id, manufacturer, name, MIDIPort::kTypeOutput, version, state));
}
void MIDIAccessInitializer::DidSetInputPortState(unsigned port_index,
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 port_index,
PortState state) {
// See comments on didSetInputPortState().
NOTREACHED();
}
void MIDIAccessInitializer::DidStartSession(Result result) {
DCHECK(accessor_);
// We would also have AbortError and SecurityError according to the spec.
// SecurityError is handled in onPermission(s)Updated().
switch (result) {
case Result::NOT_INITIALIZED:
break;
case Result::OK:
return Resolve(MIDIAccess::Create(
std::move(accessor_), options_->hasSysex() && options_->sysex(),
port_descriptors_, GetExecutionContext()));
case Result::NOT_SUPPORTED:
return Reject(DOMException::Create(DOMExceptionCode::kNotSupportedError));
case Result::INITIALIZATION_ERROR:
return Reject(
DOMException::Create(DOMExceptionCode::kInvalidStateError,
"Platform dependent initialization failed."));
}
NOTREACHED();
Reject(DOMException::Create(DOMExceptionCode::kInvalidStateError,
"Unknown internal error occurred."));
}
void MIDIAccessInitializer::Trace(Visitor* visitor) {
visitor->Trace(options_);
ScriptPromiseResolver::Trace(visitor);
}
ExecutionContext* MIDIAccessInitializer::GetExecutionContext() const {
return ExecutionContext::From(GetScriptState());
}
void MIDIAccessInitializer::OnPermissionsUpdated(PermissionStatus status) {
permission_service_.reset();
if (status == PermissionStatus::GRANTED)
accessor_->StartSession();
else
Reject(DOMException::Create(DOMExceptionCode::kSecurityError));
}
void MIDIAccessInitializer::OnPermissionUpdated(PermissionStatus status) {
permission_service_.reset();
if (status == PermissionStatus::GRANTED)
accessor_->StartSession();
else
Reject(DOMException::Create(DOMExceptionCode::kSecurityError));
}
} // namespace blink