Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70bea137 authored by Mike Lockwood's avatar Mike Lockwood Committed by Android (Google) Code Review
Browse files

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

parents 5fcf44b1 46326e59
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
}
+53 −0
Original line number Diff line number Diff line
@@ -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) {
+12 −0
Original line number Diff line number Diff line
@@ -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,
+30 −3
Original line number Diff line number Diff line
@@ -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();
            synchronized (mBuffer) {
                if (mParcelFileDescriptor != null) {
                    mParcelFileDescriptor.close();
                    mParcelFileDescriptor = null;
                }
                if (mOutputStream != null) {
                    mOutputStream.close();
                    mOutputStream = null;
                }
            }
            if (mDeviceServer != null) {
                try {
                    mDeviceServer.closePort(mToken);