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 |
deleted file mode 100644 |
index c581131fb39a646638985472e7d69ad7b8dc9c57..0000000000000000000000000000000000000000 |
--- a/media/base/android/java/src/org/chromium/media/UsbMidiDeviceAndroid.java |
+++ /dev/null |
@@ -1,327 +0,0 @@ |
-// 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.Arrays; |
-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; |
- |
- /** |
- * The request type to request a USB descriptor. |
- */ |
- static final int REQUEST_GET_DESCRIPTOR = 0x06; |
- |
- /** |
- * The STRING descriptor type. |
- */ |
- static final int STRING_DESCRIPTOR_TYPE = 0x03; |
- |
- /** |
- * 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(); |
- } |
- |
- /** |
- * Returns the string descriptor bytes for the given index |
- * @param index index of the descriptor |
- * @return the string descriptor bytes for the given index. |
- */ |
- @CalledByNative |
- byte[] getStringDescriptor(int index) { |
- if (mConnection == null) { |
- return new byte[0]; |
- } |
- byte[] buffer = new byte[255]; |
- int type = UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_STANDARD; |
- int request = REQUEST_GET_DESCRIPTOR; |
- int value = (STRING_DESCRIPTOR_TYPE << 8) | index; |
- int read = mConnection.controlTransfer(type, request, value, 0, buffer, buffer.length, 0); |
- if (read < 0) { |
- return new byte[0]; |
- } |
- return Arrays.copyOf(buffer, read); |
- } |
- |
- /** |
- * 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); |
-} |