Skip to content

Commit

Permalink
[Web MIDI] Use Android MIDI API.
Browse files Browse the repository at this point in the history
This CL introduces WebMIDI implementation using Android native MIDI
API. The implementation is enabled only when the device has a newer sdk
version and the experimental flag "use-android-midi-api" is enabled.

BUG=486584

Review URL: https://codereview.chromium.org/1177973003

Cr-Commit-Position: refs/heads/master@{#349419}
  • Loading branch information
yutakahirano authored and Commit bot committed Sep 17, 2015
1 parent 33e9087 commit e8b2e7d
Show file tree
Hide file tree
Showing 18 changed files with 1,075 additions and 20 deletions.
12 changes: 12 additions & 0 deletions media/midi/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ if (is_android) {

generate_jni("midi_jni_headers") {
sources = [
"java/src/org/chromium/media/midi/MidiDeviceAndroid.java",
"java/src/org/chromium/media/midi/MidiInputPortAndroid.java",
"java/src/org/chromium/media/midi/MidiManagerAndroid.java",
"java/src/org/chromium/media/midi/MidiOutputPortAndroid.java",
"java/src/org/chromium/media/midi/UsbMidiDeviceAndroid.java",
"java/src/org/chromium/media/midi/UsbMidiDeviceFactoryAndroid.java",
]
Expand Down Expand Up @@ -91,10 +95,18 @@ component("midi") {
libs = []

if (is_android) {
# TODO(yhirano): Consider having "android" subdirectory.
sources += [
"midi_device_android.cc",
"midi_device_android.h",
"midi_jni_registrar.cc",
"midi_jni_registrar.h",
"midi_input_port_android.cc",
"midi_input_port_android.h",
"midi_manager_android.cc",
"midi_manager_android.h",
"midi_output_port_android.cc",
"midi_output_port_android.h",
"usb_midi_device_android.cc",
"usb_midi_device_android.h",
"usb_midi_device_factory_android.cc",
Expand Down
132 changes: 132 additions & 0 deletions media/midi/java/src/org/chromium/media/midi/MidiDeviceAndroid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// 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.

package org.chromium.media.midi;

import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;

import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;

@JNINamespace("media::midi")
/**
* A class implementing media::midi::MidiDeviceAndroid functionality.
*/
class MidiDeviceAndroid {
/**
* The underlying device.
*/
private final MidiDevice mDevice;
/**
* The input ports in the device.
*/
private final MidiInputPortAndroid[] mInputPorts;
/**
* The output ports in the device.
*/
private final MidiOutputPortAndroid[] mOutputPorts;
/**
* True when the device is open.
*/
private boolean mIsOpen;

/**
* constructor
* @param device the underlying device
*/
MidiDeviceAndroid(MidiDevice device) {
mIsOpen = true;
mDevice = device;
// Note we use "input" and "output" in the Web MIDI manner.

mOutputPorts = new MidiOutputPortAndroid[getInfo().getInputPortCount()];
for (int i = 0; i < mOutputPorts.length; ++i) {
mOutputPorts[i] = new MidiOutputPortAndroid(device, i);
}

mInputPorts = new MidiInputPortAndroid[getInfo().getOutputPortCount()];
for (int i = 0; i < mInputPorts.length; ++i) {
mInputPorts[i] = new MidiInputPortAndroid(device, i);
}
}

/**
* Returns true when the device is open.
*/
boolean isOpen() {
return mIsOpen;
}

/**
* Closes the device.
*/
void close() {
mIsOpen = false;
for (MidiInputPortAndroid port : mInputPorts) {
port.close();
}
for (MidiOutputPortAndroid port : mOutputPorts) {
port.close();
}
}

/**
* Returns the underlying device.
*/
MidiDevice getDevice() {
return mDevice;
}

/**
* Returns the underlying device information.
*/
MidiDeviceInfo getInfo() {
return mDevice.getInfo();
}

/**
* Returns the manufacturer name.
*/
@CalledByNative
String getManufacturer() {
return getProperty(MidiDeviceInfo.PROPERTY_MANUFACTURER);
}

/**
* Returns the product name.
*/
@CalledByNative
String getProduct() {
return getProperty(MidiDeviceInfo.PROPERTY_PRODUCT);
}

/**
* Returns the version string.
*/
@CalledByNative
String getVersion() {
return getProperty(MidiDeviceInfo.PROPERTY_VERSION);
}

/**
* Returns the associated input ports.
*/
@CalledByNative
MidiInputPortAndroid[] getInputPorts() {
return mInputPorts;
}

/**
* Returns the associated output ports.
*/
@CalledByNative
MidiOutputPortAndroid[] getOutputPorts() {
return mOutputPorts;
}

private String getProperty(String name) {
return mDevice.getInfo().getProperties().getString(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 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.

package org.chromium.media.midi;

import android.media.midi.MidiDevice;
import android.media.midi.MidiOutputPort;
import android.media.midi.MidiReceiver;

import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;

import java.io.IOException;

// Note "InputPort" is named in the Web MIDI manner. It corresponds to MidiOutputPort class in the
// Android API.
/**
* A MidiInputPortAndroid provides data to the associated media::midi::MidiInputPortAndroid object.
*/
@JNINamespace("media::midi")
class MidiInputPortAndroid {
/**
* The underlying port.
*/
private MidiOutputPort mPort;
/**
* A pointer to a media::midi::MidiInputPortAndroid object.
*/
private long mNativeReceiverPointer;
/**
* The device this port belongs to.
*/
private final MidiDevice mDevice;
/**
* The index of the port in the associated device.
*/
private final int mIndex;

/**
* constructor
* @param device the device this port belongs to.
* @param index the index of the port in the associated device.
*/
MidiInputPortAndroid(MidiDevice device, int index) {
mDevice = device;
mIndex = index;
}

/**
* Registers this object to the underlying port so as to the C++ function will be called with
* the given C++ object when data arrives.
* @param nativeReceiverPointer a pointer to a media::midi::MidiInputPortAndroid object.
* @return true if this operation succeeds or the port is already open.
*/
@CalledByNative
boolean open(long nativeReceiverPointer) {
if (mPort != null) {
return true;
}
mPort = mDevice.openOutputPort(mIndex);
if (mPort == null) {
return false;
}
mNativeReceiverPointer = nativeReceiverPointer;
mPort.connect(new MidiReceiver() {
@Override
public void onSend(byte[] bs, int offset, int count, long timestamp) {
nativeOnData(mNativeReceiverPointer, bs, offset, count, timestamp);
}
});
return true;
}

/**
* Closes the port.
*/
@CalledByNative
void close() {
if (mPort == null) {
return;
}
try {
mPort.close();
} catch (IOException e) {
// We can do nothing here. Just ignore the error.
}
mNativeReceiverPointer = 0;
mPort = null;
}

private static native void nativeOnData(
long nativeMidiInputPortAndroid, byte[] bs, int offset, int count, long timestamp);
}
Loading

0 comments on commit e8b2e7d

Please sign in to comment.