Merge changes Ib5cc22db,I93e0c449,I65cd4cfd,I1cef3bd4,I628c0468

* changes:
  MIDI Manager: Add explicit close mechanism for input and output ports
  MidiDeviceService: Add getDeviceInfo() accessor method
  Add MidiDevice.close() method so we can clean up our ServiceConnection
  Make MidiSender and MidiReceiver abstract classes, rename MidiReceiver.post() to receive()
  Eliminate MidiPort base class for MidiInputPort and MidiOutputPort
This commit is contained in:
Mike Lockwood
2015-03-07 23:50:36 +00:00
committed by Android (Google) Code Review
12 changed files with 279 additions and 147 deletions

View File

@@ -21,6 +21,7 @@ import android.os.ParcelFileDescriptor;
/** @hide */
interface IMidiDeviceServer
{
ParcelFileDescriptor openInputPort(int portNumber);
ParcelFileDescriptor openOutputPort(int portNumber);
ParcelFileDescriptor openInputPort(IBinder token, int portNumber);
ParcelFileDescriptor openOutputPort(IBinder token, int portNumber);
void closePort(IBinder token);
}

View File

@@ -16,10 +16,17 @@
package android.media.midi;
import android.content.Context;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
/**
* This class is used for sending and receiving data to and from an MIDI device
* Instances of this class are created by {@link MidiManager#openDevice}.
@@ -27,19 +34,27 @@ import android.util.Log;
* CANDIDATE FOR PUBLIC API
* @hide
*/
public final class MidiDevice {
public final class MidiDevice implements Closeable {
private static final String TAG = "MidiDevice";
private final MidiDeviceInfo mDeviceInfo;
private final IMidiDeviceServer mServer;
private final IMidiDeviceServer mDeviceServer;
private Context mContext;
private ServiceConnection mServiceConnection;
/**
* MidiDevice should only be instantiated by MidiManager
* @hide
*/
public MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
/* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
mDeviceInfo = deviceInfo;
mServer = server;
mDeviceServer = server;
mContext = null;
mServiceConnection = null;
}
/* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server,
Context context, ServiceConnection serviceConnection) {
mDeviceInfo = deviceInfo;
mDeviceServer = server;
mContext = context;
mServiceConnection = serviceConnection;
}
/**
@@ -59,11 +74,12 @@ public final class MidiDevice {
*/
public MidiInputPort openInputPort(int portNumber) {
try {
ParcelFileDescriptor pfd = mServer.openInputPort(portNumber);
IBinder token = new Binder();
ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
if (pfd == null) {
return null;
}
return new MidiInputPort(pfd, portNumber);
return new MidiInputPort(mDeviceServer, token, pfd, portNumber);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openInputPort");
return null;
@@ -78,17 +94,27 @@ public final class MidiDevice {
*/
public MidiOutputPort openOutputPort(int portNumber) {
try {
ParcelFileDescriptor pfd = mServer.openOutputPort(portNumber);
IBinder token = new Binder();
ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
if (pfd == null) {
return null;
}
return new MidiOutputPort(pfd, portNumber);
return new MidiOutputPort(mDeviceServer, token, pfd, portNumber);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openOutputPort");
return null;
}
}
@Override
public void close() throws IOException {
if (mContext != null && mServiceConnection != null) {
mContext.unbindService(mServiceConnection);
mContext = null;
mServiceConnection = null;
}
}
@Override
public String toString() {
return ("MidiDevice: " + mDeviceInfo.toString());

View File

@@ -28,6 +28,7 @@ import libcore.io.IoUtils;
import java.io.Closeable;
import java.io.IOException;
import java.util.HashMap;
/**
* Internal class used for providing an implementation for a MIDI device.
@@ -53,11 +54,68 @@ public final class MidiDeviceServer implements Closeable {
// MidiOutputPorts for clients connected to our input ports
private final MidiOutputPort[] mInputPortOutputPorts;
abstract private class PortClient implements IBinder.DeathRecipient {
final IBinder mToken;
PortClient(IBinder token) {
mToken = token;
try {
token.linkToDeath(this, 0);
} catch (RemoteException e) {
close();
}
}
abstract void close();
@Override
public void binderDied() {
close();
}
}
private class InputPortClient extends PortClient {
private final MidiOutputPort mOutputPort;
InputPortClient(IBinder token, MidiOutputPort outputPort) {
super(token);
mOutputPort = outputPort;
}
@Override
void close() {
mToken.unlinkToDeath(this, 0);
synchronized (mInputPortOutputPorts) {
mInputPortOutputPorts[mOutputPort.getPortNumber()] = null;
}
IoUtils.closeQuietly(mOutputPort);
}
}
private class OutputPortClient extends PortClient {
private final MidiInputPort mInputPort;
OutputPortClient(IBinder token, MidiInputPort inputPort) {
super(token);
mInputPort = inputPort;
}
@Override
void close() {
mToken.unlinkToDeath(this, 0);
mOutputPortDispatchers[mInputPort.getPortNumber()].getSender().disconnect(mInputPort);
IoUtils.closeQuietly(mInputPort);
}
}
private final HashMap<IBinder, PortClient> mPortClients = new HashMap<IBinder, PortClient>();
// Binder interface stub for receiving connection requests from clients
private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
@Override
public ParcelFileDescriptor openInputPort(int portNumber) {
public ParcelFileDescriptor openInputPort(IBinder token, int portNumber) {
if (mDeviceInfo.isPrivate()) {
if (Binder.getCallingUid() != Process.myUid()) {
throw new SecurityException("Can't access private device from different UID");
@@ -78,25 +136,13 @@ public final class MidiDeviceServer implements Closeable {
try {
ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
OsConstants.SOCK_SEQPACKET);
final MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber);
MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber);
mInputPortOutputPorts[portNumber] = outputPort;
final int portNumberF = portNumber;
final MidiReceiver inputPortReceviver = mInputPortReceivers[portNumber];
outputPort.connect(new MidiReceiver() {
@Override
public void post(byte[] msg, int offset, int count, long timestamp)
throws IOException {
try {
inputPortReceviver.post(msg, offset, count, timestamp);
} catch (IOException e) {
IoUtils.closeQuietly(mInputPortOutputPorts[portNumberF]);
mInputPortOutputPorts[portNumberF] = null;
// FIXME also flush the receiver
}
}
});
outputPort.connect(mInputPortReceivers[portNumber]);
InputPortClient client = new InputPortClient(token, outputPort);
synchronized (mPortClients) {
mPortClients.put(token, client);
}
return pair[1];
} catch (IOException e) {
Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort");
@@ -106,7 +152,7 @@ public final class MidiDeviceServer implements Closeable {
}
@Override
public ParcelFileDescriptor openOutputPort(int portNumber) {
public ParcelFileDescriptor openOutputPort(IBinder token, int portNumber) {
if (mDeviceInfo.isPrivate()) {
if (Binder.getCallingUid() != Process.myUid()) {
throw new SecurityException("Can't access private device from different UID");
@@ -121,28 +167,28 @@ public final class MidiDeviceServer implements Closeable {
try {
ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
OsConstants.SOCK_SEQPACKET);
final MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
final MidiSender sender = mOutputPortDispatchers[portNumber].getSender();
sender.connect(new MidiReceiver() {
@Override
public void post(byte[] msg, int offset, int count, long timestamp)
throws IOException {
try {
inputPort.post(msg, offset, count, timestamp);
} catch (IOException e) {
IoUtils.closeQuietly(inputPort);
sender.disconnect(this);
// FIXME also flush the receiver?
}
}
});
MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
mOutputPortDispatchers[portNumber].getSender().connect(inputPort);
OutputPortClient client = new OutputPortClient(token, inputPort);
synchronized (mPortClients) {
mPortClients.put(token, client);
}
return pair[1];
} catch (IOException e) {
Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
return null;
}
}
@Override
public void closePort(IBinder token) {
synchronized (mPortClients) {
PortClient client = mPortClients.remove(token);
if (client != null) {
client.close();
}
}
}
};
/* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,

View File

@@ -55,6 +55,7 @@ abstract public class MidiDeviceService extends Service {
private IMidiManager mMidiManager;
private MidiDeviceServer mServer;
private MidiDeviceInfo mDeviceInfo;
@Override
public void onCreate() {
@@ -64,6 +65,11 @@ abstract public class MidiDeviceService extends Service {
try {
MidiDeviceInfo deviceInfo = mMidiManager.getServiceDeviceInfo(getPackageName(),
this.getClass().getName());
if (deviceInfo == null) {
Log.e(TAG, "Could not find MidiDeviceInfo for MidiDeviceService " + this);
return;
}
mDeviceInfo = deviceInfo;
MidiReceiver[] inputPortReceivers = getInputPortReceivers();
if (inputPortReceivers == null) {
inputPortReceivers = new MidiReceiver[0];
@@ -100,6 +106,14 @@ abstract public class MidiDeviceService extends Service {
}
}
/**
* returns the {@link MidiDeviceInfo} instance for this service
* @return our MidiDeviceInfo
*/
public MidiDeviceInfo getDeviceInfo() {
return mDeviceInfo;
}
@Override
public IBinder onBind(Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) {

View File

@@ -24,12 +24,12 @@ import java.util.ArrayList;
* This class subclasses {@link MidiReceiver} and dispatches any data it receives
* to its receiver list. Any receivers that throw an exception upon receiving data will
* be automatically removed from the receiver list, but no IOException will be returned
* from the dispatcher's {@link #post} in that case.
* from the dispatcher's {@link #receive} in that case.
*
* CANDIDATE FOR PUBLIC API
* @hide
*/
public class MidiDispatcher implements MidiReceiver {
public class MidiDispatcher extends MidiReceiver {
private final ArrayList<MidiReceiver> mReceivers = new ArrayList<MidiReceiver>();
@@ -71,12 +71,12 @@ public class MidiDispatcher implements MidiReceiver {
}
@Override
public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
public void receive(byte[] msg, int offset, int count, long timestamp) throws IOException {
synchronized (mReceivers) {
for (int i = 0; i < mReceivers.size(); ) {
MidiReceiver receiver = mReceivers.get(i);
try {
receiver.post(msg, offset, count, timestamp);
receiver.receive(msg, offset, count, timestamp);
i++; // increment only on success. on failure we remove the receiver
// so i should not be incremented
} catch (IOException e) {

View File

@@ -16,10 +16,16 @@
package android.media.midi;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
import java.io.Closeable;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -29,52 +35,88 @@ import java.io.IOException;
* CANDIDATE FOR PUBLIC API
* @hide
*/
public class MidiInputPort extends MidiPort implements MidiReceiver {
public class MidiInputPort extends MidiReceiver implements Closeable {
private static final String TAG = "MidiInputPort";
private final IMidiDeviceServer mDeviceServer;
private final IBinder mToken;
private final int mPortNumber;
private final FileOutputStream mOutputStream;
// buffer to use for sending messages out our output stream
private final byte[] mBuffer = new byte[MAX_PACKET_SIZE];
private final CloseGuard mGuard = CloseGuard.get();
/* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
// buffer to use for sending data out our output stream
private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
/* package */ MidiInputPort(IMidiDeviceServer server, IBinder token,
ParcelFileDescriptor pfd, int portNumber) {
mDeviceServer = server;
mToken = token;
mPortNumber = portNumber;
mOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
mGuard.open("close");
}
/* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
this(null, null, pfd, portNumber);
}
/**
* Writes a MIDI message to the input port
* Returns the port number of this port
*
* @param msg byte array containing the message
* @param offset offset of first byte of the message in msg byte array
* @param count size of the message in bytes
* @param timestamp future time to post the message (based on
* @return the port's port number
*/
public final int getPortNumber() {
return mPortNumber;
}
/**
* Writes MIDI data to the input port
*
* @param msg byte array containing the data
* @param offset offset of first byte of the data in msg byte array
* @param count size of the data in bytes
* @param timestamp future time to post the data (based on
* {@link java.lang.System#nanoTime}
*/
public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
public void receive(byte[] msg, int offset, int count, long timestamp) throws IOException {
assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
synchronized (mBuffer) {
try {
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);
while (count > 0) {
int length = MidiPortImpl.packMessage(msg, offset, count, timestamp, mBuffer);
mOutputStream.write(mBuffer, 0, length);
int sent = MidiPortImpl.getMessageSize(mBuffer, length);
assert(sent >= 0 && sent <= length);
offset += sent;
count -= sent;
}
} catch (IOException e) {
IoUtils.closeQuietly(mOutputStream);
// report I/O failure
onIOException();
throw e;
offset += sent;
count -= sent;
}
}
}
@Override
public void close() throws IOException {
mGuard.close();
mOutputStream.close();
if (mDeviceServer != null) {
try {
mDeviceServer.closePort(mToken);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MidiInputPort.close()");
}
}
}
@Override
protected void finalize() throws Throwable {
try {
if (mGuard != null) {
mGuard.warnIfOpen();
}
close();
} finally {
super.finalize();
}
}
}

View File

@@ -223,7 +223,7 @@ public class MidiManager {
public void onServiceConnected(ComponentName name, IBinder binder) {
IMidiDeviceServer server =
IMidiDeviceServer.Stub.asInterface(binder);
MidiDevice device = new MidiDevice(deviceInfoF, server);
MidiDevice device = new MidiDevice(deviceInfoF, server, mContext, this);
sendOpenDeviceResponse(deviceInfoF, device, callbackF, handlerF);
}

View File

@@ -16,11 +16,16 @@
package android.media.midi;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.IOException;
@@ -30,18 +35,23 @@ import java.io.IOException;
* CANDIDATE FOR PUBLIC API
* @hide
*/
public class MidiOutputPort extends MidiPort implements MidiSender {
public class MidiOutputPort extends MidiSender implements Closeable {
private static final String TAG = "MidiOutputPort";
private final IMidiDeviceServer mDeviceServer;
private final IBinder mToken;
private final int mPortNumber;
private final FileInputStream mInputStream;
private final MidiDispatcher mDispatcher = new MidiDispatcher();
private final CloseGuard mGuard = CloseGuard.get();
// This thread reads MIDI events from a socket and distributes them to the list of
// MidiReceivers attached to this device.
private final Thread mThread = new Thread() {
@Override
public void run() {
byte[] buffer = new byte[MAX_PACKET_SIZE];
byte[] buffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
try {
while (true) {
@@ -52,12 +62,12 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
// FIXME - inform receivers here?
}
int offset = getMessageOffset(buffer, count);
int size = getMessageSize(buffer, count);
long timestamp = getMessageTimeStamp(buffer, count);
int offset = MidiPortImpl.getMessageOffset(buffer, count);
int size = MidiPortImpl.getMessageSize(buffer, count);
long timestamp = MidiPortImpl.getMessageTimeStamp(buffer, count);
// dispatch to all our receivers
mDispatcher.post(buffer, offset, size, timestamp);
mDispatcher.receive(buffer, offset, size, timestamp);
}
} catch (IOException e) {
// FIXME report I/O failure?
@@ -68,10 +78,27 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
}
};
/* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
/* package */ MidiOutputPort(IMidiDeviceServer server, IBinder token,
ParcelFileDescriptor pfd, int portNumber) {
mDeviceServer = server;
mToken = token;
mPortNumber = portNumber;
mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
mThread.start();
mGuard.open("close");
}
/* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
this(null, null, pfd, portNumber);
}
/**
* Returns the port number of this port
*
* @return the port's port number
*/
public final int getPortNumber() {
return mPortNumber;
}
@Override
@@ -86,6 +113,26 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
@Override
public void close() throws IOException {
mGuard.close();
mInputStream.close();
if (mDeviceServer != null) {
try {
mDeviceServer.closePort(mToken);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MidiOutputPort.close()");
}
}
}
@Override
protected void finalize() throws Throwable {
try {
if (mGuard != null) {
mGuard.warnIfOpen();
}
close();
} finally {
super.finalize();
}
}
}

View File

@@ -16,31 +16,20 @@
package android.media.midi;
import java.io.Closeable;
/**
* This class represents a MIDI input or output port.
* Base class for {@link MidiInputPort} and {@link MidiOutputPort}
*
* CANDIDATE FOR PUBLIC API
* @hide
* This class contains utilities for socket communication between a
* MidiInputPort and MidiOutputPort
*/
abstract public class MidiPort implements Closeable {
/* package */ class MidiPortImpl {
private static final String TAG = "MidiPort";
private final int mPortNumber;
/**
* Maximum size of a packet that can pass through our ParcelFileDescriptor.
* For internal use only. Implementation details may change in the future.
* @hide
*/
public static final int MAX_PACKET_SIZE = 1024;
/**
* size of message timestamp in bytes
* For internal use only. Implementation details may change in the future.
* @hide
*/
private static final int TIMESTAMP_SIZE = 8;
@@ -49,29 +38,6 @@ abstract public class MidiPort implements Closeable {
*/
public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
/* package */ MidiPort(int portNumber) {
mPortNumber = portNumber;
}
/**
* Returns the port number of this port
*
* @return the port's port number
*/
public final int getPortNumber() {
return mPortNumber;
}
/**
* Called when an IOExeption occurs while sending or receiving data.
* Subclasses can override to be notified of such errors
*
* @hide
*/
public void onIOException() {
}
/**
* Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
*
@@ -80,9 +46,6 @@ abstract public class MidiPort implements Closeable {
* timestamp is message timestamp to pack
* dest is buffer to pack into
* returns size of packed message
*
* For internal use only. Implementation details may change in the future.
* @hide
*/
public static int packMessage(byte[] message, int offset, int size, long timestamp,
byte[] dest) {
@@ -104,9 +67,6 @@ abstract public class MidiPort implements Closeable {
/**
* Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
* returns the offset of the MIDI message in packed buffer
*
* For internal use only. Implementation details may change in the future.
* @hide
*/
public static int getMessageOffset(byte[] buffer, int bufferLength) {
// message is at the beginning
@@ -116,9 +76,6 @@ abstract public class MidiPort implements Closeable {
/**
* Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
* returns size of MIDI data in packed buffer
*
* For internal use only. Implementation details may change in the future.
* @hide
*/
public static int getMessageSize(byte[] buffer, int bufferLength) {
// message length is total buffer length minus size of the timestamp
@@ -128,9 +85,6 @@ abstract public class MidiPort implements Closeable {
/**
* Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
* unpacks timestamp from packed buffer
*
* For internal use only. Implementation details may change in the future.
* @hide
*/
public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
// timestamp is at end of the packet

View File

@@ -24,7 +24,7 @@ import java.io.IOException;
* CANDIDATE FOR PUBLIC API
* @hide
*/
public interface MidiReceiver {
abstract public class MidiReceiver {
/**
* Called to pass MIDI data to the receiver.
*
@@ -32,7 +32,7 @@ public interface MidiReceiver {
* 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 post() method.
* in the same application receiving incorrect values in their receive() method.
*
* @param msg a byte array containing the MIDI data
* @param offset the offset of the first byte of the data in the byte array
@@ -40,5 +40,6 @@ public interface MidiReceiver {
* @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
* @throws IOException
*/
public void post(byte[] msg, int offset, int count, long timestamp) throws IOException;
abstract public void receive(byte[] msg, int offset, int count, long timestamp)
throws IOException;
}

View File

@@ -23,18 +23,18 @@ package android.media.midi;
* CANDIDATE FOR PUBLIC API
* @hide
*/
public interface MidiSender {
abstract public class MidiSender {
/**
* Called to connect a {@link MidiReceiver} to the sender
*
* @param receiver the receiver to connect
*/
public void connect(MidiReceiver receiver);
abstract public void connect(MidiReceiver receiver);
/**
* Called to disconnect a {@link MidiReceiver} from the sender
*
* @param receiver the receiver to disconnect
*/
public void disconnect(MidiReceiver receiver);
abstract public void disconnect(MidiReceiver receiver);
}

View File

@@ -21,7 +21,6 @@ import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceServer;
import android.media.midi.MidiDispatcher;
import android.media.midi.MidiManager;
import android.media.midi.MidiPort;
import android.media.midi.MidiReceiver;
import android.media.midi.MidiSender;
import android.os.Bundle;
@@ -46,6 +45,8 @@ public final class UsbMidiDevice implements Closeable {
private final MidiReceiver[] mInputPortReceivers;
private static final int BUFFER_SIZE = 512;
// for polling multiple FileDescriptors for MIDI events
private final StructPollfd[] mPollFDs;
// streams for reading from ALSA driver
@@ -102,7 +103,7 @@ public final class UsbMidiDevice implements Closeable {
final int portF = port;
mInputPortReceivers[port] = new MidiReceiver() {
@Override
public void post(byte[] data, int offset, int count, long timestamp)
public void receive(byte[] data, int offset, int count, long timestamp)
throws IOException {
// FIXME - timestamps are ignored, future posting not supported yet.
mOutputStreams[portF].write(data, offset, count);
@@ -130,7 +131,7 @@ public final class UsbMidiDevice implements Closeable {
new Thread() {
@Override
public void run() {
byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE];
byte[] buffer = new byte[BUFFER_SIZE];
try {
boolean done = false;
while (!done) {
@@ -143,7 +144,7 @@ public final class UsbMidiDevice implements Closeable {
int count = mInputStreams[index].read(buffer);
long timestamp = System.nanoTime();
outputReceivers[index].post(buffer, 0, count, timestamp);
outputReceivers[index].receive(buffer, 0, count, timestamp);
} else if ((pfd.revents & (OsConstants.POLLERR
| OsConstants.POLLHUP)) != 0) {
done = true;