Merge "MidiDevice: Add support for making direct connections between ports"
This commit is contained in:
committed by
Android (Google) Code Review
commit
70bea13774
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user