From d338c3c8f8063a85fb82042affd6d197f5793be3 Mon Sep 17 00:00:00 2001 From: Robert Wu Date: Mon, 21 Mar 2022 15:29:02 +0000 Subject: [PATCH] USB MIDI: Create encoder per output port UsbMidiEncoder is not thread-safe. Therefore, each output port should use its own encoder. Bug: 225884009 Test: MidiKeyboard/MidiScope on both MIDI 2.0 and MIDI 1.0 paths. Test: Verified M-Audio Keyboard with only input has the correct logs. Change-Id: I43bd7381982403766b7f37c22d55ef5d19013120 --- .../android/server/usb/UsbDirectMidiDevice.java | 11 +++++++++-- .../android/server/usb/UsbMidiPacketConverter.java | 14 +++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java index 0fa79df3e008d..04c52f7253e95 100644 --- a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java +++ b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java @@ -84,7 +84,7 @@ public final class UsbDirectMidiDevice implements Closeable { private final Object mLock = new Object(); private boolean mIsOpen; - private final UsbMidiPacketConverter mUsbMidiPacketConverter = new UsbMidiPacketConverter(); + private UsbMidiPacketConverter mUsbMidiPacketConverter; private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() { @@ -264,6 +264,11 @@ public final class UsbDirectMidiDevice implements Closeable { Log.d(TAG, "openLocked()"); UsbManager manager = mContext.getSystemService(UsbManager.class); + // Converting from raw MIDI to USB MIDI is not thread-safe. + // UsbMidiPacketConverter creates a converter from raw MIDI + // to USB MIDI for each USB output. + mUsbMidiPacketConverter = new UsbMidiPacketConverter(mNumOutputs); + mUsbDeviceConnections = new ArrayList(mUsbInterfaces.size()); mInputUsbEndpoints = new ArrayList>(mUsbInterfaces.size()); mOutputUsbEndpoints = new ArrayList>(mUsbInterfaces.size()); @@ -415,7 +420,7 @@ public final class UsbDirectMidiDevice implements Closeable { } else { convertedArray = mUsbMidiPacketConverter.rawMidiToUsbMidi( - event.data, event.count); + event.data, event.count, portFinal); } if (DEBUG) { @@ -518,6 +523,8 @@ public final class UsbDirectMidiDevice implements Closeable { mInputUsbEndpoints = null; mOutputUsbEndpoints = null; + mUsbMidiPacketConverter = null; + mIsOpen = false; } diff --git a/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java b/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java index 7c93c7668fa22..56bb23681741f 100644 --- a/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java +++ b/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java @@ -74,8 +74,15 @@ public class UsbMidiPacketConverter { private static final byte SYSEX_START_EXCLUSIVE = (byte) 0xF0; private static final byte SYSEX_END_EXCLUSIVE = (byte) 0xF7; - private UsbMidiEncoder mUsbMidiEncoder = new UsbMidiEncoder(); private UsbMidiDecoder mUsbMidiDecoder = new UsbMidiDecoder(); + private UsbMidiEncoder[] mUsbMidiEncoders; + + public UsbMidiPacketConverter(int numEncoders) { + mUsbMidiEncoders = new UsbMidiEncoder[numEncoders]; + for (int i = 0; i < numEncoders; i++) { + mUsbMidiEncoders[i] = new UsbMidiEncoder(); + } + } /** * Converts a USB MIDI array into a raw MIDI array. @@ -93,10 +100,11 @@ public class UsbMidiPacketConverter { * * @param midiBytes the raw MIDI bytes to convert * @param size the size of usbMidiBytes + * @param encoderId which encoder to use * @return byte array of USB MIDI packets */ - public byte[] rawMidiToUsbMidi(byte[] midiBytes, int size) { - return mUsbMidiEncoder.encode(midiBytes, size); + public byte[] rawMidiToUsbMidi(byte[] midiBytes, int size, int encoderId) { + return mUsbMidiEncoders[encoderId].encode(midiBytes, size); } private class UsbMidiDecoder {