Merge "MidiDevice: Add support for making direct connections between ports"

This commit is contained in:
Mike Lockwood
2015-03-11 19:43:29 +00:00
committed by Android (Google) Code Review
4 changed files with 98 additions and 3 deletions

View File

@@ -24,4 +24,7 @@ interface IMidiDeviceServer
ParcelFileDescriptor openInputPort(IBinder token, int portNumber);
ParcelFileDescriptor openOutputPort(IBinder token, int portNumber);
void closePort(IBinder token);
// connects the input port pfd to the specified output port
void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
}

View File

@@ -26,6 +26,8 @@ import android.util.Log;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
import java.io.Closeable;
import java.io.IOException;
@@ -44,8 +46,29 @@ public final class MidiDevice implements Closeable {
private Context mContext;
private ServiceConnection mServiceConnection;
private final CloseGuard mGuard = CloseGuard.get();
public class MidiConnection implements Closeable {
private final IBinder mToken;
private final MidiInputPort mInputPort;
MidiConnection(IBinder token, MidiInputPort inputPort) {
mToken = token;
mInputPort = inputPort;
}
@Override
public void close() throws IOException {
try {
mDeviceServer.closePort(mToken);
IoUtils.closeQuietly(mInputPort);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MidiConnection.close");
}
}
}
/* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
this(deviceInfo, server, null, null);
}
@@ -108,6 +131,36 @@ public final class MidiDevice implements Closeable {
}
}
/**
* Connects the supplied {@link MidiInputPort} to the output port of this device
* with the specified port number. Once the connection is made, the MidiInput port instance
* can no longer receive data via its {@link MidiReciever.receive} method.
* This method returns a {@link #MidiConnection} object, which can be used to close the connection
* @param inputPort the inputPort to connect
* @param outputPortNumber the port number of the output port to connect inputPort to.
* @return {@link #MidiConnection} object if the connection is successful, or null in case of failure
*/
public MidiConnection connectPorts(MidiInputPort inputPort, int outputPortNumber) {
if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
throw new IllegalArgumentException("outputPortNumber out of range");
}
ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
if (pfd == null) {
return null;
}
try {
IBinder token = new Binder();
mDeviceServer.connectPorts(token, pfd, outputPortNumber);
// close our copy of the file descriptor
IoUtils.closeQuietly(pfd);
return new MidiConnection(token, inputPort);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in connectPorts");
return null;
}
}
@Override
public void close() throws IOException {
synchronized (mGuard) {

View File

@@ -200,6 +200,18 @@ public final class MidiDeviceServer implements Closeable {
}
}
}
@Override
public void connectPorts(IBinder token, ParcelFileDescriptor pfd,
int outputPortNumber) {
MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
mOutputPortDispatchers[outputPortNumber].getSender().connect(inputPort);
mInputPorts.add(inputPort);
OutputPortClient client = new OutputPortClient(token, inputPort);
synchronized (mPortClients) {
mPortClients.put(token, client);
}
}
};
/* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,

View File

@@ -41,7 +41,8 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
private IMidiDeviceServer mDeviceServer;
private final IBinder mToken;
private final int mPortNumber;
private final FileOutputStream mOutputStream;
private ParcelFileDescriptor mParcelFileDescriptor;
private FileOutputStream mOutputStream;
private final CloseGuard mGuard = CloseGuard.get();
private boolean mIsClosed;
@@ -53,8 +54,9 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
ParcelFileDescriptor pfd, int portNumber) {
mDeviceServer = server;
mToken = token;
mParcelFileDescriptor = pfd;
mPortNumber = portNumber;
mOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
mOutputStream = new FileOutputStream(pfd.getFileDescriptor());
mGuard.open("close");
}
@@ -89,11 +91,27 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
}
synchronized (mBuffer) {
if (mOutputStream == null) {
throw new IOException("MidiInputPort is closed");
}
int length = MidiPortImpl.packMessage(msg, offset, count, timestamp, mBuffer);
mOutputStream.write(mBuffer, 0, length);
}
}
// used by MidiDevice.connectInputPort() to connect our socket directly to another device
/* package */ ParcelFileDescriptor claimFileDescriptor() {
synchronized (mBuffer) {
ParcelFileDescriptor pfd = mParcelFileDescriptor;
if (pfd != null) {
IoUtils.closeQuietly(mOutputStream);
mParcelFileDescriptor = null;
mOutputStream = null;
}
return pfd;
}
}
@Override
public int getMaxMessageSize() {
return MidiPortImpl.MAX_PACKET_DATA_SIZE;
@@ -104,7 +122,16 @@ public final class MidiInputPort extends MidiReceiver implements Closeable {
synchronized (mGuard) {
if (mIsClosed) return;
mGuard.close();
mOutputStream.close();
synchronized (mBuffer) {
if (mParcelFileDescriptor != null) {
mParcelFileDescriptor.close();
mParcelFileDescriptor = null;
}
if (mOutputStream != null) {
mOutputStream.close();
mOutputStream = null;
}
}
if (mDeviceServer != null) {
try {
mDeviceServer.closePort(mToken);