1/*
2 * Copyright (C) 2014 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
17package android.media.midi;
18
19/**
20 * This class contains utilities for socket communication between a
21 * MidiInputPort and MidiOutputPort
22 */
23/* package */ class MidiPortImpl {
24    private static final String TAG = "MidiPort";
25
26    /**
27     * Packet type for data packet
28     */
29    public static final int PACKET_TYPE_DATA = 1;
30
31    /**
32     * Packet type for flush packet
33     */
34    public static final int PACKET_TYPE_FLUSH = 2;
35
36    /**
37     * Maximum size of a packet that can be passed between processes.
38     */
39    public static final int MAX_PACKET_SIZE = 1024;
40
41    /**
42     * size of message timestamp in bytes
43     */
44    private static final int TIMESTAMP_SIZE = 8;
45
46    /**
47     * Data packet overhead is timestamp size plus packet type byte
48     */
49    private static final int DATA_PACKET_OVERHEAD = TIMESTAMP_SIZE + 1;
50
51    /**
52     * Maximum amount of MIDI data that can be included in a packet
53     */
54    public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - DATA_PACKET_OVERHEAD;
55
56    /**
57     * Utility function for packing MIDI data to be passed between processes
58     *
59     * message byte array contains variable length MIDI message.
60     * messageSize is size of variable length MIDI message
61     * timestamp is message timestamp to pack
62     * dest is buffer to pack into
63     * returns size of packed message
64     */
65    public static int packData(byte[] message, int offset, int size, long timestamp,
66            byte[] dest) {
67        if (size  > MAX_PACKET_DATA_SIZE) {
68            size = MAX_PACKET_DATA_SIZE;
69        }
70        int length = 0;
71        // packet type goes first
72        dest[length++] = PACKET_TYPE_DATA;
73        // data goes next
74        System.arraycopy(message, offset, dest, length, size);
75        length += size;
76
77        // followed by timestamp
78        for (int i = 0; i < TIMESTAMP_SIZE; i++) {
79            dest[length++] = (byte)timestamp;
80            timestamp >>= 8;
81        }
82
83        return length;
84    }
85
86    /**
87     * Utility function for packing a flush command to be passed between processes
88     */
89    public static int packFlush(byte[] dest) {
90        dest[0] = PACKET_TYPE_FLUSH;
91        return 1;
92    }
93
94    /**
95     * Returns the packet type (PACKET_TYPE_DATA or PACKET_TYPE_FLUSH)
96     */
97    public static int getPacketType(byte[] buffer, int bufferLength) {
98        return buffer[0];
99    }
100
101    /**
102     * Utility function for unpacking MIDI data received from other process
103     * returns the offset of the MIDI message in packed buffer
104     */
105    public static int getDataOffset(byte[] buffer, int bufferLength) {
106        // data follows packet type byte
107        return 1;
108    }
109
110    /**
111     * Utility function for unpacking MIDI data received from other process
112     * returns size of MIDI data in packed buffer
113     */
114    public static int getDataSize(byte[] buffer, int bufferLength) {
115        // message length is total buffer length minus size of the timestamp
116        return bufferLength - DATA_PACKET_OVERHEAD;
117    }
118
119    /**
120     * Utility function for unpacking MIDI data received from other process
121     * unpacks timestamp from packed buffer
122     */
123    public static long getPacketTimestamp(byte[] buffer, int bufferLength) {
124        // timestamp is at end of the packet
125        int offset = bufferLength;
126        long timestamp = 0;
127
128        for (int i = 0; i < TIMESTAMP_SIZE; i++) {
129            int b = (int)buffer[--offset] & 0xFF;
130            timestamp = (timestamp << 8) | b;
131        }
132        return timestamp;
133    }
134}
135