summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/midi/MidiInputPort.java15
-rw-r--r--core/java/android/midi/MidiOutputPort.java6
-rw-r--r--core/java/android/midi/MidiPort.java56
-rw-r--r--core/java/android/midi/MidiReceiver.java2
-rw-r--r--core/java/android/midi/MidiUtils.java65
-rw-r--r--services/usb/java/com/android/server/usb/UsbMidiDevice.java31
6 files changed, 53 insertions, 122 deletions
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
index 5d806cf..88ace5f 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/core/java/android/midi/MidiInputPort.java
@@ -33,7 +33,7 @@ public class MidiInputPort extends MidiPort implements MidiReceiver {
private final FileOutputStream mOutputStream;
// buffer to use for sending messages out our output stream
- private final byte[] mBuffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+ private final byte[] mBuffer = new byte[MAX_PACKET_SIZE];
/* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
@@ -50,10 +50,19 @@ public class MidiInputPort extends MidiPort implements MidiReceiver {
* {@link java.lang.System#nanoTime}
*/
public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
+
synchronized (mBuffer) {
- int length = packMessage(msg, offset, count, timestamp, mBuffer);
try {
- mOutputStream.write(mBuffer, 0, length);
+ while (count > 0) {
+ int length = packMessage(msg, offset, count, timestamp, mBuffer);
+ mOutputStream.write(mBuffer, 0, length);
+ int sent = getMessageSize(mBuffer, length);
+ assert(sent >= 0 && sent <= length);
+
+ offset += sent;
+ count -= sent;
+ }
} catch (IOException e) {
IoUtils.closeQuietly(mOutputStream);
// report I/O failure
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
index b550ed4..00b7bad 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -45,7 +45,7 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
private final Thread mThread = new Thread() {
@Override
public void run() {
- byte[] buffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+ byte[] buffer = new byte[MAX_PACKET_SIZE];
ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
try {
@@ -54,9 +54,6 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
int count = mInputStream.read(buffer);
if (count < 0) {
break;
- } else if (count < MIN_PACKED_MESSAGE_SIZE || count > MAX_PACKED_MESSAGE_SIZE) {
- Log.e(TAG, "Number of bytes read out of range: " + count);
- continue;
}
int offset = getMessageOffset(buffer, count);
@@ -96,7 +93,6 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
}
};
-
/* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
diff --git a/core/java/android/midi/MidiPort.java b/core/java/android/midi/MidiPort.java
index 1fa7946..44d1a88 100644
--- a/core/java/android/midi/MidiPort.java
+++ b/core/java/android/midi/MidiPort.java
@@ -32,16 +32,19 @@ abstract public class MidiPort implements Closeable {
private final int mPortNumber;
/**
- * Minimum size of packed message as sent through our ParcelFileDescriptor
- * 8 bytes for timestamp and 1 to 3 bytes for message
+ * Maximum size of a packet that can pass through our ParcelFileDescriptor
*/
- protected static final int MIN_PACKED_MESSAGE_SIZE = 9;
+ protected static final int MAX_PACKET_SIZE = 1024;
/**
- * Maximum size of packed message as sent through our ParcelFileDescriptor
- * 8 bytes for timestamp and 1 to 3 bytes for message
+ * size of message timestamp in bytes
*/
- protected static final int MAX_PACKED_MESSAGE_SIZE = 11;
+ private static final int TIMESTAMP_SIZE = 8;
+
+ /**
+ * Maximum amount of MIDI data that can be included in a packet
+ */
+ public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
/* package */ MidiPort(int portNumber) {
@@ -76,49 +79,52 @@ abstract public class MidiPort implements Closeable {
*/
protected static int packMessage(byte[] message, int offset, int size, long timestamp,
byte[] dest) {
- // pack variable length message first
+ if (size + TIMESTAMP_SIZE > MAX_PACKET_SIZE) {
+ size = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+ }
+ // message data goes first
System.arraycopy(message, offset, dest, 0, size);
- int destOffset = size;
- // timestamp takes 8 bytes
- for (int i = 0; i < 8; i++) {
- dest[destOffset++] = (byte)timestamp;
+
+ // followed by timestamp
+ for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+ dest[size++] = (byte)timestamp;
timestamp >>= 8;
}
- return destOffset;
+ return size;
}
/**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * returns the offet of of MIDI message in packed buffer
+ * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+ * returns the offset of the MIDI message in packed buffer
*/
protected static int getMessageOffset(byte[] buffer, int bufferLength) {
- // message is at start of buffer
+ // message is at the beginning
return 0;
}
/**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * returns size of MIDI message in packed buffer
+ * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+ * returns size of MIDI data in packed buffer
*/
protected static int getMessageSize(byte[] buffer, int bufferLength) {
- // message length is total buffer length minus size of the timestamp and port number
- return bufferLength - 8 /* sizeof(timestamp) */;
+ // message length is total buffer length minus size of the timestamp
+ return bufferLength - TIMESTAMP_SIZE;
}
/**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
* unpacks timestamp from packed buffer
*/
protected static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+ // timestamp is at end of the packet
+ int offset = bufferLength;
long timestamp = 0;
- // timestamp follows variable length message data
- int dataLength = getMessageSize(buffer, bufferLength);
- for (int i = dataLength + 7; i >= dataLength; i--) {
- int b = (int)buffer[i] & 0xFF;
+ for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+ int b = (int)buffer[--offset] & 0xFF;
timestamp = (timestamp << 8) | b;
}
return timestamp;
- }
+ }
}
diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java
index 0b183cc..a4e1a10 100644
--- a/core/java/android/midi/MidiReceiver.java
+++ b/core/java/android/midi/MidiReceiver.java
@@ -30,6 +30,8 @@ public interface MidiReceiver {
* NOTE: the msg array parameter is only valid within the context of this call.
* The msg bytes should be copied by the receiver rather than retaining a reference
* to this parameter.
+ * Also, modifying the contents of the msg array parameter may result in other receivers
+ * in the same application receiving incorrect values in their onPost() method.
*
* @param msg a byte array containing the MIDI message
* @param offset the offset of the first byte of the message in the byte array
diff --git a/core/java/android/midi/MidiUtils.java b/core/java/android/midi/MidiUtils.java
deleted file mode 100644
index e60e2db..0000000
--- a/core/java/android/midi/MidiUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.midi;
-
-import android.util.Log;
-
-/**
- * Class containing miscellaneous MIDI utilities.
- *
- * @hide
- */
-public final class MidiUtils {
- private static final String TAG = "MidiUtils";
-
- private MidiUtils() { }
-
- /**
- * Returns data size of a MIDI message based on the message's command byte
- * @param b the message command byte
- * @return the message's data length
- */
- public static int getMessageDataSize(byte b) {
- switch (b & 0xF0) {
- case 0x80:
- case 0x90:
- case 0xA0:
- case 0xB0:
- case 0xE0:
- return 2;
- case 0xC0:
- case 0xD0:
- return 1;
- case 0xF0:
- switch (b & 0x0F) {
- case 0x00:
- Log.e(TAG, "System Exclusive not supported yet");
- return -1;
- case 0x01:
- case 0x03:
- return 1;
- case 0x02:
- return 2;
- default:
- return 0;
- }
- default:
- Log.e(TAG, "unknown MIDI command " + b);
- return -1;
- }
- }
-}
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 01b2df9..0ca52f6 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -21,9 +21,9 @@ import android.hardware.usb.UsbDevice;
import android.midi.MidiDeviceInfo;
import android.midi.MidiDeviceServer;
import android.midi.MidiManager;
+import android.midi.MidiPort;
import android.midi.MidiReceiver;
import android.midi.MidiSender;
-import android.midi.MidiUtils;
import android.os.Bundle;
import android.system.ErrnoException;
import android.system.Os;
@@ -45,7 +45,9 @@ public final class UsbMidiDevice implements Closeable {
// for polling multiple FileDescriptors for MIDI events
private final StructPollfd[] mPollFDs;
+ // streams for reading from ALSA driver
private final FileInputStream[] mInputStreams;
+ // streams for writing to ALSA driver
private final FileOutputStream[] mOutputStreams;
public static UsbMidiDevice create(Context context, UsbDevice usbDevice, int card, int device) {
@@ -131,7 +133,7 @@ public final class UsbMidiDevice implements Closeable {
new Thread() {
@Override
public void run() {
- byte[] buffer = new byte[3];
+ byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE];
try {
boolean done = false;
while (!done) {
@@ -141,7 +143,8 @@ public final class UsbMidiDevice implements Closeable {
if ((pfd.revents & OsConstants.POLLIN) != 0) {
// clear readable flag
pfd.revents = 0;
- int count = readMessage(buffer, index);
+
+ int count = mInputStreams[index].read(buffer);
mOutputPortReceivers[index].onPost(buffer, 0, count,
System.nanoTime());
} else if ((pfd.revents & (OsConstants.POLLERR
@@ -150,7 +153,7 @@ public final class UsbMidiDevice implements Closeable {
}
}
- // poll if none are readable
+ // wait until we have a readable port
Os.poll(mPollFDs, -1 /* infinite timeout */);
}
} catch (IOException e) {
@@ -174,26 +177,6 @@ public final class UsbMidiDevice implements Closeable {
}
}
- private int readMessage(byte[] buffer, int index) throws IOException {
- FileInputStream inputStream = mInputStreams[index];
-
- if (inputStream.read(buffer, 0, 1) != 1) {
- Log.e(TAG, "could not read command byte");
- return -1;
- }
- int dataSize = MidiUtils.getMessageDataSize(buffer[0]);
- if (dataSize < 0) {
- return -1;
- }
- if (dataSize > 0) {
- if (inputStream.read(buffer, 1, dataSize) != dataSize) {
- Log.e(TAG, "could not read command data");
- return -1;
- }
- }
- return dataSize + 1;
- }
-
private static native int nativeGetSubdeviceCount(int card, int device);
private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
}