1f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood/* 2f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * Copyright (C) 2015 The Android Open Source Project 3f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * 4f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 5f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * you may not use this file except in compliance with the License. 6f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * You may obtain a copy of the License at 7f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * 8f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 9f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * 10f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * Unless required by applicable law or agreed to in writing, software 11f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 12f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * See the License for the specific language governing permissions and 14f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * limitations under the License. 15f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood */ 16f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 17f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwoodpackage com.android.bluetoothmidiservice; 18f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 19f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwoodimport android.media.midi.MidiReceiver; 20f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwoodimport android.util.Log; 21f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 22f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwoodimport java.io.IOException; 23f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 24f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood/** 25f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * This is an abstract base class that decodes a packet buffer and passes it to a 26f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood * {@link android.media.midi.MidiReceiver} 27f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood */ 28f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwoodpublic class BluetoothPacketDecoder extends PacketDecoder { 29f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 30f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood private static final String TAG = "BluetoothPacketDecoder"; 31f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 32f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood private final byte[] mBuffer; 33ff001809f60b937c63d2db39e99a567af54414acMike Lockwood private MidiBtleTimeTracker mTimeTracker; 34f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 35f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood private final int TIMESTAMP_MASK_HIGH = 0x1F80; 36f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood private final int TIMESTAMP_MASK_LOW = 0x7F; 37f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood private final int HEADER_TIMESTAMP_MASK = 0x3F; 38f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 39f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood public BluetoothPacketDecoder(int maxPacketSize) { 40f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood mBuffer = new byte[maxPacketSize]; 41f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 42f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 43f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood @Override 44f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood public void decodePacket(byte[] buffer, MidiReceiver receiver) { 45ff001809f60b937c63d2db39e99a567af54414acMike Lockwood if (mTimeTracker == null) { 46ff001809f60b937c63d2db39e99a567af54414acMike Lockwood mTimeTracker = new MidiBtleTimeTracker(System.nanoTime()); 47ff001809f60b937c63d2db39e99a567af54414acMike Lockwood } 48ff001809f60b937c63d2db39e99a567af54414acMike Lockwood 49f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood int length = buffer.length; 50f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 51f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // NOTE his code allows running status across packets, 52f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // although the specification does not allow that. 53f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 54f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood if (length < 1) { 55f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood Log.e(TAG, "empty packet"); 56f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood return; 57f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 58f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood byte header = buffer[0]; 59f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood if ((header & 0xC0) != 0x80) { 60f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood Log.e(TAG, "packet does not start with header"); 61f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood return; 62f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 63f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 64f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // shift bits 0 - 5 to bits 7 - 12 65ff001809f60b937c63d2db39e99a567af54414acMike Lockwood int highTimestamp = (header & HEADER_TIMESTAMP_MASK) << 7; 66f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood boolean lastWasTimestamp = false; 67f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood int dataCount = 0; 68f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood int previousLowTimestamp = 0; 69ff001809f60b937c63d2db39e99a567af54414acMike Lockwood long nanoTimestamp = 0; 70ff001809f60b937c63d2db39e99a567af54414acMike Lockwood int currentTimestamp = 0; 71f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 72f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // iterate through the rest of the packet, separating MIDI data from timestamps 73f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood for (int i = 1; i < buffer.length; i++) { 74f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood byte b = buffer[i]; 75f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 76f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood if ((b & 0x80) != 0 && !lastWasTimestamp) { 77f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood lastWasTimestamp = true; 78f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood int lowTimestamp = b & TIMESTAMP_MASK_LOW; 79f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood if (lowTimestamp < previousLowTimestamp) { 80ff001809f60b937c63d2db39e99a567af54414acMike Lockwood highTimestamp = (highTimestamp + 0x0080) & TIMESTAMP_MASK_HIGH; 81f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 82f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood previousLowTimestamp = lowTimestamp; 83f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 84ff001809f60b937c63d2db39e99a567af54414acMike Lockwood int newTimestamp = highTimestamp | lowTimestamp; 85ff001809f60b937c63d2db39e99a567af54414acMike Lockwood if (newTimestamp != currentTimestamp) { 86f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood if (dataCount > 0) { 87f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // send previous message separately since it has a different timestamp 88f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood try { 897eb441cb4abcd3230a4d243469c5044f49e707c8Mike Lockwood receiver.send(mBuffer, 0, dataCount, nanoTimestamp); 90f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } catch (IOException e) { 91f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // ??? 92f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 93f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood dataCount = 0; 94f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 95ff001809f60b937c63d2db39e99a567af54414acMike Lockwood currentTimestamp = newTimestamp; 96f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 97ff001809f60b937c63d2db39e99a567af54414acMike Lockwood 98ff001809f60b937c63d2db39e99a567af54414acMike Lockwood // calculate nanoTimestamp 99ff001809f60b937c63d2db39e99a567af54414acMike Lockwood long now = System.nanoTime(); 100ff001809f60b937c63d2db39e99a567af54414acMike Lockwood nanoTimestamp = mTimeTracker.convertTimestampToNanotime(currentTimestamp, now); 101f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } else { 102f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood lastWasTimestamp = false; 103f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood mBuffer[dataCount++] = b; 104f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 105f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 106f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood 107f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood if (dataCount > 0) { 108f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood try { 1097eb441cb4abcd3230a4d243469c5044f49e707c8Mike Lockwood receiver.send(mBuffer, 0, dataCount, nanoTimestamp); 110f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } catch (IOException e) { 111f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood // ??? 112f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 113f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 114f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood } 115f0a41d1c591193fbe02c9ddbaf24c79af4da9972Mike Lockwood} 116