Loading core/java/com/android/internal/midi/EventScheduler.java +16 −8 Original line number Diff line number Diff line Loading @@ -27,10 +27,11 @@ import java.util.TreeMap; public class EventScheduler { private static final long NANOS_PER_MILLI = 1000000; private final Object lock = new Object(); private final Object mLock = new Object(); private SortedMap<Long, FastEventQueue> mEventBuffer; private FastEventQueue mEventPool = null; private int mMaxPoolSize = 200; private boolean mClosed; public EventScheduler() { mEventBuffer = new TreeMap<Long, FastEventQueue>(); Loading Loading @@ -146,7 +147,7 @@ public class EventScheduler { * @param event */ public void add(SchedulableEvent event) { synchronized (lock) { synchronized (mLock) { FastEventQueue list = mEventBuffer.get(event.getTimestamp()); if (list == null) { long lowestTime = mEventBuffer.isEmpty() ? Long.MAX_VALUE Loading @@ -156,7 +157,7 @@ public class EventScheduler { // If the event we added is earlier than the previous earliest // event then notify any threads waiting for the next event. if (event.getTimestamp() < lowestTime) { lock.notify(); mLock.notify(); } } else { list.add(event); Loading @@ -183,7 +184,7 @@ public class EventScheduler { */ public SchedulableEvent getNextEvent(long time) { SchedulableEvent event = null; synchronized (lock) { synchronized (mLock) { if (!mEventBuffer.isEmpty()) { long lowestTime = mEventBuffer.firstKey(); // Is it time for this list to be processed? Loading @@ -206,9 +207,9 @@ public class EventScheduler { */ public SchedulableEvent waitNextEvent() throws InterruptedException { SchedulableEvent event = null; while (true) { synchronized (mLock) { while (!mClosed) { long millisToWait = Integer.MAX_VALUE; synchronized (lock) { if (!mEventBuffer.isEmpty()) { long now = System.nanoTime(); long lowestTime = mEventBuffer.firstKey(); Loading @@ -228,9 +229,16 @@ public class EventScheduler { } } } lock.wait((int) millisToWait); mLock.wait((int) millisToWait); } } return event; } public void close() { synchronized (mLock) { mClosed = true; mLock.notify(); } } } core/java/com/android/internal/midi/MidiEventScheduler.java +31 −4 Original line number Diff line number Diff line Loading @@ -28,10 +28,16 @@ public class MidiEventScheduler extends EventScheduler { // Maintain a pool of scheduled events to reduce memory allocation. // This pool increases performance by about 14%. private final static int POOL_EVENT_SIZE = 16; private MidiReceiver mReceiver = new SchedulingReceiver(); private class SchedulingReceiver extends MidiReceiver { private final MidiReceiver[] mReceivers; private class SchedulingReceiver extends MidiReceiver { private final int mPortNumber; public SchedulingReceiver(int portNumber) { mPortNumber = portNumber; } /** * Store these bytes in the EventScheduler to be delivered at the specified * time. Loading @@ -41,12 +47,14 @@ public class MidiEventScheduler extends EventScheduler { throws IOException { MidiEvent event = createScheduledEvent(msg, offset, count, timestamp); if (event != null) { event.portNumber = mPortNumber; add(event); } } } public static class MidiEvent extends SchedulableEvent { public int portNumber; public int count = 0; public byte[] data; Loading @@ -72,6 +80,17 @@ public class MidiEventScheduler extends EventScheduler { } } public MidiEventScheduler() { this(0); } public MidiEventScheduler(int portCount) { mReceivers = new MidiReceiver[portCount]; for (int i = 0; i < portCount; i++) { mReceivers[i] = new SchedulingReceiver(i); } } /** * Create an event that contains the message. */ Loading Loading @@ -113,7 +132,15 @@ public class MidiEventScheduler extends EventScheduler { * @return the MidiReceiver */ public MidiReceiver getReceiver() { return mReceiver; return mReceivers[0]; } /** * This MidiReceiver will write date to the scheduling buffer. * @return the MidiReceiver */ public MidiReceiver getReceiver(int portNumber) { return mReceivers[portNumber]; } } services/usb/java/com/android/server/usb/UsbMidiDevice.java +43 −17 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ import android.system.OsConstants; import android.system.StructPollfd; import android.util.Log; import com.android.internal.midi.MidiEventScheduler; import com.android.internal.midi.MidiEventScheduler.MidiEvent; import libcore.io.IoUtils; import java.io.Closeable; Loading @@ -42,7 +45,7 @@ public final class UsbMidiDevice implements Closeable { private MidiDeviceServer mServer; private final MidiReceiver[] mInputPortReceivers; private final MidiEventScheduler mEventScheduler; private static final int BUFFER_SIZE = 512; Loading Loading @@ -99,19 +102,7 @@ public final class UsbMidiDevice implements Closeable { for (int i = 0; i < outputCount; i++) { mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]); } mInputPortReceivers = new MidiReceiver[inputCount]; for (int port = 0; port < inputCount; port++) { final int portF = port; mInputPortReceivers[port] = new MidiReceiver() { @Override public void onReceive(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); } }; } mEventScheduler = new MidiEventScheduler(inputCount); } private boolean register(Context context, Bundle properties) { Loading @@ -121,16 +112,22 @@ public final class UsbMidiDevice implements Closeable { return false; } int inputCount = mInputStreams.length; int outputCount = mOutputStreams.length; mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount, MidiReceiver[] inputPortReceivers = new MidiReceiver[inputCount]; for (int port = 0; port < inputCount; port++) { inputPortReceivers[port] = mEventScheduler.getReceiver(port); } mServer = midiManager.createDeviceServer(inputPortReceivers, outputCount, null, null, properties, MidiDeviceInfo.TYPE_USB, null); if (mServer == null) { return false; } final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers(); // FIXME can we only run this when we have a dispatcher that has listeners? new Thread() { // Create input thread new Thread("UsbMidiDevice input thread") { @Override public void run() { byte[] buffer = new byte[BUFFER_SIZE]; Loading Loading @@ -160,6 +157,33 @@ public final class UsbMidiDevice implements Closeable { } catch (ErrnoException e) { Log.d(TAG, "reader thread exiting"); } Log.d(TAG, "input thread exit"); } }.start(); // Create output thread new Thread("UsbMidiDevice output thread") { @Override public void run() { while (true) { MidiEvent event; try { event = (MidiEvent)mEventScheduler.waitNextEvent(); } catch (InterruptedException e) { // try again continue; } if (event == null) { break; } try { mOutputStreams[event.portNumber].write(event.data, 0, event.count); } catch (IOException e) { Log.e(TAG, "write failed for port " + event.portNumber); } mEventScheduler.addEventToPool(event); } Log.d(TAG, "output thread exit"); } }.start(); Loading @@ -168,6 +192,8 @@ public final class UsbMidiDevice implements Closeable { @Override public void close() throws IOException { mEventScheduler.close(); if (mServer != null) { mServer.close(); } Loading Loading
core/java/com/android/internal/midi/EventScheduler.java +16 −8 Original line number Diff line number Diff line Loading @@ -27,10 +27,11 @@ import java.util.TreeMap; public class EventScheduler { private static final long NANOS_PER_MILLI = 1000000; private final Object lock = new Object(); private final Object mLock = new Object(); private SortedMap<Long, FastEventQueue> mEventBuffer; private FastEventQueue mEventPool = null; private int mMaxPoolSize = 200; private boolean mClosed; public EventScheduler() { mEventBuffer = new TreeMap<Long, FastEventQueue>(); Loading Loading @@ -146,7 +147,7 @@ public class EventScheduler { * @param event */ public void add(SchedulableEvent event) { synchronized (lock) { synchronized (mLock) { FastEventQueue list = mEventBuffer.get(event.getTimestamp()); if (list == null) { long lowestTime = mEventBuffer.isEmpty() ? Long.MAX_VALUE Loading @@ -156,7 +157,7 @@ public class EventScheduler { // If the event we added is earlier than the previous earliest // event then notify any threads waiting for the next event. if (event.getTimestamp() < lowestTime) { lock.notify(); mLock.notify(); } } else { list.add(event); Loading @@ -183,7 +184,7 @@ public class EventScheduler { */ public SchedulableEvent getNextEvent(long time) { SchedulableEvent event = null; synchronized (lock) { synchronized (mLock) { if (!mEventBuffer.isEmpty()) { long lowestTime = mEventBuffer.firstKey(); // Is it time for this list to be processed? Loading @@ -206,9 +207,9 @@ public class EventScheduler { */ public SchedulableEvent waitNextEvent() throws InterruptedException { SchedulableEvent event = null; while (true) { synchronized (mLock) { while (!mClosed) { long millisToWait = Integer.MAX_VALUE; synchronized (lock) { if (!mEventBuffer.isEmpty()) { long now = System.nanoTime(); long lowestTime = mEventBuffer.firstKey(); Loading @@ -228,9 +229,16 @@ public class EventScheduler { } } } lock.wait((int) millisToWait); mLock.wait((int) millisToWait); } } return event; } public void close() { synchronized (mLock) { mClosed = true; mLock.notify(); } } }
core/java/com/android/internal/midi/MidiEventScheduler.java +31 −4 Original line number Diff line number Diff line Loading @@ -28,10 +28,16 @@ public class MidiEventScheduler extends EventScheduler { // Maintain a pool of scheduled events to reduce memory allocation. // This pool increases performance by about 14%. private final static int POOL_EVENT_SIZE = 16; private MidiReceiver mReceiver = new SchedulingReceiver(); private class SchedulingReceiver extends MidiReceiver { private final MidiReceiver[] mReceivers; private class SchedulingReceiver extends MidiReceiver { private final int mPortNumber; public SchedulingReceiver(int portNumber) { mPortNumber = portNumber; } /** * Store these bytes in the EventScheduler to be delivered at the specified * time. Loading @@ -41,12 +47,14 @@ public class MidiEventScheduler extends EventScheduler { throws IOException { MidiEvent event = createScheduledEvent(msg, offset, count, timestamp); if (event != null) { event.portNumber = mPortNumber; add(event); } } } public static class MidiEvent extends SchedulableEvent { public int portNumber; public int count = 0; public byte[] data; Loading @@ -72,6 +80,17 @@ public class MidiEventScheduler extends EventScheduler { } } public MidiEventScheduler() { this(0); } public MidiEventScheduler(int portCount) { mReceivers = new MidiReceiver[portCount]; for (int i = 0; i < portCount; i++) { mReceivers[i] = new SchedulingReceiver(i); } } /** * Create an event that contains the message. */ Loading Loading @@ -113,7 +132,15 @@ public class MidiEventScheduler extends EventScheduler { * @return the MidiReceiver */ public MidiReceiver getReceiver() { return mReceiver; return mReceivers[0]; } /** * This MidiReceiver will write date to the scheduling buffer. * @return the MidiReceiver */ public MidiReceiver getReceiver(int portNumber) { return mReceivers[portNumber]; } }
services/usb/java/com/android/server/usb/UsbMidiDevice.java +43 −17 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ import android.system.OsConstants; import android.system.StructPollfd; import android.util.Log; import com.android.internal.midi.MidiEventScheduler; import com.android.internal.midi.MidiEventScheduler.MidiEvent; import libcore.io.IoUtils; import java.io.Closeable; Loading @@ -42,7 +45,7 @@ public final class UsbMidiDevice implements Closeable { private MidiDeviceServer mServer; private final MidiReceiver[] mInputPortReceivers; private final MidiEventScheduler mEventScheduler; private static final int BUFFER_SIZE = 512; Loading Loading @@ -99,19 +102,7 @@ public final class UsbMidiDevice implements Closeable { for (int i = 0; i < outputCount; i++) { mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]); } mInputPortReceivers = new MidiReceiver[inputCount]; for (int port = 0; port < inputCount; port++) { final int portF = port; mInputPortReceivers[port] = new MidiReceiver() { @Override public void onReceive(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); } }; } mEventScheduler = new MidiEventScheduler(inputCount); } private boolean register(Context context, Bundle properties) { Loading @@ -121,16 +112,22 @@ public final class UsbMidiDevice implements Closeable { return false; } int inputCount = mInputStreams.length; int outputCount = mOutputStreams.length; mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount, MidiReceiver[] inputPortReceivers = new MidiReceiver[inputCount]; for (int port = 0; port < inputCount; port++) { inputPortReceivers[port] = mEventScheduler.getReceiver(port); } mServer = midiManager.createDeviceServer(inputPortReceivers, outputCount, null, null, properties, MidiDeviceInfo.TYPE_USB, null); if (mServer == null) { return false; } final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers(); // FIXME can we only run this when we have a dispatcher that has listeners? new Thread() { // Create input thread new Thread("UsbMidiDevice input thread") { @Override public void run() { byte[] buffer = new byte[BUFFER_SIZE]; Loading Loading @@ -160,6 +157,33 @@ public final class UsbMidiDevice implements Closeable { } catch (ErrnoException e) { Log.d(TAG, "reader thread exiting"); } Log.d(TAG, "input thread exit"); } }.start(); // Create output thread new Thread("UsbMidiDevice output thread") { @Override public void run() { while (true) { MidiEvent event; try { event = (MidiEvent)mEventScheduler.waitNextEvent(); } catch (InterruptedException e) { // try again continue; } if (event == null) { break; } try { mOutputStreams[event.portNumber].write(event.data, 0, event.count); } catch (IOException e) { Log.e(TAG, "write failed for port " + event.portNumber); } mEventScheduler.addEventToPool(event); } Log.d(TAG, "output thread exit"); } }.start(); Loading @@ -168,6 +192,8 @@ public final class UsbMidiDevice implements Closeable { @Override public void close() throws IOException { mEventScheduler.close(); if (mServer != null) { mServer.close(); } Loading