Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(669)

Unified Diff: media/base/android/java/src/org/chromium/media/UsbMidiDeviceAndroid.java

Issue 1085843003: Revert of Web MIDI: split build rules for media/midi (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/base/android/java/src/org/chromium/media/UsbMidiDeviceAndroid.java
diff --git a/media/base/android/java/src/org/chromium/media/UsbMidiDeviceAndroid.java b/media/base/android/java/src/org/chromium/media/UsbMidiDeviceAndroid.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f80b961da1b3daa56c7165243a1e55792b060e5
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/UsbMidiDeviceAndroid.java
@@ -0,0 +1,295 @@
+// 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.
+
+package org.chromium.media;
+
+import android.annotation.TargetApi;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbRequest;
+import android.os.Build;
+import android.os.Handler;
+import android.util.SparseArray;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Owned by its native counterpart declared in usb_midi_device_android.h.
+ * Refer to that class for general comments.
+ */
+@JNINamespace("media")
+class UsbMidiDeviceAndroid {
+ /**
+ * A connection handle for this device.
+ */
+ private final UsbDeviceConnection mConnection;
+
+ /**
+ * A map from endpoint number to UsbEndpoint.
+ */
+ private final SparseArray<UsbEndpoint> mEndpointMap;
+
+ /**
+ * A map from UsbEndpoint to UsbRequest associated to it.
+ */
+ private final Map<UsbEndpoint, UsbRequest> mRequestMap;
+
+ /**
+ * The handler used for posting events on the main thread.
+ */
+ private final Handler mHandler;
+
+ /**
+ * True if this device is closed.
+ */
+ private boolean mIsClosed;
+
+ /**
+ * True if there is a thread processing input data.
+ */
+ private boolean mHasInputThread;
+
+ /**
+ * The identifier of this device.
+ */
+ private long mNativePointer;
+
+ /**
+ * The underlying USB device.
+ */
+ private UsbDevice mUsbDevice;
+
+ /**
+ * Audio interface subclass code for MIDI.
+ */
+ static final int MIDI_SUBCLASS = 3;
+
+ /**
+ * Constructs a UsbMidiDeviceAndroid.
+ * @param manager
+ * @param device The USB device which this object is assocated with.
+ */
+ UsbMidiDeviceAndroid(UsbManager manager, UsbDevice device) {
+ mConnection = manager.openDevice(device);
+ mEndpointMap = new SparseArray<UsbEndpoint>();
+ mRequestMap = new HashMap<UsbEndpoint, UsbRequest>();
+ mHandler = new Handler();
+ mUsbDevice = device;
+ mIsClosed = false;
+ mHasInputThread = false;
+ mNativePointer = 0;
+
+ for (int i = 0; i < device.getInterfaceCount(); ++i) {
+ UsbInterface iface = device.getInterface(i);
+ if (iface.getInterfaceClass() != UsbConstants.USB_CLASS_AUDIO
+ || iface.getInterfaceSubclass() != MIDI_SUBCLASS) {
+ continue;
+ }
+ mConnection.claimInterface(iface, true);
+ for (int j = 0; j < iface.getEndpointCount(); ++j) {
+ UsbEndpoint endpoint = iface.getEndpoint(j);
+ if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
+ mEndpointMap.put(endpoint.getEndpointNumber(), endpoint);
+ }
+ }
+ }
+ // Start listening for input endpoints.
+ // This function will create and run a thread if there is USB-MIDI endpoints in the
+ // device. Note that because UsbMidiDevice is shared among all tabs and the thread
+ // will be terminated when the device is disconnected, at most one thread can be created
+ // for each connected USB-MIDI device.
+ startListen(device);
+ }
+
+ /**
+ * Starts listening for input endpoints.
+ */
+ private void startListen(final UsbDevice device) {
+ final Map<UsbEndpoint, ByteBuffer> bufferForEndpoints =
+ new HashMap<UsbEndpoint, ByteBuffer>();
+
+ for (int i = 0; i < device.getInterfaceCount(); ++i) {
+ UsbInterface iface = device.getInterface(i);
+ if (iface.getInterfaceClass() != UsbConstants.USB_CLASS_AUDIO
+ || iface.getInterfaceSubclass() != MIDI_SUBCLASS) {
+ continue;
+ }
+ for (int j = 0; j < iface.getEndpointCount(); ++j) {
+ UsbEndpoint endpoint = iface.getEndpoint(j);
+ if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
+ ByteBuffer buffer = ByteBuffer.allocate(endpoint.getMaxPacketSize());
+ UsbRequest request = new UsbRequest();
+ request.initialize(mConnection, endpoint);
+ request.queue(buffer, buffer.remaining());
+ bufferForEndpoints.put(endpoint, buffer);
+ }
+ }
+ }
+ if (bufferForEndpoints.isEmpty()) {
+ return;
+ }
+ mHasInputThread = true;
+ // bufferForEndpoints must not be accessed hereafter on this thread.
+ new Thread() {
+ @Override
+ public void run() {
+ while (true) {
+ UsbRequest request = mConnection.requestWait();
+ if (request == null) {
+ // When the device is closed requestWait will fail.
+ break;
+ }
+ UsbEndpoint endpoint = request.getEndpoint();
+ if (endpoint.getDirection() != UsbConstants.USB_DIR_IN) {
+ continue;
+ }
+ ByteBuffer buffer = bufferForEndpoints.get(endpoint);
+ int length = getInputDataLength(buffer);
+ if (length > 0) {
+ buffer.rewind();
+ final byte[] bs = new byte[length];
+ buffer.get(bs, 0, length);
+ postOnDataEvent(endpoint.getEndpointNumber(), bs);
+ }
+ buffer.rewind();
+ request.queue(buffer, buffer.capacity());
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * Posts a data input event to the main thread.
+ */
+ private void postOnDataEvent(final int endpointNumber, final byte[] bs) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mIsClosed) {
+ return;
+ }
+ nativeOnData(mNativePointer, endpointNumber, bs);
+ }
+ });
+ }
+
+ UsbDevice getUsbDevice() {
+ return mUsbDevice;
+ }
+
+ boolean isClosed() {
+ return mIsClosed;
+ }
+
+ /**
+ * Register the own native pointer.
+ */
+ @CalledByNative
+ void registerSelf(long nativePointer) {
+ mNativePointer = nativePointer;
+ }
+
+ /**
+ * Sends a USB-MIDI data to the device.
+ * @param endpointNumber The endpoint number of the destination endpoint.
+ * @param bs The data to be sent.
+ */
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+ @CalledByNative
+ void send(int endpointNumber, byte[] bs) {
+ if (mIsClosed) {
+ return;
+ }
+ UsbEndpoint endpoint = mEndpointMap.get(endpointNumber);
+ if (endpoint == null) {
+ return;
+ }
+ if (shouldUseBulkTransfer()) {
+ // We use bulkTransfer instead of UsbRequest.queue because queueing
+ // a UsbRequest is currently not thread safe.
+ // Note that this is not exactly correct because we don't care
+ // about the transfer attribute (bmAttribute) of the endpoint.
+ // See also:
+ // http://stackoverflow.com/questions/9644415/
+ // https://code.google.com/p/android/issues/detail?id=59467
+ //
+ // TODO(yhirano): Delete this block once the problem is fixed.
+ final int timeout = 100;
+ mConnection.bulkTransfer(endpoint, bs, bs.length, timeout);
+ } else {
+ UsbRequest request = mRequestMap.get(endpoint);
+ if (request == null) {
+ request = new UsbRequest();
+ request.initialize(mConnection, endpoint);
+ mRequestMap.put(endpoint, request);
+ }
+ request.queue(ByteBuffer.wrap(bs), bs.length);
+ }
+ }
+
+ /**
+ * Returns true if |bulkTransfer| should be used in |send|.
+ * See comments in |send|.
+ */
+ private boolean shouldUseBulkTransfer() {
+ return mHasInputThread;
+ }
+
+ /**
+ * Returns the descriptors bytes of this device.
+ * @return The descriptors bytes of this device.
+ */
+ @CalledByNative
+ byte[] getDescriptors() {
+ if (mConnection == null) {
+ return new byte[0];
+ }
+ return mConnection.getRawDescriptors();
+ }
+
+ /**
+ * Closes the device connection.
+ */
+ @CalledByNative
+ void close() {
+ mEndpointMap.clear();
+ for (UsbRequest request : mRequestMap.values()) {
+ request.close();
+ }
+ mRequestMap.clear();
+ mConnection.close();
+ mNativePointer = 0;
+ mIsClosed = true;
+ }
+
+ /**
+ * Returns the length of a USB-MIDI input.
+ * Since the Android API doesn't provide us the length,
+ * we calculate it manually.
+ */
+ private static int getInputDataLength(ByteBuffer buffer) {
+ int position = buffer.position();
+ // We assume that the data length is always divisable by 4.
+ for (int i = 0; i < position; i += 4) {
+ // Since Code Index Number 0 is reserved, it is not a valid USB-MIDI data.
+ if (buffer.get(i) == 0) {
+ return i;
+ }
+ }
+ return position;
+ }
+
+ private static native void nativeOnData(long nativeUsbMidiDeviceAndroid,
+ int endpointNumber,
+ byte[] data);
+}
« no previous file with comments | « media/base/android/BUILD.gn ('k') | media/base/android/java/src/org/chromium/media/UsbMidiDeviceFactoryAndroid.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698