1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 // Wrapper to the native phone test signal processing library, which 18 // exposes an interface suitable for calling via JNI. 19 20 #include <stdlib.h> 21 #include <jni.h> 22 23 #include "GenerateSinusoid.h" 24 #include "MeasureRms.h" 25 #include "GlitchTest.h" 26 #include "OverflowCheck.h" 27 #include "CompareSpectra.h" 28 #include "LinearityTest.h" 29 30 typedef short *shortPtr; 31 32 extern "C" { 33 JNIEXPORT jshortArray JNICALL 34 Java_com_android_cts_verifier_audioquality_Native_generateSinusoid( 35 JNIEnv *env, jobject obj, 36 jfloat freq, jfloat duration, 37 jfloat sampleRate, jfloat amplitude, jfloat ramp); 38 JNIEXPORT jfloatArray JNICALL 39 Java_com_android_cts_verifier_audioquality_Native_measureRms( 40 JNIEnv *env, jobject obj, 41 jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh); 42 JNIEXPORT jfloatArray JNICALL 43 Java_com_android_cts_verifier_audioquality_Native_glitchTest( 44 JNIEnv *env, jobject obj, 45 jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh, 46 jfloat dbSnrThresh, jshortArray jpcm); 47 JNIEXPORT jfloatArray JNICALL 48 Java_com_android_cts_verifier_audioquality_Native_overflowCheck( 49 JNIEnv *env, jobject obj, 50 jshortArray jpcm, jfloat sampleRate); 51 JNIEXPORT jfloatArray JNICALL 52 Java_com_android_cts_verifier_audioquality_Native_compareSpectra( 53 JNIEnv *env, jobject obj, 54 jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate); 55 JNIEXPORT jfloat JNICALL 56 Java_com_android_cts_verifier_audioquality_Native_linearityTest( 57 JNIEnv *env, jobject obj, 58 jobjectArray jpcms, 59 jfloat sampleRate, jfloat dbStepSize, jint referenceStim); 60 61 JNIEXPORT jfloat JNICALL 62 Java_com_android_cts_verifier_audioquality_Native_linearityTestRms( 63 JNIEnv *env, jobject obj, 64 jobjectArray jpcms, 65 jfloat sampleRate, jfloat dbStepSize); 66 }; 67 68 /* Returns an array of sinusoidal samples. 69 If the arguments are invalid, returns an empty array. */ 70 JNIEXPORT jshortArray JNICALL 71 Java_com_android_cts_verifier_audioquality_Native_generateSinusoid( 72 JNIEnv *env, jobject obj, 73 jfloat freq, jfloat duration, 74 jfloat sampleRate, jfloat amplitude, jfloat ramp) { 75 short *wave = NULL; 76 int numSamples = 0; 77 78 generateSinusoid(freq, duration, sampleRate, amplitude, ramp, 79 &numSamples, &wave); 80 81 jshortArray ja; 82 if (!numSamples) { 83 ja = env->NewShortArray(0); 84 } else { 85 ja = env->NewShortArray(numSamples); 86 env->SetShortArrayRegion(ja, 0, numSamples, wave); 87 delete[] wave; 88 } 89 return ja; 90 } 91 92 /* Returns an array of four floats. 93 ret[0] = RMS 94 ret[1] = standard deviation of the RMS 95 ret[2] = non-silent region duration 96 ret[3] = mean value 97 */ 98 JNIEXPORT jfloatArray JNICALL 99 Java_com_android_cts_verifier_audioquality_Native_measureRms( 100 JNIEnv *env, jobject obj, 101 jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh) { 102 float ret[4]; 103 ret[0] = ret[1] = ret[2] = ret[3] = -1.0; 104 int numSamples = env->GetArrayLength(jpcm); 105 short *pcm = new short[numSamples]; 106 env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); 107 108 measureRms(pcm, numSamples, sampleRate, onsetThresh, ret, ret + 1, 109 ret + 3, ret + 2); 110 111 jfloatArray ja = env->NewFloatArray(4); 112 env->SetFloatArrayRegion(ja, 0, 4, ret); 113 return ja; 114 } 115 116 /* Returns an array of three floats. 117 ret[0] = #bad frames 118 ret[1] = error code 119 ret[2] = duration 120 Error code = 1 for success, 121 -1 if initialization failed, 122 -2 if insufficient samples 123 -3 if tone signal onset not found 124 -4 if tone signal end not found 125 */ 126 JNIEXPORT jfloatArray JNICALL 127 Java_com_android_cts_verifier_audioquality_Native_glitchTest( 128 JNIEnv *env, jobject obj, 129 jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh, 130 jfloat dbSnrThresh, jshortArray jpcm) { 131 float ret[3]; 132 int numSamples = env->GetArrayLength(jpcm); 133 short *pcm = new short[numSamples]; 134 env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); 135 136 GlitchTest gt; 137 gt.init(sampleRate, stimFreq, onsetThresh, dbSnrThresh); 138 float duration = -1.0; 139 int badFrames = -1; 140 int success = gt.checkToneSnr(pcm, numSamples, &duration, &badFrames); 141 ret[0] = badFrames; 142 ret[1] = success; 143 ret[2] = duration; 144 jfloatArray ja = env->NewFloatArray(3); 145 env->SetFloatArrayRegion(ja, 0, 3, ret); 146 return ja; 147 } 148 149 /* Returns an array of seven floats. 150 ret[0] = num deltas 151 ret[1] = error code 152 ret[2] = duration 153 ret[3] = onset 154 ret[4] = offset 155 ret[5] = max peak 156 ret[6] = min peak 157 Error code = 1 for success, -1 for failure. */ 158 JNIEXPORT jfloatArray JNICALL 159 Java_com_android_cts_verifier_audioquality_Native_overflowCheck( 160 JNIEnv *env, jobject obj, 161 jshortArray jpcm, jfloat sampleRate) { 162 float ret[7]; 163 int numSamples = env->GetArrayLength(jpcm); 164 short *pcm = new short[numSamples]; 165 env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); 166 167 float duration = -1.0; 168 int numDeltas = -1, onset = -1, offset = -1; 169 int maxPeak = 0, minPeak = 0; 170 int success = overflowCheck(pcm, numSamples, sampleRate, 171 &duration, &numDeltas, &onset, &offset, &maxPeak, &minPeak); 172 ret[0] = numDeltas; 173 ret[1] = success ? 1 : -1; 174 ret[2] = duration; 175 ret[3] = onset; 176 ret[4] = offset; 177 ret[5] = maxPeak; 178 ret[6] = minPeak; 179 jfloatArray ja = env->NewFloatArray(7); 180 env->SetFloatArrayRegion(ja, 0, 7, ret); 181 return ja; 182 } 183 184 /* Returns an array of three floats. 185 ret[0] = max deviation, 186 ret[1] = error code, 187 ret[2] = rms deviation. 188 Error code = 1 for success, -1 for failure. */ 189 JNIEXPORT jfloatArray JNICALL 190 Java_com_android_cts_verifier_audioquality_Native_compareSpectra( 191 JNIEnv *env, jobject obj, 192 jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate) { 193 float ret[3]; 194 int numSamples = env->GetArrayLength(jpcm); 195 short *pcm = new short[numSamples]; 196 env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); 197 int nRefSamples = env->GetArrayLength(jrefPcm); 198 short *refPcm = new short[nRefSamples]; 199 env->GetShortArrayRegion(jrefPcm, 0, nRefSamples, refPcm); 200 201 float maxDeviation = -1.0, rmsDeviation = -1.0; 202 int success = compareSpectra(pcm, numSamples, refPcm, nRefSamples, 203 sampleRate, &maxDeviation, &rmsDeviation); 204 ret[1] = success ? 1 : -1; 205 206 ret[0] = maxDeviation; 207 ret[2] = rmsDeviation; 208 jfloatArray ja = env->NewFloatArray(3); 209 env->SetFloatArrayRegion(ja, 0, 3, ret); 210 return ja; 211 } 212 213 /* Return maximum deviation from linearity in dB. 214 On failure returns: 215 -1.0 The input signals or sample counts are missing. 216 -2.0 The number of input signals is < 2. 217 -3.0 The specified sample rate is <= 4000.0 218 -4.0 The dB step size for the increase in stimulus level is <= 0.0 219 -5.0 The specified reverence stimulus number is out of range. 220 -6.0 One or more of the stimuli is too short in duration. 221 */ 222 JNIEXPORT jfloat JNICALL 223 Java_com_android_cts_verifier_audioquality_Native_linearityTest( 224 JNIEnv *env, jobject obj, 225 jobjectArray jpcms, 226 jfloat sampleRate, jfloat dbStepSize, jint referenceStim) { 227 int numSignals = env->GetArrayLength(jpcms); 228 int *sampleCounts = new int[numSignals]; 229 short **pcms = new shortPtr[numSignals]; 230 jshortArray ja; 231 for (int i = 0; i < numSignals; i++) { 232 ja = (jshortArray) env->GetObjectArrayElement(jpcms, i); 233 sampleCounts[i] = env->GetArrayLength(ja); 234 pcms[i] = new short[sampleCounts[i]]; 235 env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]); 236 } 237 238 float maxDeviation = -1.0; 239 int ret = linearityTest(pcms, sampleCounts, numSignals, 240 sampleRate, dbStepSize, referenceStim, &maxDeviation); 241 delete[] sampleCounts; 242 for (int i = 0; i < numSignals; i++) { 243 delete[] pcms[i]; 244 } 245 delete[] pcms; 246 if (ret < 1) return ret; 247 248 return maxDeviation; 249 } 250 251 252 /* Return maximum deviation from linearity in dB. 253 On failure returns: 254 -1.0 The input signals or sample counts are missing. 255 -2.0 The number of input signals is < 2. 256 -3.0 The specified sample rate is <= 4000.0 257 -4.0 The dB step size for the increase in stimulus level is <= 0.0 258 -6.0 One or more of the stimuli is too short in duration. 259 */ 260 JNIEXPORT jfloat JNICALL 261 Java_com_android_cts_verifier_audioquality_Native_linearityTestRms( 262 JNIEnv *env, jobject obj, 263 jobjectArray jpcms, 264 jfloat sampleRate, jfloat dbStepSize) { 265 int numSignals = env->GetArrayLength(jpcms); 266 int *sampleCounts = new int[numSignals]; 267 short **pcms = new shortPtr[numSignals]; 268 jshortArray ja; 269 for (int i = 0; i < numSignals; i++) { 270 ja = (jshortArray) env->GetObjectArrayElement(jpcms, i); 271 sampleCounts[i] = env->GetArrayLength(ja); 272 pcms[i] = new short[sampleCounts[i]]; 273 env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]); 274 } 275 276 float maxDeviation = -1.0; 277 int ret = linearityTestRms(pcms, sampleCounts, numSignals, 278 sampleRate, dbStepSize, &maxDeviation); 279 delete[] sampleCounts; 280 for (int i = 0; i < numSignals; i++) { 281 delete[] pcms[i]; 282 } 283 delete[] pcms; 284 if (ret < 1) return ret; 285 286 return maxDeviation; 287 } 288