Merge "Squashed commit of the following:"
This commit is contained in:
@@ -26,11 +26,23 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
* Utility class for dispatching MIDI data to a list of {@link android.media.midi.MidiReceiver}s.
|
* Utility class for dispatching MIDI data to a list of {@link android.media.midi.MidiReceiver}s.
|
||||||
* This class subclasses {@link android.media.midi.MidiReceiver} and dispatches any data it receives
|
* This class subclasses {@link android.media.midi.MidiReceiver} and dispatches any data it receives
|
||||||
* to its receiver list. Any receivers that throw an exception upon receiving data will
|
* 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
|
* be automatically removed from the receiver list. If a MidiReceiverFailureHandler has been
|
||||||
* from the dispatcher's {@link android.media.midi.MidiReceiver#onSend} in that case.
|
* provided to the MidiDispatcher, it will be notified about the failure, but the exception
|
||||||
|
* itself will be swallowed.
|
||||||
*/
|
*/
|
||||||
public final class MidiDispatcher extends MidiReceiver {
|
public final class MidiDispatcher extends MidiReceiver {
|
||||||
|
|
||||||
|
// MidiDispatcher's client and MidiReceiver's owner can be different
|
||||||
|
// classes (e.g. MidiDeviceService is a client, but MidiDeviceServer is
|
||||||
|
// the owner), and errors occuring during sending need to be reported
|
||||||
|
// to the owner rather than to the sender.
|
||||||
|
//
|
||||||
|
// Note that the callbacks will be called on the sender's thread.
|
||||||
|
public interface MidiReceiverFailureHandler {
|
||||||
|
void onReceiverFailure(MidiReceiver receiver, IOException failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final MidiReceiverFailureHandler mFailureHandler;
|
||||||
private final CopyOnWriteArrayList<MidiReceiver> mReceivers
|
private final CopyOnWriteArrayList<MidiReceiver> mReceivers
|
||||||
= new CopyOnWriteArrayList<MidiReceiver>();
|
= new CopyOnWriteArrayList<MidiReceiver>();
|
||||||
|
|
||||||
@@ -46,6 +58,14 @@ public final class MidiDispatcher extends MidiReceiver {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public MidiDispatcher() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MidiDispatcher(MidiReceiverFailureHandler failureHandler) {
|
||||||
|
mFailureHandler = failureHandler;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of {@link android.media.midi.MidiReceiver}s this dispatcher contains.
|
* Returns the number of {@link android.media.midi.MidiReceiver}s this dispatcher contains.
|
||||||
* @return the number of receivers
|
* @return the number of receivers
|
||||||
@@ -70,8 +90,13 @@ public final class MidiDispatcher extends MidiReceiver {
|
|||||||
try {
|
try {
|
||||||
receiver.send(msg, offset, count, timestamp);
|
receiver.send(msg, offset, count, timestamp);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// if the receiver fails we remove the receiver but do not propagate the exception
|
// If the receiver fails we remove the receiver but do not propagate the exception.
|
||||||
|
// Note that this may also happen if the client code stalls, and thus underlying
|
||||||
|
// MidiInputPort.onSend has raised IOException for EAGAIN / EWOULDBLOCK error.
|
||||||
mReceivers.remove(receiver);
|
mReceivers.remove(receiver);
|
||||||
|
if (mFailureHandler != null) {
|
||||||
|
mFailureHandler.onReceiverFailure(receiver, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +104,15 @@ public final class MidiDispatcher extends MidiReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onFlush() throws IOException {
|
public void onFlush() throws IOException {
|
||||||
for (MidiReceiver receiver : mReceivers) {
|
for (MidiReceiver receiver : mReceivers) {
|
||||||
receiver.flush();
|
try {
|
||||||
|
receiver.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// This is just a special case of 'send' thus handle in the same way.
|
||||||
|
mReceivers.remove(receiver);
|
||||||
|
if (mFailureHandler != null) {
|
||||||
|
mFailureHandler.onReceiverFailure(receiver, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ interface IMidiDeviceServer
|
|||||||
void closeDevice();
|
void closeDevice();
|
||||||
|
|
||||||
// connects the input port pfd to the specified output port
|
// connects the input port pfd to the specified output port
|
||||||
void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
|
// Returns the PID of the called process.
|
||||||
|
int connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
|
||||||
|
|
||||||
MidiDeviceInfo getDeviceInfo();
|
MidiDeviceInfo getDeviceInfo();
|
||||||
void setDeviceInfo(in MidiDeviceInfo deviceInfo);
|
void setDeviceInfo(in MidiDeviceInfo deviceInfo);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package android.media.midi;
|
|||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ public final class MidiDevice implements Closeable {
|
|||||||
private final IMidiManager mMidiManager;
|
private final IMidiManager mMidiManager;
|
||||||
private final IBinder mClientToken;
|
private final IBinder mClientToken;
|
||||||
private final IBinder mDeviceToken;
|
private final IBinder mDeviceToken;
|
||||||
|
private boolean mIsDeviceClosed;
|
||||||
|
|
||||||
private final CloseGuard mGuard = CloseGuard.get();
|
private final CloseGuard mGuard = CloseGuard.get();
|
||||||
|
|
||||||
@@ -122,6 +124,9 @@ public final class MidiDevice implements Closeable {
|
|||||||
* or null in case of failure.
|
* or null in case of failure.
|
||||||
*/
|
*/
|
||||||
public MidiInputPort openInputPort(int portNumber) {
|
public MidiInputPort openInputPort(int portNumber) {
|
||||||
|
if (mIsDeviceClosed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
IBinder token = new Binder();
|
IBinder token = new Binder();
|
||||||
ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
|
ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
|
||||||
@@ -145,6 +150,9 @@ public final class MidiDevice implements Closeable {
|
|||||||
* or null in case of failure.
|
* or null in case of failure.
|
||||||
*/
|
*/
|
||||||
public MidiOutputPort openOutputPort(int portNumber) {
|
public MidiOutputPort openOutputPort(int portNumber) {
|
||||||
|
if (mIsDeviceClosed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
IBinder token = new Binder();
|
IBinder token = new Binder();
|
||||||
ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
|
ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
|
||||||
@@ -174,16 +182,26 @@ public final class MidiDevice implements Closeable {
|
|||||||
if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
|
if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
|
||||||
throw new IllegalArgumentException("outputPortNumber out of range");
|
throw new IllegalArgumentException("outputPortNumber out of range");
|
||||||
}
|
}
|
||||||
|
if (mIsDeviceClosed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
|
ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
|
||||||
if (pfd == null) {
|
if (pfd == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
IBinder token = new Binder();
|
IBinder token = new Binder();
|
||||||
mDeviceServer.connectPorts(token, pfd, outputPortNumber);
|
int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
|
||||||
// close our copy of the file descriptor
|
// If the service is a different Process then it will duplicate the pfd
|
||||||
IoUtils.closeQuietly(pfd);
|
// and we can safely close this one.
|
||||||
|
// But if the service is in the same Process then closing the pfd will
|
||||||
|
// kill the connection. So don't do that.
|
||||||
|
if (calleePid != Process.myPid()) {
|
||||||
|
// close our copy of the file descriptor
|
||||||
|
IoUtils.closeQuietly(pfd);
|
||||||
|
}
|
||||||
|
|
||||||
return new MidiConnection(token, inputPort);
|
return new MidiConnection(token, inputPort);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException in connectPorts");
|
Log.e(TAG, "RemoteException in connectPorts");
|
||||||
@@ -194,11 +212,14 @@ public final class MidiDevice implements Closeable {
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
synchronized (mGuard) {
|
synchronized (mGuard) {
|
||||||
mGuard.close();
|
if (!mIsDeviceClosed) {
|
||||||
try {
|
mGuard.close();
|
||||||
mMidiManager.closeDevice(mClientToken, mDeviceToken);
|
mIsDeviceClosed = true;
|
||||||
} catch (RemoteException e) {
|
try {
|
||||||
Log.e(TAG, "RemoteException in closeDevice");
|
mMidiManager.closeDevice(mClientToken, mDeviceToken);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "RemoteException in closeDevice");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
|
|
||||||
private final Callback mCallback;
|
private final Callback mCallback;
|
||||||
|
|
||||||
|
private final HashMap<IBinder, PortClient> mPortClients = new HashMap<IBinder, PortClient>();
|
||||||
|
private final HashMap<MidiInputPort, PortClient> mInputPortClients =
|
||||||
|
new HashMap<MidiInputPort, PortClient>();
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
/**
|
/**
|
||||||
* Called to notify when an our device status has changed
|
* Called to notify when an our device status has changed
|
||||||
@@ -102,6 +106,10 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
|
|
||||||
abstract void close();
|
abstract void close();
|
||||||
|
|
||||||
|
MidiInputPort getInputPort() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
close();
|
close();
|
||||||
@@ -152,9 +160,12 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
mInputPorts.remove(mInputPort);
|
mInputPorts.remove(mInputPort);
|
||||||
IoUtils.closeQuietly(mInputPort);
|
IoUtils.closeQuietly(mInputPort);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private final HashMap<IBinder, PortClient> mPortClients = new HashMap<IBinder, PortClient>();
|
@Override
|
||||||
|
MidiInputPort getInputPort() {
|
||||||
|
return mInputPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Binder interface stub for receiving connection requests from clients
|
// Binder interface stub for receiving connection requests from clients
|
||||||
private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
|
private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
|
||||||
@@ -215,6 +226,12 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
|
ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
|
||||||
OsConstants.SOCK_SEQPACKET);
|
OsConstants.SOCK_SEQPACKET);
|
||||||
MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
|
MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
|
||||||
|
// Undo the default blocking-mode of the server-side socket for
|
||||||
|
// physical devices to avoid stalling the Java device handler if
|
||||||
|
// client app code gets stuck inside 'onSend' handler.
|
||||||
|
if (mDeviceInfo.getType() != MidiDeviceInfo.TYPE_VIRTUAL) {
|
||||||
|
IoUtils.setBlocking(pair[0].getFileDescriptor(), false);
|
||||||
|
}
|
||||||
MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber];
|
MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber];
|
||||||
synchronized (dispatcher) {
|
synchronized (dispatcher) {
|
||||||
dispatcher.getSender().connect(inputPort);
|
dispatcher.getSender().connect(inputPort);
|
||||||
@@ -228,6 +245,9 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
synchronized (mPortClients) {
|
synchronized (mPortClients) {
|
||||||
mPortClients.put(token, client);
|
mPortClients.put(token, client);
|
||||||
}
|
}
|
||||||
|
synchronized (mInputPortClients) {
|
||||||
|
mInputPortClients.put(inputPort, client);
|
||||||
|
}
|
||||||
return pair[1];
|
return pair[1];
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
|
Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
|
||||||
@@ -237,12 +257,19 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closePort(IBinder token) {
|
public void closePort(IBinder token) {
|
||||||
|
MidiInputPort inputPort = null;
|
||||||
synchronized (mPortClients) {
|
synchronized (mPortClients) {
|
||||||
PortClient client = mPortClients.remove(token);
|
PortClient client = mPortClients.remove(token);
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
|
inputPort = client.getInputPort();
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (inputPort != null) {
|
||||||
|
synchronized (mInputPortClients) {
|
||||||
|
mInputPortClients.remove(inputPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -254,7 +281,7 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectPorts(IBinder token, ParcelFileDescriptor pfd,
|
public int connectPorts(IBinder token, ParcelFileDescriptor pfd,
|
||||||
int outputPortNumber) {
|
int outputPortNumber) {
|
||||||
MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
|
MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
|
||||||
MidiDispatcher dispatcher = mOutputPortDispatchers[outputPortNumber];
|
MidiDispatcher dispatcher = mOutputPortDispatchers[outputPortNumber];
|
||||||
@@ -270,6 +297,10 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
synchronized (mPortClients) {
|
synchronized (mPortClients) {
|
||||||
mPortClients.put(token, client);
|
mPortClients.put(token, client);
|
||||||
}
|
}
|
||||||
|
synchronized (mInputPortClients) {
|
||||||
|
mInputPortClients.put(inputPort, client);
|
||||||
|
}
|
||||||
|
return Process.myPid(); // for caller to detect same process ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -302,7 +333,7 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
|
|
||||||
mOutputPortDispatchers = new MidiDispatcher[numOutputPorts];
|
mOutputPortDispatchers = new MidiDispatcher[numOutputPorts];
|
||||||
for (int i = 0; i < numOutputPorts; i++) {
|
for (int i = 0; i < numOutputPorts; i++) {
|
||||||
mOutputPortDispatchers[i] = new MidiDispatcher();
|
mOutputPortDispatchers[i] = new MidiDispatcher(mInputPortFailureHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
mInputPortOpen = new boolean[mInputPortCount];
|
mInputPortOpen = new boolean[mInputPortCount];
|
||||||
@@ -311,6 +342,20 @@ public final class MidiDeviceServer implements Closeable {
|
|||||||
mGuard.open("close");
|
mGuard.open("close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final MidiDispatcher.MidiReceiverFailureHandler mInputPortFailureHandler =
|
||||||
|
new MidiDispatcher.MidiReceiverFailureHandler() {
|
||||||
|
public void onReceiverFailure(MidiReceiver receiver, IOException failure) {
|
||||||
|
Log.e(TAG, "MidiInputPort failed to send data", failure);
|
||||||
|
PortClient client = null;
|
||||||
|
synchronized (mInputPortClients) {
|
||||||
|
client = mInputPortClients.remove(receiver);
|
||||||
|
}
|
||||||
|
if (client != null) {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Constructor for MidiDeviceService.onCreate()
|
// Constructor for MidiDeviceService.onCreate()
|
||||||
/* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
|
/* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
|
||||||
MidiDeviceInfo deviceInfo, Callback callback) {
|
MidiDeviceInfo deviceInfo, Callback callback) {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public final class MidiOutputPort extends MidiSender implements Closeable {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// FIXME report I/O failure?
|
// FIXME report I/O failure?
|
||||||
Log.e(TAG, "read failed");
|
Log.e(TAG, "read failed", e);
|
||||||
} finally {
|
} finally {
|
||||||
IoUtils.closeQuietly(mInputStream);
|
IoUtils.closeQuietly(mInputStream);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<p>Android MIDI User Guide</p>
|
|
||||||
|
<p>
|
||||||
|
Provides classes for sending and receiving messages using the standard MIDI
|
||||||
|
event protocol over USB, Bluetooth LE, and virtual (inter-app) transports.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h1 id=overview>Overview</h1>
|
<h1 id=overview>Overview</h1>
|
||||||
|
|
||||||
|
|
||||||
<p>This document describes how to use the Android MIDI API in Java.</p>
|
|
||||||
|
|
||||||
<p>The Android MIDI package allows users to:</p>
|
<p>The Android MIDI package allows users to:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ public class MidiService extends IMidiManager.Stub {
|
|||||||
// This client's PID
|
// This client's PID
|
||||||
private final int mPid;
|
private final int mPid;
|
||||||
// List of all receivers for this client
|
// List of all receivers for this client
|
||||||
private final ArrayList<IMidiDeviceListener> mListeners
|
private final HashMap<IBinder, IMidiDeviceListener> mListeners
|
||||||
= new ArrayList<IMidiDeviceListener>();
|
= new HashMap<IBinder, IMidiDeviceListener>();
|
||||||
// List of all device connections for this client
|
// List of all device connections for this client
|
||||||
private final HashMap<IBinder, DeviceConnection> mDeviceConnections
|
private final HashMap<IBinder, DeviceConnection> mDeviceConnections
|
||||||
= new HashMap<IBinder, DeviceConnection>();
|
= new HashMap<IBinder, DeviceConnection>();
|
||||||
@@ -143,11 +143,13 @@ public class MidiService extends IMidiManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(IMidiDeviceListener listener) {
|
public void addListener(IMidiDeviceListener listener) {
|
||||||
mListeners.add(listener);
|
// Use asBinder() so that we can match it in removeListener().
|
||||||
|
// The listener proxy objects themselves do not match.
|
||||||
|
mListeners.put(listener.asBinder(), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeListener(IMidiDeviceListener listener) {
|
public void removeListener(IMidiDeviceListener listener) {
|
||||||
mListeners.remove(listener);
|
mListeners.remove(listener.asBinder());
|
||||||
if (mListeners.size() == 0 && mDeviceConnections.size() == 0) {
|
if (mListeners.size() == 0 && mDeviceConnections.size() == 0) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -184,7 +186,7 @@ public class MidiService extends IMidiManager.Stub {
|
|||||||
|
|
||||||
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
|
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
|
||||||
try {
|
try {
|
||||||
for (IMidiDeviceListener listener : mListeners) {
|
for (IMidiDeviceListener listener : mListeners.values()) {
|
||||||
listener.onDeviceAdded(deviceInfo);
|
listener.onDeviceAdded(deviceInfo);
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@@ -198,7 +200,7 @@ public class MidiService extends IMidiManager.Stub {
|
|||||||
|
|
||||||
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
|
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
|
||||||
try {
|
try {
|
||||||
for (IMidiDeviceListener listener : mListeners) {
|
for (IMidiDeviceListener listener : mListeners.values()) {
|
||||||
listener.onDeviceRemoved(deviceInfo);
|
listener.onDeviceRemoved(deviceInfo);
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@@ -211,7 +213,7 @@ public class MidiService extends IMidiManager.Stub {
|
|||||||
if (!device.isUidAllowed(mUid)) return;
|
if (!device.isUidAllowed(mUid)) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (IMidiDeviceListener listener : mListeners) {
|
for (IMidiDeviceListener listener : mListeners.values()) {
|
||||||
listener.onDeviceStatusChanged(status);
|
listener.onDeviceStatusChanged(status);
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public final class UsbMidiDevice implements Closeable {
|
|||||||
|
|
||||||
private MidiDeviceServer mServer;
|
private MidiDeviceServer mServer;
|
||||||
|
|
||||||
// event schedulers for each output port
|
// event schedulers for each input port of the physical device
|
||||||
private MidiEventScheduler[] mEventSchedulers;
|
private MidiEventScheduler[] mEventSchedulers;
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 512;
|
private static final int BUFFER_SIZE = 512;
|
||||||
@@ -160,9 +160,9 @@ public final class UsbMidiDevice implements Closeable {
|
|||||||
mSubdeviceCount = subdeviceCount;
|
mSubdeviceCount = subdeviceCount;
|
||||||
|
|
||||||
// FIXME - support devices with different number of input and output ports
|
// FIXME - support devices with different number of input and output ports
|
||||||
int inputCount = subdeviceCount;
|
int inputPortCount = subdeviceCount;
|
||||||
mInputPortReceivers = new InputReceiverProxy[inputCount];
|
mInputPortReceivers = new InputReceiverProxy[inputPortCount];
|
||||||
for (int port = 0; port < inputCount; port++) {
|
for (int port = 0; port < inputPortCount; port++) {
|
||||||
mInputPortReceivers[port] = new InputReceiverProxy();
|
mInputPortReceivers[port] = new InputReceiverProxy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,14 +176,14 @@ public final class UsbMidiDevice implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mFileDescriptors = fileDescriptors;
|
mFileDescriptors = fileDescriptors;
|
||||||
int inputCount = fileDescriptors.length;
|
int inputStreamCount = fileDescriptors.length;
|
||||||
// last file descriptor returned from nativeOpen() is only used for unblocking Os.poll()
|
// last file descriptor returned from nativeOpen() is only used for unblocking Os.poll()
|
||||||
// in our input thread
|
// in our input thread
|
||||||
int outputCount = fileDescriptors.length - 1;
|
int outputStreamCount = fileDescriptors.length - 1;
|
||||||
|
|
||||||
mPollFDs = new StructPollfd[inputCount];
|
mPollFDs = new StructPollfd[inputStreamCount];
|
||||||
mInputStreams = new FileInputStream[inputCount];
|
mInputStreams = new FileInputStream[inputStreamCount];
|
||||||
for (int i = 0; i < inputCount; i++) {
|
for (int i = 0; i < inputStreamCount; i++) {
|
||||||
FileDescriptor fd = fileDescriptors[i];
|
FileDescriptor fd = fileDescriptors[i];
|
||||||
StructPollfd pollfd = new StructPollfd();
|
StructPollfd pollfd = new StructPollfd();
|
||||||
pollfd.fd = fd;
|
pollfd.fd = fd;
|
||||||
@@ -192,9 +192,9 @@ public final class UsbMidiDevice implements Closeable {
|
|||||||
mInputStreams[i] = new FileInputStream(fd);
|
mInputStreams[i] = new FileInputStream(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
mOutputStreams = new FileOutputStream[outputCount];
|
mOutputStreams = new FileOutputStream[outputStreamCount];
|
||||||
mEventSchedulers = new MidiEventScheduler[outputCount];
|
mEventSchedulers = new MidiEventScheduler[outputStreamCount];
|
||||||
for (int i = 0; i < outputCount; i++) {
|
for (int i = 0; i < outputStreamCount; i++) {
|
||||||
mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
|
mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
|
||||||
|
|
||||||
MidiEventScheduler scheduler = new MidiEventScheduler();
|
MidiEventScheduler scheduler = new MidiEventScheduler();
|
||||||
@@ -204,7 +204,7 @@ public final class UsbMidiDevice implements Closeable {
|
|||||||
|
|
||||||
final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
|
final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
|
||||||
|
|
||||||
// Create input thread which will read from all input ports
|
// Create input thread which will read from all output ports of the physical device
|
||||||
new Thread("UsbMidiDevice input thread") {
|
new Thread("UsbMidiDevice input thread") {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -249,8 +249,8 @@ public final class UsbMidiDevice implements Closeable {
|
|||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
|
|
||||||
// Create output thread for each output port
|
// Create output thread for each input port of the physical device
|
||||||
for (int port = 0; port < outputCount; port++) {
|
for (int port = 0; port < outputStreamCount; port++) {
|
||||||
final MidiEventScheduler eventSchedulerF = mEventSchedulers[port];
|
final MidiEventScheduler eventSchedulerF = mEventSchedulers[port];
|
||||||
final FileOutputStream outputStreamF = mOutputStreams[port];
|
final FileOutputStream outputStreamF = mOutputStreams[port];
|
||||||
final int portF = port;
|
final int portF = port;
|
||||||
|
|||||||
Reference in New Issue
Block a user