diff options
author | Mike Lockwood <lockwood@google.com> | 2015-05-02 16:09:45 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-02 16:09:47 +0000 |
commit | 5ba44affe6747d2995030005bd99471d621d6e79 (patch) | |
tree | 26c2104290ae4900a5830a70d83f80a040ede82b /media | |
parent | 9eb25fad188e48fb3adafe1043f2014357cce898 (diff) | |
parent | 8c26d843a786e5ee56046245fbf72a81b533bcb9 (diff) | |
download | frameworks_base-5ba44affe6747d2995030005bd99471d621d6e79.zip frameworks_base-5ba44affe6747d2995030005bd99471d621d6e79.tar.gz frameworks_base-5ba44affe6747d2995030005bd99471d621d6e79.tar.bz2 |
Merge "BluetoothMidiService: Add support for sending SysEx messages that span multiple Bluetooth packets" into mnc-dev
Diffstat (limited to 'media')
2 files changed, 94 insertions, 36 deletions
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java index 8d194e5..63a8da7 100644 --- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java +++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java @@ -47,6 +47,7 @@ import java.util.UUID; public final class BluetoothMidiDevice { private static final String TAG = "BluetoothMidiDevice"; + private static final boolean DEBUG = false; private static final int MAX_PACKET_SIZE = 20; @@ -152,8 +153,10 @@ public final class BluetoothMidiDevice { @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { -// logByteArray("Received ", characteristic.getValue(), 0, -// characteristic.getValue().length); + if (DEBUG) { + logByteArray("Received ", characteristic.getValue(), 0, + characteristic.getValue().length); + } mPacketDecoder.decodePacket(characteristic.getValue(), mOutputReceiver); } }; @@ -182,8 +185,10 @@ public final class BluetoothMidiDevice { byte[] writeBuffer = mWriteBuffers[count]; System.arraycopy(buffer, 0, writeBuffer, 0, count); mCharacteristic.setValue(writeBuffer); -// logByteArray("Sent ", mCharacteristic.getValue(), 0, -// mCharacteristic.getValue().length); + if (DEBUG) { + logByteArray("Sent ", mCharacteristic.getValue(), 0, + mCharacteristic.getValue().length); + } mBluetoothGatt.writeCharacteristic(mCharacteristic); } } @@ -259,14 +264,7 @@ public final class BluetoothMidiDevice { private static void logByteArray(String prefix, byte[] value, int offset, int count) { StringBuilder builder = new StringBuilder(prefix); for (int i = offset; i < count; i++) { - String hex = Integer.toHexString(value[i]); - int length = hex.length(); - if (length == 1) { - hex = "0x" + hex; - } else { - hex = hex.substring(length - 2, length); - } - builder.append(hex); + builder.append(String.format("0x%02X", value[i])); if (i != value.length - 1) { builder.append(", "); } diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java index 463edcf..99ea353 100644 --- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java +++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java @@ -44,7 +44,7 @@ public class BluetoothPacketEncoder extends PacketEncoder { // timestamp for first message in current packet private int mPacketTimestamp; // current running status, or zero if none - private int mRunningStatus; + private byte mRunningStatus; private boolean mWritePending; @@ -56,12 +56,28 @@ public class BluetoothPacketEncoder extends PacketEncoder { public void onReceive(byte[] msg, int offset, int count, long timestamp) throws IOException { - int milliTimestamp = (int)(timestamp / MILLISECOND_NANOS) & MILLISECOND_MASK; - int status = msg[0] & 0xFF; - synchronized (mLock) { + int milliTimestamp = (int)(timestamp / MILLISECOND_NANOS) & MILLISECOND_MASK; + byte status = msg[offset]; + boolean isSysExStart = (status == MidiConstants.STATUS_SYSTEM_EXCLUSIVE); + boolean isSysExContinuation = ((status & 0x80) == 0); + + int bytesNeeded; + if (isSysExStart || isSysExContinuation) { + // SysEx messages can be split into multiple packets + bytesNeeded = 1; + } else { + bytesNeeded = count; + } + boolean needsTimestamp = (milliTimestamp != mPacketTimestamp); - int bytesNeeded = count; + if (isSysExStart) { + // SysEx start byte must be preceded by a timestamp + needsTimestamp = true; + } else if (isSysExContinuation) { + // SysEx continuation packets must not have timestamp byte + needsTimestamp = false; + } if (needsTimestamp) bytesNeeded++; // add one for timestamp byte if (status == mRunningStatus) bytesNeeded--; // subtract one for status byte @@ -71,15 +87,12 @@ public class BluetoothPacketEncoder extends PacketEncoder { flushLocked(true); } - // write header if we are starting a new packet - if (mAccumulatedBytes == 0) { - // header byte with timestamp bits 7 - 12 - mAccumulationBuffer[mAccumulatedBytes++] = (byte)(0x80 | (milliTimestamp >> 7)); - mPacketTimestamp = milliTimestamp; - needsTimestamp = true; + // write the header if necessary + if (appendHeader(milliTimestamp)) { + needsTimestamp = !isSysExContinuation; } - // write new timestamp byte and status byte if necessary + // write new timestamp byte if necessary if (needsTimestamp) { // timestamp byte with bits 0 - 6 of timestamp mAccumulationBuffer[mAccumulatedBytes++] = @@ -87,20 +100,55 @@ public class BluetoothPacketEncoder extends PacketEncoder { mPacketTimestamp = milliTimestamp; } - if (status != mRunningStatus) { - mAccumulationBuffer[mAccumulatedBytes++] = (byte)status; - if (MidiConstants.allowRunningStatus(status)) { - mRunningStatus = status; - } else if (MidiConstants.allowRunningStatus(status)) { - mRunningStatus = 0; + if (isSysExStart || isSysExContinuation) { + // MidiFramer will end the packet with SysEx End if there is one in the buffer + boolean hasSysExEnd = + (msg[offset + count - 1] == MidiConstants.STATUS_END_SYSEX); + int remaining = (hasSysExEnd ? count - 1 : count); + + while (remaining > 0) { + if (mAccumulatedBytes == mAccumulationBuffer.length) { + // write out our data if there is no more room + // if necessary, block until previous packet is sent + flushLocked(true); + appendHeader(milliTimestamp); + } + + int copy = mAccumulationBuffer.length - mAccumulatedBytes; + if (copy > remaining) copy = remaining; + System.arraycopy(msg, offset, mAccumulationBuffer, mAccumulatedBytes, copy); + mAccumulatedBytes += copy; + offset += copy; + remaining -= copy; } - } - // now copy data bytes - int dataLength = count - 1; - System.arraycopy(msg, 1, mAccumulationBuffer, mAccumulatedBytes, dataLength); - // FIXME - handle long SysEx properly - mAccumulatedBytes += dataLength; + if (hasSysExEnd) { + // SysEx End command must be preceeded by a timestamp byte + if (mAccumulatedBytes + 2 > mAccumulationBuffer.length) { + // write out our data if there is no more room + // if necessary, block until previous packet is sent + flushLocked(true); + appendHeader(milliTimestamp); + } + mAccumulationBuffer[mAccumulatedBytes++] = (byte)(0x80 | (milliTimestamp & 0x7F)); + mAccumulationBuffer[mAccumulatedBytes++] = MidiConstants.STATUS_END_SYSEX; + } + } else { + // Non-SysEx message + if (status != mRunningStatus) { + mAccumulationBuffer[mAccumulatedBytes++] = status; + if (MidiConstants.allowRunningStatus(status)) { + mRunningStatus = status; + } else if (MidiConstants.cancelsRunningStatus(status)) { + mRunningStatus = 0; + } + } + + // now copy data bytes + int dataLength = count - 1; + System.arraycopy(msg, offset + 1, mAccumulationBuffer, mAccumulatedBytes, dataLength); + mAccumulatedBytes += dataLength; + } // write the packet if possible, but do not block flushLocked(false); @@ -108,6 +156,18 @@ public class BluetoothPacketEncoder extends PacketEncoder { } }; + private boolean appendHeader(int milliTimestamp) { + // write header if we are starting a new packet + if (mAccumulatedBytes == 0) { + // header byte with timestamp bits 7 - 12 + mAccumulationBuffer[mAccumulatedBytes++] = (byte)(0x80 | ((milliTimestamp >> 7) & 0x3F)); + mPacketTimestamp = milliTimestamp; + return true; + } else { + return false; + } + } + // MidiFramer for normalizing incoming data private final MidiFramer mMidiFramer = new MidiFramer(mFramedDataReceiver); |