xref: /aosp_15_r20/cts/apps/CtsVerifier/jni/midi/MidiTestManager.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1*b7c941bbSAndroid Build Coastguard Worker /*
2*b7c941bbSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*b7c941bbSAndroid Build Coastguard Worker  *
4*b7c941bbSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b7c941bbSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b7c941bbSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b7c941bbSAndroid Build Coastguard Worker  *
8*b7c941bbSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b7c941bbSAndroid Build Coastguard Worker  *
10*b7c941bbSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b7c941bbSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b7c941bbSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b7c941bbSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b7c941bbSAndroid Build Coastguard Worker  * limitations under the License.
15*b7c941bbSAndroid Build Coastguard Worker  */
16*b7c941bbSAndroid Build Coastguard Worker #include <cstring>
17*b7c941bbSAndroid Build Coastguard Worker #include <pthread.h>
18*b7c941bbSAndroid Build Coastguard Worker #include <unistd.h>
19*b7c941bbSAndroid Build Coastguard Worker #include <stdio.h>
20*b7c941bbSAndroid Build Coastguard Worker #include <chrono>
21*b7c941bbSAndroid Build Coastguard Worker 
22*b7c941bbSAndroid Build Coastguard Worker #define TAG "MidiTestManager"
23*b7c941bbSAndroid Build Coastguard Worker #include <android/log.h>
24*b7c941bbSAndroid Build Coastguard Worker #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
25*b7c941bbSAndroid Build Coastguard Worker #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
26*b7c941bbSAndroid Build Coastguard Worker #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
27*b7c941bbSAndroid Build Coastguard Worker 
28*b7c941bbSAndroid Build Coastguard Worker #include "MidiTestManager.h"
29*b7c941bbSAndroid Build Coastguard Worker 
30*b7c941bbSAndroid Build Coastguard Worker static pthread_t readThread;
31*b7c941bbSAndroid Build Coastguard Worker 
32*b7c941bbSAndroid Build Coastguard Worker static const bool DEBUG = true;
33*b7c941bbSAndroid Build Coastguard Worker static const bool DEBUG_MIDIDATA = true;
34*b7c941bbSAndroid Build Coastguard Worker 
35*b7c941bbSAndroid Build Coastguard Worker static const int MAX_PACKET_SIZE = 1024;
36*b7c941bbSAndroid Build Coastguard Worker static const int TIMEOUT_SECONDS = 5;
37*b7c941bbSAndroid Build Coastguard Worker 
38*b7c941bbSAndroid Build Coastguard Worker //
39*b7c941bbSAndroid Build Coastguard Worker // MIDI Messages
40*b7c941bbSAndroid Build Coastguard Worker //
41*b7c941bbSAndroid Build Coastguard Worker // Channel Commands
42*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_KeyDown = 9;
43*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_KeyUp = 8;
44*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_PolyPress = 10;
45*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_Control = 11;
46*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_ProgramChange = 12;
47*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_ChannelPress = 13;
48*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDIChanCmd_PitchWheel = 14;
49*b7c941bbSAndroid Build Coastguard Worker // System Commands
50*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDISysCmd_SysEx = 0xF0;
51*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDISysCmd_EndOfSysEx =  0xF7;
52*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDISysCmd_ActiveSensing = 0xFE;
53*b7c941bbSAndroid Build Coastguard Worker static const uint8_t kMIDISysCmd_Reset = 0xFF;
54*b7c941bbSAndroid Build Coastguard Worker 
readThreadRoutine(void * context)55*b7c941bbSAndroid Build Coastguard Worker static void* readThreadRoutine(void * context) {
56*b7c941bbSAndroid Build Coastguard Worker     MidiTestManager* testManager = (MidiTestManager*)context;
57*b7c941bbSAndroid Build Coastguard Worker     return reinterpret_cast<void*>(static_cast<intptr_t>(testManager->ProcessInput()));
58*b7c941bbSAndroid Build Coastguard Worker }
59*b7c941bbSAndroid Build Coastguard Worker 
60*b7c941bbSAndroid Build Coastguard Worker /*
61*b7c941bbSAndroid Build Coastguard Worker  * TestMessage
62*b7c941bbSAndroid Build Coastguard Worker  */
63*b7c941bbSAndroid Build Coastguard Worker #define makeMIDICmd(cmd, channel)  (uint8_t)((cmd << 4) | (channel & 0x0F))
64*b7c941bbSAndroid Build Coastguard Worker 
65*b7c941bbSAndroid Build Coastguard Worker uint8_t warmupMsg[] = {makeMIDICmd(kMIDIChanCmd_Control, 0), 0, 0};
66*b7c941bbSAndroid Build Coastguard Worker uint8_t msg0[] = {makeMIDICmd(kMIDIChanCmd_KeyDown, 0), 64, 120};
67*b7c941bbSAndroid Build Coastguard Worker uint8_t msg1[] = {makeMIDICmd(kMIDIChanCmd_KeyUp, 0), 64, 35};
68*b7c941bbSAndroid Build Coastguard Worker 
69*b7c941bbSAndroid Build Coastguard Worker class TestMessage {
70*b7c941bbSAndroid Build Coastguard Worker public:
71*b7c941bbSAndroid Build Coastguard Worker     uint8_t*   mMsgBytes;
72*b7c941bbSAndroid Build Coastguard Worker     int     mNumMsgBytes;
73*b7c941bbSAndroid Build Coastguard Worker 
TestMessage()74*b7c941bbSAndroid Build Coastguard Worker     TestMessage()
75*b7c941bbSAndroid Build Coastguard Worker         : mMsgBytes(NULL), mNumMsgBytes(0)
76*b7c941bbSAndroid Build Coastguard Worker     {}
77*b7c941bbSAndroid Build Coastguard Worker 
~TestMessage()78*b7c941bbSAndroid Build Coastguard Worker     ~TestMessage() {
79*b7c941bbSAndroid Build Coastguard Worker         delete[] mMsgBytes;
80*b7c941bbSAndroid Build Coastguard Worker     }
81*b7c941bbSAndroid Build Coastguard Worker 
set(uint8_t * msgBytes,int numMsgBytes)82*b7c941bbSAndroid Build Coastguard Worker     bool set(uint8_t* msgBytes, int numMsgBytes) {
83*b7c941bbSAndroid Build Coastguard Worker         if (msgBytes == NULL || numMsgBytes <= 0) {
84*b7c941bbSAndroid Build Coastguard Worker             return false;
85*b7c941bbSAndroid Build Coastguard Worker         }
86*b7c941bbSAndroid Build Coastguard Worker         mNumMsgBytes = numMsgBytes;
87*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes = new uint8_t[numMsgBytes];
88*b7c941bbSAndroid Build Coastguard Worker         memcpy(mMsgBytes, msgBytes, mNumMsgBytes * sizeof(uint8_t));
89*b7c941bbSAndroid Build Coastguard Worker         return true;
90*b7c941bbSAndroid Build Coastguard Worker     }
91*b7c941bbSAndroid Build Coastguard Worker 
setSysExMessage(int numMsgBytes)92*b7c941bbSAndroid Build Coastguard Worker     bool setSysExMessage(int numMsgBytes) {
93*b7c941bbSAndroid Build Coastguard Worker         if (numMsgBytes <= 0) {
94*b7c941bbSAndroid Build Coastguard Worker             return false;
95*b7c941bbSAndroid Build Coastguard Worker         }
96*b7c941bbSAndroid Build Coastguard Worker         mNumMsgBytes = numMsgBytes;
97*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes = new uint8_t[mNumMsgBytes];
98*b7c941bbSAndroid Build Coastguard Worker         memset(mMsgBytes, 0, mNumMsgBytes * sizeof(uint8_t));
99*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes[0] = kMIDISysCmd_SysEx;
100*b7c941bbSAndroid Build Coastguard Worker         for(int index = 1; index < numMsgBytes - 1; index++) {
101*b7c941bbSAndroid Build Coastguard Worker             mMsgBytes[index] = (uint8_t) (index % 100);
102*b7c941bbSAndroid Build Coastguard Worker         }
103*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes[numMsgBytes - 1] = kMIDISysCmd_EndOfSysEx;
104*b7c941bbSAndroid Build Coastguard Worker         return true;
105*b7c941bbSAndroid Build Coastguard Worker     }
106*b7c941bbSAndroid Build Coastguard Worker 
setTwoSysExMessage(int firstMsgBytes,int secondMsgBytes)107*b7c941bbSAndroid Build Coastguard Worker     bool setTwoSysExMessage(int firstMsgBytes, int secondMsgBytes) {
108*b7c941bbSAndroid Build Coastguard Worker         if (firstMsgBytes <= 0 || secondMsgBytes <= 0) {
109*b7c941bbSAndroid Build Coastguard Worker             return false;
110*b7c941bbSAndroid Build Coastguard Worker         }
111*b7c941bbSAndroid Build Coastguard Worker         mNumMsgBytes = firstMsgBytes + secondMsgBytes;
112*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes = new uint8_t[mNumMsgBytes];
113*b7c941bbSAndroid Build Coastguard Worker         memset(mMsgBytes, 0, mNumMsgBytes * sizeof(uint8_t));
114*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes[0] = kMIDISysCmd_SysEx;
115*b7c941bbSAndroid Build Coastguard Worker         for(int index = 1; index < firstMsgBytes - 1; index++) {
116*b7c941bbSAndroid Build Coastguard Worker             mMsgBytes[index] = (uint8_t) (index % 100);
117*b7c941bbSAndroid Build Coastguard Worker         }
118*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes[firstMsgBytes - 1] = kMIDISysCmd_EndOfSysEx;
119*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes[firstMsgBytes] = kMIDISysCmd_SysEx;
120*b7c941bbSAndroid Build Coastguard Worker         for(int index = firstMsgBytes + 1; index < firstMsgBytes + secondMsgBytes - 1; index++) {
121*b7c941bbSAndroid Build Coastguard Worker             mMsgBytes[index] = (uint8_t) (index % 100);
122*b7c941bbSAndroid Build Coastguard Worker         }
123*b7c941bbSAndroid Build Coastguard Worker         mMsgBytes[firstMsgBytes + secondMsgBytes - 1] = kMIDISysCmd_EndOfSysEx;
124*b7c941bbSAndroid Build Coastguard Worker         return true;
125*b7c941bbSAndroid Build Coastguard Worker     }
126*b7c941bbSAndroid Build Coastguard Worker }; /* class TestMessage */
127*b7c941bbSAndroid Build Coastguard Worker 
128*b7c941bbSAndroid Build Coastguard Worker /*
129*b7c941bbSAndroid Build Coastguard Worker  * MidiTestManager
130*b7c941bbSAndroid Build Coastguard Worker  */
MidiTestManager()131*b7c941bbSAndroid Build Coastguard Worker MidiTestManager::MidiTestManager()
132*b7c941bbSAndroid Build Coastguard Worker     : mTestModuleObj(NULL),
133*b7c941bbSAndroid Build Coastguard Worker       mReceiveStreamPos(0),
134*b7c941bbSAndroid Build Coastguard Worker       mMidiSendPort(NULL), mMidiReceivePort(NULL),
135*b7c941bbSAndroid Build Coastguard Worker       mTestMsgs(0), mNumTestMsgs(0),
136*b7c941bbSAndroid Build Coastguard Worker       mThrottleData(false)
137*b7c941bbSAndroid Build Coastguard Worker {}
138*b7c941bbSAndroid Build Coastguard Worker 
~MidiTestManager()139*b7c941bbSAndroid Build Coastguard Worker MidiTestManager::~MidiTestManager() {
140*b7c941bbSAndroid Build Coastguard Worker     mMatchStream.clear();
141*b7c941bbSAndroid Build Coastguard Worker }
142*b7c941bbSAndroid Build Coastguard Worker 
jniSetup(JNIEnv * env)143*b7c941bbSAndroid Build Coastguard Worker void MidiTestManager::jniSetup(JNIEnv* env) {
144*b7c941bbSAndroid Build Coastguard Worker     env->GetJavaVM(&mJvm);
145*b7c941bbSAndroid Build Coastguard Worker 
146*b7c941bbSAndroid Build Coastguard Worker     jclass clsMidiTestModule =
147*b7c941bbSAndroid Build Coastguard Worker         env->FindClass("com/android/cts/verifier/audio/MidiNativeTestActivity$NativeMidiTestModule");
148*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
149*b7c941bbSAndroid Build Coastguard Worker         ALOGI("gClsMidiTestModule:%p", clsMidiTestModule);
150*b7c941bbSAndroid Build Coastguard Worker     }
151*b7c941bbSAndroid Build Coastguard Worker 
152*b7c941bbSAndroid Build Coastguard Worker     // public void endTest(int endCode)
153*b7c941bbSAndroid Build Coastguard Worker     mMidEndTest = env->GetMethodID(clsMidiTestModule, "endTest", "(I)V");
154*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
155*b7c941bbSAndroid Build Coastguard Worker         ALOGI("mMidEndTestgMidEndTest:%p", mMidEndTest);
156*b7c941bbSAndroid Build Coastguard Worker     }
157*b7c941bbSAndroid Build Coastguard Worker }
158*b7c941bbSAndroid Build Coastguard Worker 
setupMessages()159*b7c941bbSAndroid Build Coastguard Worker bool MidiTestManager::setupMessages() {
160*b7c941bbSAndroid Build Coastguard Worker     mNumTestMsgs = 7;
161*b7c941bbSAndroid Build Coastguard Worker     mTestMsgs.resize(mNumTestMsgs);
162*b7c941bbSAndroid Build Coastguard Worker 
163*b7c941bbSAndroid Build Coastguard Worker     if (!mTestMsgs[0].set(msg0, sizeof(msg0)) ||
164*b7c941bbSAndroid Build Coastguard Worker         !mTestMsgs[1].set(msg1, sizeof(msg1)) ||
165*b7c941bbSAndroid Build Coastguard Worker         !mTestMsgs[2].setSysExMessage(30) ||
166*b7c941bbSAndroid Build Coastguard Worker         !mTestMsgs[3].setSysExMessage(6) ||
167*b7c941bbSAndroid Build Coastguard Worker         !mTestMsgs[4].setSysExMessage(120) ||
168*b7c941bbSAndroid Build Coastguard Worker         !mTestMsgs[5].setTwoSysExMessage(5, 13) ||
169*b7c941bbSAndroid Build Coastguard Worker         !mTestMsgs[6].setSysExMessage(340)) {
170*b7c941bbSAndroid Build Coastguard Worker         return false;
171*b7c941bbSAndroid Build Coastguard Worker     }
172*b7c941bbSAndroid Build Coastguard Worker     return true;
173*b7c941bbSAndroid Build Coastguard Worker }
174*b7c941bbSAndroid Build Coastguard Worker 
buildMatchStream()175*b7c941bbSAndroid Build Coastguard Worker void MidiTestManager::buildMatchStream() {
176*b7c941bbSAndroid Build Coastguard Worker     mMatchStream.clear();
177*b7c941bbSAndroid Build Coastguard Worker     for(int byteIndex = 0; byteIndex < sizeof(warmupMsg); byteIndex++) {
178*b7c941bbSAndroid Build Coastguard Worker         mMatchStream.push_back(warmupMsg[byteIndex]);
179*b7c941bbSAndroid Build Coastguard Worker     }
180*b7c941bbSAndroid Build Coastguard Worker     for(int msgIndex = 0; msgIndex < mNumTestMsgs; msgIndex++) {
181*b7c941bbSAndroid Build Coastguard Worker         for(int byteIndex = 0; byteIndex < mTestMsgs[msgIndex].mNumMsgBytes; byteIndex++) {
182*b7c941bbSAndroid Build Coastguard Worker             mMatchStream.push_back(mTestMsgs[msgIndex].mMsgBytes[byteIndex]);
183*b7c941bbSAndroid Build Coastguard Worker         }
184*b7c941bbSAndroid Build Coastguard Worker     }
185*b7c941bbSAndroid Build Coastguard Worker 
186*b7c941bbSAndroid Build Coastguard Worker     // Reset stream position
187*b7c941bbSAndroid Build Coastguard Worker     mReceiveStreamPos = 0;
188*b7c941bbSAndroid Build Coastguard Worker }
189*b7c941bbSAndroid Build Coastguard Worker 
logBytes(uint8_t * bytes,int count)190*b7c941bbSAndroid Build Coastguard Worker static void logBytes(uint8_t* bytes, int count) {
191*b7c941bbSAndroid Build Coastguard Worker     int buffSize = (count * 6) + 1; // count of "0x??, " + '\0';
192*b7c941bbSAndroid Build Coastguard Worker 
193*b7c941bbSAndroid Build Coastguard Worker     char* logBuff = new char[buffSize];
194*b7c941bbSAndroid Build Coastguard Worker     for (int dataIndex = 0; dataIndex < count; dataIndex++) {
195*b7c941bbSAndroid Build Coastguard Worker         sprintf(logBuff + (dataIndex * 6), "0x%.2X", bytes[dataIndex]);
196*b7c941bbSAndroid Build Coastguard Worker         if (dataIndex < count - 1) {
197*b7c941bbSAndroid Build Coastguard Worker             sprintf(logBuff + (dataIndex * 6) + 4, ", ");
198*b7c941bbSAndroid Build Coastguard Worker         }
199*b7c941bbSAndroid Build Coastguard Worker     }
200*b7c941bbSAndroid Build Coastguard Worker     ALOGD("logbytes(%d): %s", count, logBuff);
201*b7c941bbSAndroid Build Coastguard Worker     delete[] logBuff;
202*b7c941bbSAndroid Build Coastguard Worker }
203*b7c941bbSAndroid Build Coastguard Worker 
204*b7c941bbSAndroid Build Coastguard Worker /**
205*b7c941bbSAndroid Build Coastguard Worker  * Compares the supplied bytes against the sent message stream at the current position
206*b7c941bbSAndroid Build Coastguard Worker  * and advances the stream position.
207*b7c941bbSAndroid Build Coastguard Worker  *
208*b7c941bbSAndroid Build Coastguard Worker  * Returns the number of matched bytes on success and -1 on failure.
209*b7c941bbSAndroid Build Coastguard Worker  *
210*b7c941bbSAndroid Build Coastguard Worker  */
matchStream(uint8_t * bytes,int count)211*b7c941bbSAndroid Build Coastguard Worker int MidiTestManager::matchStream(uint8_t* bytes, int count) {
212*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
213*b7c941bbSAndroid Build Coastguard Worker         ALOGI("---- matchStream() count:%d", count);
214*b7c941bbSAndroid Build Coastguard Worker     }
215*b7c941bbSAndroid Build Coastguard Worker 
216*b7c941bbSAndroid Build Coastguard Worker     int matchedByteCount = 0;
217*b7c941bbSAndroid Build Coastguard Worker 
218*b7c941bbSAndroid Build Coastguard Worker     // a little bit of checking here...
219*b7c941bbSAndroid Build Coastguard Worker     if (count < 0) {
220*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Negative Byte Count in MidiTestManager::matchStream()");
221*b7c941bbSAndroid Build Coastguard Worker         return -1;
222*b7c941bbSAndroid Build Coastguard Worker     }
223*b7c941bbSAndroid Build Coastguard Worker 
224*b7c941bbSAndroid Build Coastguard Worker     if (count > MESSAGE_MAX_BYTES) {
225*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Too Large Byte Count (%d) in MidiTestManager::matchStream()", count);
226*b7c941bbSAndroid Build Coastguard Worker         return -1;
227*b7c941bbSAndroid Build Coastguard Worker     }
228*b7c941bbSAndroid Build Coastguard Worker 
229*b7c941bbSAndroid Build Coastguard Worker     bool matches = true;
230*b7c941bbSAndroid Build Coastguard Worker     for (int index = 0; index < count; index++) {
231*b7c941bbSAndroid Build Coastguard Worker         // Check for buffer overflow
232*b7c941bbSAndroid Build Coastguard Worker         if (mReceiveStreamPos >= mMatchStream.size()) {
233*b7c941bbSAndroid Build Coastguard Worker             ALOGD("matchStream() out-of-bounds @%d", mReceiveStreamPos);
234*b7c941bbSAndroid Build Coastguard Worker             matches = false;
235*b7c941bbSAndroid Build Coastguard Worker             break;
236*b7c941bbSAndroid Build Coastguard Worker         }
237*b7c941bbSAndroid Build Coastguard Worker 
238*b7c941bbSAndroid Build Coastguard Worker         if (bytes[index] == kMIDISysCmd_ActiveSensing) {
239*b7c941bbSAndroid Build Coastguard Worker             if (bytes[index] == mMatchStream[mReceiveStreamPos]) {
240*b7c941bbSAndroid Build Coastguard Worker                 ALOGD("matched active sensing message");
241*b7c941bbSAndroid Build Coastguard Worker                 matchedByteCount++;
242*b7c941bbSAndroid Build Coastguard Worker                 mReceiveStreamPos++;
243*b7c941bbSAndroid Build Coastguard Worker             } else {
244*b7c941bbSAndroid Build Coastguard Worker                 ALOGD("skipping active sensing message");
245*b7c941bbSAndroid Build Coastguard Worker             }
246*b7c941bbSAndroid Build Coastguard Worker         } else {
247*b7c941bbSAndroid Build Coastguard Worker             // Check first byte for warm-up message
248*b7c941bbSAndroid Build Coastguard Worker             if ((mReceiveStreamPos == 0) && bytes[index] != makeMIDICmd(kMIDIChanCmd_Control, 0)) {
249*b7c941bbSAndroid Build Coastguard Worker                 ALOGD("skipping warm-up message");
250*b7c941bbSAndroid Build Coastguard Worker                 matchedByteCount += sizeof(warmupMsg);
251*b7c941bbSAndroid Build Coastguard Worker                 mReceiveStreamPos += sizeof(warmupMsg);
252*b7c941bbSAndroid Build Coastguard Worker             }
253*b7c941bbSAndroid Build Coastguard Worker 
254*b7c941bbSAndroid Build Coastguard Worker             if (bytes[index] != mMatchStream[mReceiveStreamPos]) {
255*b7c941bbSAndroid Build Coastguard Worker                 matches = false;
256*b7c941bbSAndroid Build Coastguard Worker                 ALOGD("---- mismatch @%d [rec:0x%X : exp:0x%X]",
257*b7c941bbSAndroid Build Coastguard Worker                         index, bytes[index], mMatchStream[mReceiveStreamPos]);
258*b7c941bbSAndroid Build Coastguard Worker             } else {
259*b7c941bbSAndroid Build Coastguard Worker                 matchedByteCount++;
260*b7c941bbSAndroid Build Coastguard Worker                 mReceiveStreamPos++;
261*b7c941bbSAndroid Build Coastguard Worker             }
262*b7c941bbSAndroid Build Coastguard Worker         }
263*b7c941bbSAndroid Build Coastguard Worker     }
264*b7c941bbSAndroid Build Coastguard Worker 
265*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
266*b7c941bbSAndroid Build Coastguard Worker         ALOGI("  success:%d", matches);
267*b7c941bbSAndroid Build Coastguard Worker     }
268*b7c941bbSAndroid Build Coastguard Worker 
269*b7c941bbSAndroid Build Coastguard Worker     if (!matches) {
270*b7c941bbSAndroid Build Coastguard Worker         ALOGD("Mismatched Received Data:");
271*b7c941bbSAndroid Build Coastguard Worker         logBytes(bytes, count);
272*b7c941bbSAndroid Build Coastguard Worker         return -1;
273*b7c941bbSAndroid Build Coastguard Worker     }
274*b7c941bbSAndroid Build Coastguard Worker 
275*b7c941bbSAndroid Build Coastguard Worker     return matchedByteCount;
276*b7c941bbSAndroid Build Coastguard Worker }
277*b7c941bbSAndroid Build Coastguard Worker 
278*b7c941bbSAndroid Build Coastguard Worker #define THROTTLE_PERIOD_MS 20
279*b7c941bbSAndroid Build Coastguard Worker #define THROTTLE_MAX_PACKET_SIZE 15
280*b7c941bbSAndroid Build Coastguard Worker 
281*b7c941bbSAndroid Build Coastguard Worker /**
282*b7c941bbSAndroid Build Coastguard Worker  * Send a number of bytes.
283*b7c941bbSAndroid Build Coastguard Worker  *
284*b7c941bbSAndroid Build Coastguard Worker  * Returns the number of sent bytes on success or negative error code on failure.
285*b7c941bbSAndroid Build Coastguard Worker  *
286*b7c941bbSAndroid Build Coastguard Worker  */
portSend(AMidiInputPort * sendPort,uint8_t * msg,int length,bool throttle)287*b7c941bbSAndroid Build Coastguard Worker int portSend(AMidiInputPort* sendPort, uint8_t* msg, int length, bool throttle) {
288*b7c941bbSAndroid Build Coastguard Worker 
289*b7c941bbSAndroid Build Coastguard Worker     int numSent = 0;
290*b7c941bbSAndroid Build Coastguard Worker     if (throttle) {
291*b7c941bbSAndroid Build Coastguard Worker         for(int index = 0; index < length; index += THROTTLE_MAX_PACKET_SIZE) {
292*b7c941bbSAndroid Build Coastguard Worker             int packetSize = std::min(length - index, THROTTLE_MAX_PACKET_SIZE);
293*b7c941bbSAndroid Build Coastguard Worker             int curSent = AMidiInputPort_send(sendPort, msg + index, packetSize);
294*b7c941bbSAndroid Build Coastguard Worker             if (curSent < 0) {
295*b7c941bbSAndroid Build Coastguard Worker                 return curSent;
296*b7c941bbSAndroid Build Coastguard Worker             }
297*b7c941bbSAndroid Build Coastguard Worker             numSent += curSent;
298*b7c941bbSAndroid Build Coastguard Worker             usleep(THROTTLE_PERIOD_MS * 1000);
299*b7c941bbSAndroid Build Coastguard Worker         }
300*b7c941bbSAndroid Build Coastguard Worker     } else {
301*b7c941bbSAndroid Build Coastguard Worker         numSent = AMidiInputPort_send(sendPort, msg, length);
302*b7c941bbSAndroid Build Coastguard Worker     }
303*b7c941bbSAndroid Build Coastguard Worker     return numSent;
304*b7c941bbSAndroid Build Coastguard Worker }
305*b7c941bbSAndroid Build Coastguard Worker 
306*b7c941bbSAndroid Build Coastguard Worker /**
307*b7c941bbSAndroid Build Coastguard Worker  * Writes out the list of MIDI messages to the output port.
308*b7c941bbSAndroid Build Coastguard Worker  * Returns total number of bytes sent or negative error code.
309*b7c941bbSAndroid Build Coastguard Worker  */
sendMessages()310*b7c941bbSAndroid Build Coastguard Worker int MidiTestManager::sendMessages() {
311*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
312*b7c941bbSAndroid Build Coastguard Worker         ALOGI("---- sendMessages()...");
313*b7c941bbSAndroid Build Coastguard Worker         for(int msgIndex = 0; msgIndex < mNumTestMsgs; msgIndex++) {
314*b7c941bbSAndroid Build Coastguard Worker             if (DEBUG_MIDIDATA) {
315*b7c941bbSAndroid Build Coastguard Worker                 ALOGI("--------");
316*b7c941bbSAndroid Build Coastguard Worker                 for(int byteIndex = 0; byteIndex < mTestMsgs[msgIndex].mNumMsgBytes; byteIndex++) {
317*b7c941bbSAndroid Build Coastguard Worker                     ALOGI("  0x%X", mTestMsgs[msgIndex].mMsgBytes[byteIndex]);
318*b7c941bbSAndroid Build Coastguard Worker                 }
319*b7c941bbSAndroid Build Coastguard Worker             }
320*b7c941bbSAndroid Build Coastguard Worker         }
321*b7c941bbSAndroid Build Coastguard Worker     }
322*b7c941bbSAndroid Build Coastguard Worker 
323*b7c941bbSAndroid Build Coastguard Worker     // Send "Warm-up" message
324*b7c941bbSAndroid Build Coastguard Worker     portSend(mMidiSendPort, warmupMsg, sizeof(warmupMsg), mThrottleData);
325*b7c941bbSAndroid Build Coastguard Worker 
326*b7c941bbSAndroid Build Coastguard Worker     int totalSent = 0;
327*b7c941bbSAndroid Build Coastguard Worker     for(int msgIndex = 0; msgIndex < mNumTestMsgs; msgIndex++) {
328*b7c941bbSAndroid Build Coastguard Worker         ssize_t numSent =
329*b7c941bbSAndroid Build Coastguard Worker             portSend(mMidiSendPort, mTestMsgs[msgIndex].mMsgBytes, mTestMsgs[msgIndex].mNumMsgBytes,
330*b7c941bbSAndroid Build Coastguard Worker                 mThrottleData);
331*b7c941bbSAndroid Build Coastguard Worker         if (numSent < 0) {
332*b7c941bbSAndroid Build Coastguard Worker             ALOGE("sendMessages(): Send failed. index: %d, error: %zd", msgIndex, numSent);
333*b7c941bbSAndroid Build Coastguard Worker             return numSent;
334*b7c941bbSAndroid Build Coastguard Worker         }
335*b7c941bbSAndroid Build Coastguard Worker         totalSent += numSent;
336*b7c941bbSAndroid Build Coastguard Worker     }
337*b7c941bbSAndroid Build Coastguard Worker 
338*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
339*b7c941bbSAndroid Build Coastguard Worker         ALOGI("---- totalSent:%d", totalSent);
340*b7c941bbSAndroid Build Coastguard Worker     }
341*b7c941bbSAndroid Build Coastguard Worker 
342*b7c941bbSAndroid Build Coastguard Worker     return totalSent;
343*b7c941bbSAndroid Build Coastguard Worker }
344*b7c941bbSAndroid Build Coastguard Worker 
ProcessInput()345*b7c941bbSAndroid Build Coastguard Worker int MidiTestManager::ProcessInput() {
346*b7c941bbSAndroid Build Coastguard Worker     uint8_t readBuffer[MAX_PACKET_SIZE];
347*b7c941bbSAndroid Build Coastguard Worker     size_t totalNumReceived = 0;
348*b7c941bbSAndroid Build Coastguard Worker 
349*b7c941bbSAndroid Build Coastguard Worker     int testResult = TESTSTATUS_NOTRUN;
350*b7c941bbSAndroid Build Coastguard Worker 
351*b7c941bbSAndroid Build Coastguard Worker     int32_t opCode;
352*b7c941bbSAndroid Build Coastguard Worker     size_t numBytesReceived;
353*b7c941bbSAndroid Build Coastguard Worker     int64_t timeStamp;
354*b7c941bbSAndroid Build Coastguard Worker 
355*b7c941bbSAndroid Build Coastguard Worker     auto startTime = std::chrono::system_clock::now();
356*b7c941bbSAndroid Build Coastguard Worker 
357*b7c941bbSAndroid Build Coastguard Worker     while (true) {
358*b7c941bbSAndroid Build Coastguard Worker         // AMidiOutputPort_receive is non-blocking, so let's not burn up the CPU unnecessarily
359*b7c941bbSAndroid Build Coastguard Worker         usleep(2000);
360*b7c941bbSAndroid Build Coastguard Worker 
361*b7c941bbSAndroid Build Coastguard Worker         numBytesReceived = 0;
362*b7c941bbSAndroid Build Coastguard Worker         ssize_t numMessagesReceived =
363*b7c941bbSAndroid Build Coastguard Worker             AMidiOutputPort_receive(mMidiReceivePort, &opCode, readBuffer, MAX_PACKET_SIZE,
364*b7c941bbSAndroid Build Coastguard Worker                         &numBytesReceived, &timeStamp);
365*b7c941bbSAndroid Build Coastguard Worker 
366*b7c941bbSAndroid Build Coastguard Worker         if (DEBUG && numBytesReceived > 0) {
367*b7c941bbSAndroid Build Coastguard Worker             logBytes(readBuffer, numBytesReceived);
368*b7c941bbSAndroid Build Coastguard Worker         }
369*b7c941bbSAndroid Build Coastguard Worker 
370*b7c941bbSAndroid Build Coastguard Worker         if (numBytesReceived > 0 &&
371*b7c941bbSAndroid Build Coastguard Worker             opCode == AMIDI_OPCODE_DATA &&
372*b7c941bbSAndroid Build Coastguard Worker             readBuffer[0] != kMIDISysCmd_Reset) {
373*b7c941bbSAndroid Build Coastguard Worker             if (DEBUG) {
374*b7c941bbSAndroid Build Coastguard Worker                 ALOGI("---- msgs:%zd, bytes:%zu", numMessagesReceived, numBytesReceived);
375*b7c941bbSAndroid Build Coastguard Worker             }
376*b7c941bbSAndroid Build Coastguard Worker 
377*b7c941bbSAndroid Build Coastguard Worker             int matchResult = matchStream(readBuffer, numBytesReceived);
378*b7c941bbSAndroid Build Coastguard Worker             if (matchResult < 0) {
379*b7c941bbSAndroid Build Coastguard Worker                 testResult = TESTSTATUS_FAILED_MISMATCH;
380*b7c941bbSAndroid Build Coastguard Worker                 if (DEBUG) {
381*b7c941bbSAndroid Build Coastguard Worker                     ALOGE("---- TESTSTATUS_FAILED_MISMATCH");
382*b7c941bbSAndroid Build Coastguard Worker                 }
383*b7c941bbSAndroid Build Coastguard Worker                 return testResult;
384*b7c941bbSAndroid Build Coastguard Worker             }
385*b7c941bbSAndroid Build Coastguard Worker             totalNumReceived += matchResult;
386*b7c941bbSAndroid Build Coastguard Worker 
387*b7c941bbSAndroid Build Coastguard Worker             if (totalNumReceived > mMatchStream.size()) {
388*b7c941bbSAndroid Build Coastguard Worker                 testResult = TESTSTATUS_FAILED_OVERRUN;
389*b7c941bbSAndroid Build Coastguard Worker                 if (DEBUG) {
390*b7c941bbSAndroid Build Coastguard Worker                     ALOGE("---- TESTSTATUS_FAILED_OVERRUN");
391*b7c941bbSAndroid Build Coastguard Worker                 }
392*b7c941bbSAndroid Build Coastguard Worker                 return testResult;
393*b7c941bbSAndroid Build Coastguard Worker             }
394*b7c941bbSAndroid Build Coastguard Worker             if (totalNumReceived == mMatchStream.size()) {
395*b7c941bbSAndroid Build Coastguard Worker                 testResult = TESTSTATUS_PASSED;
396*b7c941bbSAndroid Build Coastguard Worker                 if (DEBUG) {
397*b7c941bbSAndroid Build Coastguard Worker                     ALOGE("---- TESTSTATUS_PASSED");
398*b7c941bbSAndroid Build Coastguard Worker                 }
399*b7c941bbSAndroid Build Coastguard Worker                 return testResult;
400*b7c941bbSAndroid Build Coastguard Worker             }
401*b7c941bbSAndroid Build Coastguard Worker         }
402*b7c941bbSAndroid Build Coastguard Worker 
403*b7c941bbSAndroid Build Coastguard Worker         auto currentTime = std::chrono::system_clock::now();
404*b7c941bbSAndroid Build Coastguard Worker         std::chrono::duration<double> elapsedSeconds = currentTime - startTime;
405*b7c941bbSAndroid Build Coastguard Worker         if (elapsedSeconds.count() > TIMEOUT_SECONDS) {
406*b7c941bbSAndroid Build Coastguard Worker             testResult = TESTSTATUS_FAILED_TIMEOUT;
407*b7c941bbSAndroid Build Coastguard Worker             if (DEBUG) {
408*b7c941bbSAndroid Build Coastguard Worker                 ALOGE("---- TESTSTATUS_FAILED_TIMEOUT");
409*b7c941bbSAndroid Build Coastguard Worker             }
410*b7c941bbSAndroid Build Coastguard Worker             return testResult;
411*b7c941bbSAndroid Build Coastguard Worker         }
412*b7c941bbSAndroid Build Coastguard Worker     }
413*b7c941bbSAndroid Build Coastguard Worker 
414*b7c941bbSAndroid Build Coastguard Worker     return testResult;
415*b7c941bbSAndroid Build Coastguard Worker }
416*b7c941bbSAndroid Build Coastguard Worker 
StartReading(AMidiDevice * nativeReadDevice)417*b7c941bbSAndroid Build Coastguard Worker bool MidiTestManager::StartReading(AMidiDevice* nativeReadDevice) {
418*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
419*b7c941bbSAndroid Build Coastguard Worker         ALOGI("StartReading()...");
420*b7c941bbSAndroid Build Coastguard Worker     }
421*b7c941bbSAndroid Build Coastguard Worker 
422*b7c941bbSAndroid Build Coastguard Worker     media_status_t m_status =
423*b7c941bbSAndroid Build Coastguard Worker         AMidiOutputPort_open(nativeReadDevice, 0, &mMidiReceivePort);
424*b7c941bbSAndroid Build Coastguard Worker     if (m_status != 0) {
425*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Can't open MIDI device for reading err:%d", m_status);
426*b7c941bbSAndroid Build Coastguard Worker         return false;
427*b7c941bbSAndroid Build Coastguard Worker     }
428*b7c941bbSAndroid Build Coastguard Worker 
429*b7c941bbSAndroid Build Coastguard Worker     // Start read thread
430*b7c941bbSAndroid Build Coastguard Worker     int status = pthread_create(&readThread, NULL, readThreadRoutine, this);
431*b7c941bbSAndroid Build Coastguard Worker     if (status != 0) {
432*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Can't start readThread: %s (%d)", strerror(status), status);
433*b7c941bbSAndroid Build Coastguard Worker     }
434*b7c941bbSAndroid Build Coastguard Worker     return status == 0;
435*b7c941bbSAndroid Build Coastguard Worker }
436*b7c941bbSAndroid Build Coastguard Worker 
StartWriting(AMidiDevice * nativeWriteDevice)437*b7c941bbSAndroid Build Coastguard Worker bool MidiTestManager::StartWriting(AMidiDevice* nativeWriteDevice) {
438*b7c941bbSAndroid Build Coastguard Worker     ALOGI("StartWriting()...");
439*b7c941bbSAndroid Build Coastguard Worker 
440*b7c941bbSAndroid Build Coastguard Worker     media_status_t status =
441*b7c941bbSAndroid Build Coastguard Worker         AMidiInputPort_open(nativeWriteDevice, 0, &mMidiSendPort);
442*b7c941bbSAndroid Build Coastguard Worker     if (status != 0) {
443*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Can't open MIDI device for writing err:%d", status);
444*b7c941bbSAndroid Build Coastguard Worker         return false;
445*b7c941bbSAndroid Build Coastguard Worker     }
446*b7c941bbSAndroid Build Coastguard Worker     return true;
447*b7c941bbSAndroid Build Coastguard Worker }
448*b7c941bbSAndroid Build Coastguard Worker 
RunTest(jobject testModuleObj,AMidiDevice * sendDevice,AMidiDevice * receiveDevice,bool throttleData)449*b7c941bbSAndroid Build Coastguard Worker bool MidiTestManager::RunTest(jobject testModuleObj, AMidiDevice* sendDevice,
450*b7c941bbSAndroid Build Coastguard Worker         AMidiDevice* receiveDevice, bool throttleData) {
451*b7c941bbSAndroid Build Coastguard Worker     if (DEBUG) {
452*b7c941bbSAndroid Build Coastguard Worker         ALOGI("RunTest(%p, %p, %p)", testModuleObj, sendDevice, receiveDevice);
453*b7c941bbSAndroid Build Coastguard Worker     }
454*b7c941bbSAndroid Build Coastguard Worker 
455*b7c941bbSAndroid Build Coastguard Worker     mThrottleData = throttleData;
456*b7c941bbSAndroid Build Coastguard Worker 
457*b7c941bbSAndroid Build Coastguard Worker     JNIEnv* env;
458*b7c941bbSAndroid Build Coastguard Worker     mJvm->AttachCurrentThread(&env, NULL);
459*b7c941bbSAndroid Build Coastguard Worker     if (env == NULL) {
460*b7c941bbSAndroid Build Coastguard Worker         EndTest(TESTSTATUS_FAILED_JNI);
461*b7c941bbSAndroid Build Coastguard Worker         return false; // bail
462*b7c941bbSAndroid Build Coastguard Worker     }
463*b7c941bbSAndroid Build Coastguard Worker 
464*b7c941bbSAndroid Build Coastguard Worker     if (!setupMessages()) {
465*b7c941bbSAndroid Build Coastguard Worker         EndTest(TESTSTATUS_FAILED_SETUP);
466*b7c941bbSAndroid Build Coastguard Worker         return false; // bail
467*b7c941bbSAndroid Build Coastguard Worker     }
468*b7c941bbSAndroid Build Coastguard Worker     buildMatchStream();
469*b7c941bbSAndroid Build Coastguard Worker 
470*b7c941bbSAndroid Build Coastguard Worker     mTestModuleObj = env->NewGlobalRef(testModuleObj);
471*b7c941bbSAndroid Build Coastguard Worker 
472*b7c941bbSAndroid Build Coastguard Worker     // Call StartWriting first because StartReading starts a thread.
473*b7c941bbSAndroid Build Coastguard Worker     if (!StartWriting(sendDevice) || !StartReading(receiveDevice)) {
474*b7c941bbSAndroid Build Coastguard Worker         // Test call to EndTest will close any open devices.
475*b7c941bbSAndroid Build Coastguard Worker         EndTest(TESTSTATUS_FAILED_DEVICE);
476*b7c941bbSAndroid Build Coastguard Worker         return false; // bail
477*b7c941bbSAndroid Build Coastguard Worker     }
478*b7c941bbSAndroid Build Coastguard Worker 
479*b7c941bbSAndroid Build Coastguard Worker     int bytesSent = sendMessages();
480*b7c941bbSAndroid Build Coastguard Worker     void* threadRetval = (void*)TESTSTATUS_NOTRUN;
481*b7c941bbSAndroid Build Coastguard Worker     int status = pthread_join(readThread, &threadRetval);
482*b7c941bbSAndroid Build Coastguard Worker 
483*b7c941bbSAndroid Build Coastguard Worker     // If send fails, the test should still wait for the receiver port to timeout to flush buffers.
484*b7c941bbSAndroid Build Coastguard Worker     if (bytesSent < 0) {
485*b7c941bbSAndroid Build Coastguard Worker         EndTest(TESTSTATUS_FAILED_SEND);
486*b7c941bbSAndroid Build Coastguard Worker         return false;
487*b7c941bbSAndroid Build Coastguard Worker     }
488*b7c941bbSAndroid Build Coastguard Worker 
489*b7c941bbSAndroid Build Coastguard Worker     if (status != 0) {
490*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Failed to join readThread: %s (%d)", strerror(status), status);
491*b7c941bbSAndroid Build Coastguard Worker     }
492*b7c941bbSAndroid Build Coastguard Worker     EndTest(static_cast<int>(reinterpret_cast<intptr_t>(threadRetval)));
493*b7c941bbSAndroid Build Coastguard Worker     return true;
494*b7c941bbSAndroid Build Coastguard Worker }
495*b7c941bbSAndroid Build Coastguard Worker 
EndTest(int endCode)496*b7c941bbSAndroid Build Coastguard Worker void MidiTestManager::EndTest(int endCode) {
497*b7c941bbSAndroid Build Coastguard Worker 
498*b7c941bbSAndroid Build Coastguard Worker     JNIEnv* env;
499*b7c941bbSAndroid Build Coastguard Worker     mJvm->AttachCurrentThread(&env, NULL);
500*b7c941bbSAndroid Build Coastguard Worker     if (env == NULL) {
501*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Error retrieving JNI Env");
502*b7c941bbSAndroid Build Coastguard Worker     }
503*b7c941bbSAndroid Build Coastguard Worker 
504*b7c941bbSAndroid Build Coastguard Worker     env->CallVoidMethod(mTestModuleObj, mMidEndTest, endCode);
505*b7c941bbSAndroid Build Coastguard Worker     env->DeleteGlobalRef(mTestModuleObj);
506*b7c941bbSAndroid Build Coastguard Worker 
507*b7c941bbSAndroid Build Coastguard Worker     // EndTest() will ALWAYS be called, so we can close the ports here.
508*b7c941bbSAndroid Build Coastguard Worker     if (mMidiSendPort != NULL) {
509*b7c941bbSAndroid Build Coastguard Worker         AMidiInputPort_close(mMidiSendPort);
510*b7c941bbSAndroid Build Coastguard Worker         mMidiSendPort = NULL;
511*b7c941bbSAndroid Build Coastguard Worker     }
512*b7c941bbSAndroid Build Coastguard Worker     if (mMidiReceivePort != NULL) {
513*b7c941bbSAndroid Build Coastguard Worker         AMidiOutputPort_close(mMidiReceivePort);
514*b7c941bbSAndroid Build Coastguard Worker         mMidiReceivePort = NULL;
515*b7c941bbSAndroid Build Coastguard Worker     }
516*b7c941bbSAndroid Build Coastguard Worker }
517