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