Home | History | Annotate | Download | only in cpp
      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 #include "jni_native.h"
     18 
     19 #include <stdlib.h>
     20 
     21 #include <android/log.h>
     22 
     23 #include "loopback.h"
     24 
     25 #define LOG_TAG "jni_native"
     26 
     27 static int nativeEngineFromThreadType(int threadType) {
     28     switch (threadType) {
     29         case AUDIO_THREAD_TYPE_NATIVE_SLES: return NATIVE_ENGINE_SLES;
     30         case AUDIO_THREAD_TYPE_NATIVE_AAUDIO: return NATIVE_ENGINE_AAUDIO;
     31     }
     32     __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     33             "unsupported thread type %d", threadType);
     34     return -1;
     35 }
     36 
     37 JNIEXPORT jobject JNICALL
     38 Java_org_drrickorang_loopback_NativeAudioThread_nativeComputeDefaultSettings
     39 (JNIEnv *env, jobject obj __unused, jint bytesPerFrame, jint threadType, jint performanceMode) {
     40     int engine = nativeEngineFromThreadType(threadType);
     41     if (engine == -1) return NULL;
     42     int samplingRate, playerBufferFrameCount, recorderBufferFrameCount;
     43     if (sEngines[engine].computeDefaultSettings(performanceMode, &samplingRate,
     44                     &playerBufferFrameCount, &recorderBufferFrameCount) == STATUS_SUCCESS) {
     45         jclass cls = (*env)->FindClass(env, "org/drrickorang/loopback/TestSettings");
     46         jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "(III)V");
     47         jobject testSettings = (*env)->NewObject(env, cls, methodID,
     48                 samplingRate,
     49                 playerBufferFrameCount * bytesPerFrame,
     50                 recorderBufferFrameCount * bytesPerFrame);
     51         return testSettings;
     52     } else {
     53         return NULL;
     54     }
     55 }
     56 
     57 JNIEXPORT jlong JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeInit
     58   (JNIEnv *env, jobject obj __unused, jint threadType, jint samplingRate, jint frameCount,
     59    jint micSource, jint performanceMode,
     60    jint testType, jdouble frequency1, jobject byteBuffer, jshortArray loopbackTone,
     61    jint maxRecordedLateCallbacks, jint ignoreFirstFrames) {
     62 
     63     int engine = nativeEngineFromThreadType(threadType);
     64     if (engine == -1) return 0;
     65 
     66     native_engine_instance_t *pInstance =
     67             (native_engine_instance_t*) malloc(sizeof(native_engine_instance_t));
     68     if (pInstance == NULL) {
     69         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     70                 "failed to allocate a native engine instance");
     71         return 0;
     72     }
     73     void *pContext = NULL;
     74 
     75     char *byteBufferPtr = (*env)->GetDirectBufferAddress(env, byteBuffer);
     76     int byteBufferLength = (*env)->GetDirectBufferCapacity(env, byteBuffer);
     77 
     78     short *loopbackToneArray = (*env)->GetShortArrayElements(env, loopbackTone, 0);
     79 
     80     if (sEngines[engine].init(&pContext, samplingRate, frameCount, micSource,
     81                  performanceMode,
     82                  testType, frequency1, byteBufferPtr, byteBufferLength,
     83                  loopbackToneArray, maxRecordedLateCallbacks, ignoreFirstFrames) != STATUS_FAIL) {
     84         pInstance->context = pContext;
     85         pInstance->methods = &sEngines[engine];
     86         return (long) pInstance;
     87     }
     88 
     89     free(pInstance);
     90     return 0;
     91 }
     92 
     93 
     94 JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeProcessNext
     95 (JNIEnv *env __unused, jobject obj __unused, jlong handle, jdoubleArray samplesArray,
     96 jlong offset) {
     97     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
     98 
     99     long maxSamples = (*env)->GetArrayLength(env, samplesArray);
    100     double *pSamples = (*env)->GetDoubleArrayElements(env, samplesArray, 0);
    101 
    102     long availableSamples = maxSamples-offset;
    103     double *pCurrentSample = pSamples+offset;
    104 
    105     __android_log_print(ANDROID_LOG_INFO, LOG_TAG,
    106             "jni nativeProcessNext currentSample %p, availableSamples %ld ",
    107             pCurrentSample, availableSamples);
    108 
    109     int samplesRead = pInstance->methods->processNext(
    110             pInstance->context, pCurrentSample, availableSamples);
    111     return samplesRead;
    112 }
    113 
    114 
    115 JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeDestroy
    116   (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    117     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    118     int status = pInstance->methods->destroy(&pInstance->context);
    119     free(pInstance);
    120     return status;
    121 }
    122 
    123 
    124 JNIEXPORT jintArray JNICALL
    125         Java_org_drrickorang_loopback_NativeAudioThread_nativeGetRecorderBufferPeriod
    126   (JNIEnv *env, jobject obj __unused, jlong handle) {
    127     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    128     int* recorderBufferPeriod = pInstance->methods->getRecorderBufferPeriod(
    129             pInstance->context);
    130 
    131     // get the length = RANGE
    132     jintArray result = (*env)->NewIntArray(env, RANGE);
    133     (*env)->SetIntArrayRegion(env, result, 0, RANGE, recorderBufferPeriod);
    134 
    135     return result;
    136 }
    137 
    138 
    139 JNIEXPORT jint JNICALL
    140         Java_org_drrickorang_loopback_NativeAudioThread_nativeGetRecorderMaxBufferPeriod
    141   (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    142     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    143     int recorderMaxBufferPeriod = pInstance->methods->getRecorderMaxBufferPeriod(
    144             pInstance->context);
    145 
    146     return recorderMaxBufferPeriod;
    147 }
    148 
    149 
    150 JNIEXPORT jdouble JNICALL
    151         Java_org_drrickorang_loopback_NativeAudioThread_nativeGetRecorderVarianceBufferPeriod
    152         (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    153     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    154     int64_t result = pInstance->methods->getRecorderVarianceBufferPeriod(pInstance->context);
    155     // variance has units ns^2 so we have to square the conversion factor
    156     double scaled = (double) result / ((double) NANOS_PER_MILLI * (double) NANOS_PER_MILLI);
    157     return scaled;
    158 }
    159 
    160 
    161 JNIEXPORT jintArray
    162 JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeGetPlayerBufferPeriod
    163   (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    164     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    165     int* playerBufferPeriod = pInstance->methods->getPlayerBufferPeriod(pInstance->context);
    166 
    167     jintArray result = (*env)->NewIntArray(env, RANGE);
    168     (*env)->SetIntArrayRegion(env, result, 0, RANGE, playerBufferPeriod);
    169 
    170     return result;
    171 }
    172 
    173 
    174 JNIEXPORT jint JNICALL
    175         Java_org_drrickorang_loopback_NativeAudioThread_nativeGetPlayerMaxBufferPeriod
    176   (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    177     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    178     int playerMaxBufferPeriod = pInstance->methods->getPlayerMaxBufferPeriod(pInstance->context);
    179 
    180     return playerMaxBufferPeriod;
    181 }
    182 
    183 
    184 JNIEXPORT jdouble JNICALL
    185 Java_org_drrickorang_loopback_NativeAudioThread_nativeGetPlayerVarianceBufferPeriod
    186         (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    187     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    188     int64_t result = pInstance->methods->getPlayerVarianceBufferPeriod(pInstance->context);
    189     // variance has units ns^2 so we have to square the conversion factor
    190     double scaled = (double) result / ((double) NANOS_PER_MILLI * (double) NANOS_PER_MILLI);
    191     return scaled;
    192 }
    193 
    194 
    195 jobject getCallbackTimes(JNIEnv *env, callbackTimeStamps *callbacks, short expectedBufferPeriod){
    196     jintArray timeStamps = (*env)->NewIntArray(env, callbacks->index);
    197     (*env)->SetIntArrayRegion(env, timeStamps, 0, callbacks->index, callbacks->timeStampsMs);
    198 
    199     jshortArray callbackLengths = (*env)->NewShortArray(env, callbacks->index);
    200     (*env)->SetShortArrayRegion(env, callbackLengths, 0, callbacks->index,
    201                                 callbacks->callbackDurations);
    202 
    203     jclass cls = (*env)->FindClass(env, "org/drrickorang/loopback/BufferCallbackTimes");
    204     jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "([I[SZS)V");
    205     jobject callbackTimes=(*env)->NewObject(env,cls, methodID, timeStamps, callbackLengths,
    206                                             callbacks->exceededCapacity, expectedBufferPeriod);
    207     return callbackTimes;
    208 }
    209 
    210 JNIEXPORT jobject
    211 JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeGetPlayerCallbackTimeStamps
    212         (JNIEnv *env, jobject obj __unused, jlong handle) {
    213     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    214     callbackTimeStamps *pTSs;
    215     int expectedBufferPeriod = pInstance->methods->getPlayerTimeStampsAndExpectedBufferPeriod(
    216             pInstance->context, &pTSs);
    217     return getCallbackTimes(env, pTSs, expectedBufferPeriod);
    218 }
    219 
    220 JNIEXPORT jobject
    221 JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeGetRecorderCallbackTimeStamps
    222         (JNIEnv *env, jobject obj __unused, jlong handle) {
    223     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    224     callbackTimeStamps *pTSs;
    225     int expectedBufferPeriod = pInstance->methods->getRecorderTimeStampsAndExpectedBufferPeriod(
    226             pInstance->context, &pTSs);
    227     return getCallbackTimes(env, pTSs, expectedBufferPeriod);
    228 }
    229 
    230 JNIEXPORT jint
    231 JNICALL Java_org_drrickorang_loopback_NativeAudioThread_nativeGetCaptureRank
    232         (JNIEnv *env __unused, jobject obj __unused, jlong handle) {
    233     native_engine_instance_t *pInstance = (native_engine_instance_t*) handle;
    234     return pInstance->methods->getCaptureRank(pInstance->context);
    235 }
    236