/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ // Wrapper to the native phone test signal processing library, which // exposes an interface suitable for calling via JNI. #include <stdlib.h> #include <jni.h> #include "GenerateSinusoid.h" #include "MeasureRms.h" #include "GlitchTest.h" #include "OverflowCheck.h" #include "CompareSpectra.h" #include "LinearityTest.h" typedef short *shortPtr; extern "C" { JNIEXPORT jshortArray JNICALL Java_com_android_cts_verifier_audioquality_Native_generateSinusoid( JNIEnv *env, jobject obj, jfloat freq, jfloat duration, jfloat sampleRate, jfloat amplitude, jfloat ramp); JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_measureRms( JNIEnv *env, jobject obj, jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh); JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_glitchTest( JNIEnv *env, jobject obj, jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh, jfloat dbSnrThresh, jshortArray jpcm); JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_overflowCheck( JNIEnv *env, jobject obj, jshortArray jpcm, jfloat sampleRate); JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_compareSpectra( JNIEnv *env, jobject obj, jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate); JNIEXPORT jfloat JNICALL Java_com_android_cts_verifier_audioquality_Native_linearityTest( JNIEnv *env, jobject obj, jobjectArray jpcms, jfloat sampleRate, jfloat dbStepSize, jint referenceStim); }; /* Returns an array of sinusoidal samples. If the arguments are invalid, returns an empty array. */ JNIEXPORT jshortArray JNICALL Java_com_android_cts_verifier_audioquality_Native_generateSinusoid( JNIEnv *env, jobject obj, jfloat freq, jfloat duration, jfloat sampleRate, jfloat amplitude, jfloat ramp) { short *wave = NULL; int numSamples = 0; generateSinusoid(freq, duration, sampleRate, amplitude, ramp, &numSamples, &wave); jshortArray ja; if (!numSamples) { ja = env->NewShortArray(0); } else { ja = env->NewShortArray(numSamples); env->SetShortArrayRegion(ja, 0, numSamples, wave); delete[] wave; } return ja; } /* Returns an array of four floats. ret[0] = RMS ret[1] = standard deviation of the RMS ret[2] = non-silent region duration ret[3] = mean value */ JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_measureRms( JNIEnv *env, jobject obj, jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh) { float ret[4]; ret[0] = ret[1] = ret[2] = ret[3] = -1.0; int numSamples = env->GetArrayLength(jpcm); short *pcm = new short[numSamples]; env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); measureRms(pcm, numSamples, sampleRate, onsetThresh, ret, ret + 1, ret + 3, ret + 2); jfloatArray ja = env->NewFloatArray(4); env->SetFloatArrayRegion(ja, 0, 4, ret); return ja; } /* Returns an array of three floats. ret[0] = #bad frames ret[1] = error code ret[2] = duration Error code = 1 for success, -1 if initialization failed, -2 if insufficient samples -3 if tone signal onset not found -4 if tone signal end not found */ JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_glitchTest( JNIEnv *env, jobject obj, jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh, jfloat dbSnrThresh, jshortArray jpcm) { float ret[3]; int numSamples = env->GetArrayLength(jpcm); short *pcm = new short[numSamples]; env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); GlitchTest gt; gt.init(sampleRate, stimFreq, onsetThresh, dbSnrThresh); float duration = -1.0; int badFrames = -1; int success = gt.checkToneSnr(pcm, numSamples, &duration, &badFrames); ret[0] = badFrames; ret[1] = success; ret[2] = duration; jfloatArray ja = env->NewFloatArray(3); env->SetFloatArrayRegion(ja, 0, 3, ret); return ja; } /* Returns an array of seven floats. ret[0] = num deltas ret[1] = error code ret[2] = duration ret[3] = onset ret[4] = offset ret[5] = max peak ret[6] = min peak Error code = 1 for success, -1 for failure. */ JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_overflowCheck( JNIEnv *env, jobject obj, jshortArray jpcm, jfloat sampleRate) { float ret[7]; int numSamples = env->GetArrayLength(jpcm); short *pcm = new short[numSamples]; env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); float duration = -1.0; int numDeltas = -1, onset = -1, offset = -1; int maxPeak = 0, minPeak = 0; int success = overflowCheck(pcm, numSamples, sampleRate, &duration, &numDeltas, &onset, &offset, &maxPeak, &minPeak); ret[0] = numDeltas; ret[1] = success ? 1 : -1; ret[2] = duration; ret[3] = onset; ret[4] = offset; ret[5] = maxPeak; ret[6] = minPeak; jfloatArray ja = env->NewFloatArray(7); env->SetFloatArrayRegion(ja, 0, 7, ret); return ja; } /* Returns an array of three floats. ret[0] = max deviation, ret[1] = error code, ret[2] = rms deviation. Error code = 1 for success, -1 for failure. */ JNIEXPORT jfloatArray JNICALL Java_com_android_cts_verifier_audioquality_Native_compareSpectra( JNIEnv *env, jobject obj, jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate) { float ret[3]; int numSamples = env->GetArrayLength(jpcm); short *pcm = new short[numSamples]; env->GetShortArrayRegion(jpcm, 0, numSamples, pcm); int nRefSamples = env->GetArrayLength(jrefPcm); short *refPcm = new short[nRefSamples]; env->GetShortArrayRegion(jrefPcm, 0, nRefSamples, refPcm); float maxDeviation = -1.0, rmsDeviation = -1.0; int success = compareSpectra(pcm, numSamples, refPcm, nRefSamples, sampleRate, &maxDeviation, &rmsDeviation); ret[1] = success ? 1 : -1; ret[0] = maxDeviation; ret[2] = rmsDeviation; jfloatArray ja = env->NewFloatArray(3); env->SetFloatArrayRegion(ja, 0, 3, ret); return ja; } /* Return maximum deviation from linearity in dB. On failure returns: -1.0 The input signals or sample counts are missing. -2.0 The number of input signals is < 2. -3.0 The specified sample rate is <= 4000.0 -4.0 The dB step size for the increase in stimulus level is <= 0.0 -5.0 The specified reverence stimulus number is out of range. -6.0 One or more of the stimuli is too short in duration. */ JNIEXPORT jfloat JNICALL Java_com_android_cts_verifier_audioquality_Native_linearityTest( JNIEnv *env, jobject obj, jobjectArray jpcms, jfloat sampleRate, jfloat dbStepSize, jint referenceStim) { int numSignals = env->GetArrayLength(jpcms); int *sampleCounts = new int[numSignals]; short **pcms = new shortPtr[numSignals]; jshortArray ja; for (int i = 0; i < numSignals; i++) { ja = (jshortArray) env->GetObjectArrayElement(jpcms, i); sampleCounts[i] = env->GetArrayLength(ja); pcms[i] = new short[sampleCounts[i]]; env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]); } float maxDeviation = -1.0; int ret = linearityTest(pcms, sampleCounts, numSignals, sampleRate, dbStepSize, referenceStim, &maxDeviation); delete[] sampleCounts; for (int i = 0; i < numSignals; i++) { delete[] pcms[i]; } delete[] pcms; if (ret < 1) return ret; return maxDeviation; }