Java Android NDK-渐变生成错误

Java Android NDK-渐变生成错误,java,android,c++,android-ndk,Java,Android,C++,Android Ndk,我已成功编译SoundTouch库,并将生成的文件复制到项目的libs文件夹中 在每个文件夹中都有一个libsoundtouch.so文件 在我的项目的jni文件夹中,我有以下文件: Android.mk Application.mk soundtouch-jni.cpp 我的Android.mk如下所示: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # *** Remember: Change -O0 into -O2 in

我已成功编译SoundTouch库,并将生成的文件复制到项目的
libs
文件夹中

在每个文件夹中都有一个
libsoundtouch.so
文件

在我的项目的
jni
文件夹中,我有以下文件:

  • Android.mk
  • Application.mk
  • soundtouch-jni.cpp
我的Android.mk如下所示:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# *** Remember: Change -O0 into -O2 in add-applications.mk ***

LOCAL_MODULE    := soundtouch
LOCAL_SRC_FILES := soundtouch-jni.cpp ../../SoundTouch/AAFilter.cpp  ../../SoundTouch/FIFOSampleBuffer.cpp \
                ../../SoundTouch/FIRFilter.cpp ../../SoundTouch/cpu_detect_x86.cpp \
                ../../SoundTouch/sse_optimized.cpp ../../SoundStretch/WavFile.cpp \
                ../../SoundTouch/RateTransposer.cpp ../../SoundTouch/SoundTouch.cpp \
                ../../SoundTouch/InterpolateCubic.cpp ../../SoundTouch/InterpolateLinear.cpp \
                ../../SoundTouch/InterpolateShannon.cpp ../../SoundTouch/TDStretch.cpp \
                ../../SoundTouch/BPMDetect.cpp ../../SoundTouch/PeakFinder.cpp 

# for native audio
LOCAL_SHARED_LIBRARIES += -lgcc 
# --whole-archive -lgcc 
# for logging
LOCAL_LDLIBS    += -llog
# for native asset manager
#LOCAL_LDLIBS    += -landroid

# Custom Flags: 
# -fvisibility=hidden : don't export all symbols
LOCAL_CFLAGS += -fvisibility=hidden -I ../../../include -fdata-sections -ffunction-sections

# OpenMP mode : enable these flags to enable using OpenMP for parallel computation 
#LOCAL_CFLAGS += -fopenmp
#LOCAL_LDFLAGS += -fopenmp


# Use ARM instruction set instead of Thumb for improved calculation performance in ARM CPUs 
LOCAL_ARM_MODE := arm

include $(BUILD_SHARED_LIBRARY)
这是我的
模块构建.gradle
文件:

apply plugin: 'com.android.application'

android {
    signingConfigs {
        dev_key {
            keyAlias '#########'
            keyPassword '########'
            storeFile file('/Users/daniele/Desktop/Chords/########')
            storePassword '#######'
        }
    }
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.dancam.chords"
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 16
        versionName "2.1"
        signingConfig ##########
        multiDexEnabled true
    }
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
#include <jni.h>
#include <android/log.h>
#include <stdexcept>
#include <string>

using namespace std;

#include "../../../include/SoundTouch.h"
#include "../source/SoundStretch/WavFile.h"

#define LOGV(...)   __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
//#define LOGV(...)


// String for keeping possible c++ exception error messages. Notice that this isn't
// thread-safe but it's expected that exceptions are special situations that won't
// occur in several threads in parallel.
static string _errMsg = "";


#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define BUFF_SIZE 4096


using namespace soundtouch;


// Set error message to return
static void _setErrmsg(const char *msg)
{
    _errMsg = msg;
}


#ifdef _OPENMP

#include <pthread.h>
extern pthread_key_t gomp_tls_key;
static void * _p_gomp_tls = NULL;

/// Function to initialize threading for OpenMP.
///
/// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if
/// called from the Android App main thread because in the main thread the gomp_tls storage is
/// properly set, however, Android does not properly initialize gomp_tls storage for other threads.
/// Thus if OpenMP routines are invoked from some other thread than the main thread,
/// the OpenMP routine will crash the application due to NULL pointer access on uninitialized storage.
///
/// This workaround stores the gomp_tls storage from main thread, and copies to other threads.
/// In order this to work, the Application main thread needws to call at least "getVersionString"
/// routine.
static int _init_threading(bool warn)
{
    void *ptr = pthread_getspecific(gomp_tls_key);
    LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
    if (ptr == NULL)
    {
        LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
        pthread_setspecific(gomp_tls_key, _p_gomp_tls);
    }
    else
    {
        LOGV("JNI store this TLS storage");
        _p_gomp_tls = ptr;
    }
    // Where critical, show warning if storage still not properly initialized
    if ((warn) && (_p_gomp_tls == NULL))
    {
        _setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
        return -1;
    }
    return 0;
}

#else
static int _init_threading(bool warn)
{
    // do nothing if not OpenMP build
    return 0;
}
#endif


// Processes the sound file
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
{
    int nSamples;
    int nChannels;
    int buffSizeSamples;
    SAMPLETYPE sampleBuffer[BUFF_SIZE];

    // open input file
    WavInFile inFile(inFileName);
    int sampleRate = inFile.getSampleRate();
    int bits = inFile.getNumBits();
    nChannels = inFile.getNumChannels();

    // create output file
    WavOutFile outFile(outFileName, sampleRate, bits, nChannels);

    pSoundTouch->setSampleRate(sampleRate);
    pSoundTouch->setChannels(nChannels);

    assert(nChannels > 0);
    buffSizeSamples = BUFF_SIZE / nChannels;

    // Process samples read from the input file
    while (inFile.eof() == 0)
    {
        int num;

        // Read a chunk of samples from the input file
        num = inFile.read(sampleBuffer, BUFF_SIZE);
        nSamples = num / nChannels;

        // Feed the samples into SoundTouch processor
        pSoundTouch->putSamples(sampleBuffer, nSamples);

        // Read ready samples from SoundTouch processor & write them output file.
        // NOTES:
        // - 'receiveSamples' doesn't necessarily return any samples at all
        //   during some rounds!
        // - On the other hand, during some round 'receiveSamples' may have more
        //   ready samples than would fit into 'sampleBuffer', and for this reason
        //   the 'receiveSamples' call is iterated for as many times as it
        //   outputs samples.
        do
        {
            nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
            outFile.write(sampleBuffer, nSamples * nChannels);
        } while (nSamples != 0);
    }

    // Now the input file is processed, yet 'flush' few last samples that are
    // hiding in the SoundTouch's internal processing pipeline.
    pSoundTouch->flush();
    do
    {
        nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
        outFile.write(sampleBuffer, nSamples * nChannels);
    } while (nSamples != 0);
}



extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
{
    const char *verStr;

    LOGV("JNI call SoundTouch.getVersionString");

    // Call example SoundTouch routine
    verStr = SoundTouch::getVersionString();

    /// gomp_tls storage bug workaround - see comments in _init_threading() function!
    _init_threading(false);

    int threads = 0;
    #pragma omp parallel
    {
        #pragma omp atomic
        threads ++;
    }
    LOGV("JNI thread count %d", threads);

    // return version as string
    return env->NewStringUTF(verStr);
}



extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
{
    return (jlong)(new SoundTouch());
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    delete ptr;
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    ptr->setTempo(tempo);
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    ptr->setPitchSemiTones(pitch);
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    ptr->setRate(speed);
}


extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
{
    jstring result = env->NewStringUTF(_errMsg.c_str());
    _errMsg.clear();

    return result;
}


extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
{
    SoundTouch *ptr = (SoundTouch*)handle;

    const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
    const char *outputFile = env->GetStringUTFChars(joutputFile, 0);

    LOGV("JNI process file %s", inputFile);

    /// gomp_tls storage bug workaround - see comments in _init_threading() function!
    if (_init_threading(true)) return -1;

    try
    {
        _processFile(ptr, inputFile, outputFile);
    }
    catch (const runtime_error &e)
    {
        const char *err = e.what();
        // An exception occurred during processing, return the error message
        LOGV("JNI exception in SoundTouch::processFile: %s", err);
        _setErrmsg(err);
        return -1;
    }


    env->ReleaseStringUTFChars(jinputFile, inputFile);
    env->ReleaseStringUTFChars(joutputFile, outputFile);

    return 0;
}
我导入本机函数:

public final class SoundTouch {
    public native final static String getVersionString();

// Load the native library upon startup
static
{
    System.loadLibrary("soundtouch");
}
}
这是我的
soundtouch jni.cpp
文件:

apply plugin: 'com.android.application'

android {
    signingConfigs {
        dev_key {
            keyAlias '#########'
            keyPassword '########'
            storeFile file('/Users/daniele/Desktop/Chords/########')
            storePassword '#######'
        }
    }
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.dancam.chords"
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 16
        versionName "2.1"
        signingConfig ##########
        multiDexEnabled true
    }
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
#include <jni.h>
#include <android/log.h>
#include <stdexcept>
#include <string>

using namespace std;

#include "../../../include/SoundTouch.h"
#include "../source/SoundStretch/WavFile.h"

#define LOGV(...)   __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
//#define LOGV(...)


// String for keeping possible c++ exception error messages. Notice that this isn't
// thread-safe but it's expected that exceptions are special situations that won't
// occur in several threads in parallel.
static string _errMsg = "";


#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define BUFF_SIZE 4096


using namespace soundtouch;


// Set error message to return
static void _setErrmsg(const char *msg)
{
    _errMsg = msg;
}


#ifdef _OPENMP

#include <pthread.h>
extern pthread_key_t gomp_tls_key;
static void * _p_gomp_tls = NULL;

/// Function to initialize threading for OpenMP.
///
/// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if
/// called from the Android App main thread because in the main thread the gomp_tls storage is
/// properly set, however, Android does not properly initialize gomp_tls storage for other threads.
/// Thus if OpenMP routines are invoked from some other thread than the main thread,
/// the OpenMP routine will crash the application due to NULL pointer access on uninitialized storage.
///
/// This workaround stores the gomp_tls storage from main thread, and copies to other threads.
/// In order this to work, the Application main thread needws to call at least "getVersionString"
/// routine.
static int _init_threading(bool warn)
{
    void *ptr = pthread_getspecific(gomp_tls_key);
    LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
    if (ptr == NULL)
    {
        LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
        pthread_setspecific(gomp_tls_key, _p_gomp_tls);
    }
    else
    {
        LOGV("JNI store this TLS storage");
        _p_gomp_tls = ptr;
    }
    // Where critical, show warning if storage still not properly initialized
    if ((warn) && (_p_gomp_tls == NULL))
    {
        _setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
        return -1;
    }
    return 0;
}

#else
static int _init_threading(bool warn)
{
    // do nothing if not OpenMP build
    return 0;
}
#endif


// Processes the sound file
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
{
    int nSamples;
    int nChannels;
    int buffSizeSamples;
    SAMPLETYPE sampleBuffer[BUFF_SIZE];

    // open input file
    WavInFile inFile(inFileName);
    int sampleRate = inFile.getSampleRate();
    int bits = inFile.getNumBits();
    nChannels = inFile.getNumChannels();

    // create output file
    WavOutFile outFile(outFileName, sampleRate, bits, nChannels);

    pSoundTouch->setSampleRate(sampleRate);
    pSoundTouch->setChannels(nChannels);

    assert(nChannels > 0);
    buffSizeSamples = BUFF_SIZE / nChannels;

    // Process samples read from the input file
    while (inFile.eof() == 0)
    {
        int num;

        // Read a chunk of samples from the input file
        num = inFile.read(sampleBuffer, BUFF_SIZE);
        nSamples = num / nChannels;

        // Feed the samples into SoundTouch processor
        pSoundTouch->putSamples(sampleBuffer, nSamples);

        // Read ready samples from SoundTouch processor & write them output file.
        // NOTES:
        // - 'receiveSamples' doesn't necessarily return any samples at all
        //   during some rounds!
        // - On the other hand, during some round 'receiveSamples' may have more
        //   ready samples than would fit into 'sampleBuffer', and for this reason
        //   the 'receiveSamples' call is iterated for as many times as it
        //   outputs samples.
        do
        {
            nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
            outFile.write(sampleBuffer, nSamples * nChannels);
        } while (nSamples != 0);
    }

    // Now the input file is processed, yet 'flush' few last samples that are
    // hiding in the SoundTouch's internal processing pipeline.
    pSoundTouch->flush();
    do
    {
        nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
        outFile.write(sampleBuffer, nSamples * nChannels);
    } while (nSamples != 0);
}



extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
{
    const char *verStr;

    LOGV("JNI call SoundTouch.getVersionString");

    // Call example SoundTouch routine
    verStr = SoundTouch::getVersionString();

    /// gomp_tls storage bug workaround - see comments in _init_threading() function!
    _init_threading(false);

    int threads = 0;
    #pragma omp parallel
    {
        #pragma omp atomic
        threads ++;
    }
    LOGV("JNI thread count %d", threads);

    // return version as string
    return env->NewStringUTF(verStr);
}



extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
{
    return (jlong)(new SoundTouch());
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    delete ptr;
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    ptr->setTempo(tempo);
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    ptr->setPitchSemiTones(pitch);
}


extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
{
    SoundTouch *ptr = (SoundTouch*)handle;
    ptr->setRate(speed);
}


extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
{
    jstring result = env->NewStringUTF(_errMsg.c_str());
    _errMsg.clear();

    return result;
}


extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
{
    SoundTouch *ptr = (SoundTouch*)handle;

    const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
    const char *outputFile = env->GetStringUTFChars(joutputFile, 0);

    LOGV("JNI process file %s", inputFile);

    /// gomp_tls storage bug workaround - see comments in _init_threading() function!
    if (_init_threading(true)) return -1;

    try
    {
        _processFile(ptr, inputFile, outputFile);
    }
    catch (const runtime_error &e)
    {
        const char *err = e.what();
        // An exception occurred during processing, return the error message
        LOGV("JNI exception in SoundTouch::processFile: %s", err);
        _setErrmsg(err);
        return -1;
    }


    env->ReleaseStringUTFChars(jinputFile, inputFile);
    env->ReleaseStringUTFChars(joutputFile, outputFile);

    return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
#包括“../../include/SoundTouch.h”
#包括“./source/SoundStretch/WavFile.h”
#定义LOGV(…)\uuuuuAndroid\uLog\uPrint((int)android\uLog\uInfo,“SOUNDTOUCH”、\uuuuu VA\uArgs\uuuuuu)
//#定义LOGV(…)
//字符串以保持可能的C++异常错误消息。请注意,这不是
//线程安全,但异常是不安全的特殊情况
//在多个线程中并行出现。
静态字符串_errMsg=“”;
#定义DLL\u公共属性(可见性(“默认”))
#定义BUFF_尺寸4096
使用声音触摸;
//将错误消息设置为返回
静态void_setErrmsg(const char*msg)
{
_errMsg=msg;
}
#ifdef\u OPENMP
#包括
extern pthread_key_t gomp_tls_key;
静态无效*_p_gomp_tls=NULL;
///函数为OpenMP初始化线程。
///
///这是Android NDK v10中有关OpenMP的bug的一个解决方法:OpenMP仅在
///从Android应用程序主线程调用,因为在主线程中,gomp_tls存储是
///但是,如果设置正确,Android不会为其他线程正确初始化gomp_tls存储。
///因此,如果从主线程以外的其他线程调用OpenMP例程,
///由于对未初始化存储的空指针访问,OpenMP例程将使应用程序崩溃。
///
///此解决方案存储来自主线程的gomp_tls存储,并复制到其他线程。
///为了使其工作,应用程序主线程需要WS至少调用“getVersionString”
///例行公事。
静态整数初始化线程(布尔警告)
{
void*ptr=pthread_getspecific(gomp_tls_键);
LOGV(“JNI线程特定TLS存储%ld”,(长)ptr);
如果(ptr==NULL)
{
LOGV(“JNI将缺少的TLS存储设置为%ld”,(长)\u p\u gomp\u TLS);
pthread_setspecific(gomp_tls_键,_p_gomp_tls);
}
其他的
{
LOGV(“JNI存储此TLS存储”);
_p_gomp_tls=ptr;
}
//在关键位置,如果存储仍未正确初始化,则显示警告
如果((警告)和(_p_gomp_tls==NULL))
{
_setErrmsg(“错误-OpenMP线程未正确初始化:从应用程序主线程调用SoundTouch.getVersionString());
返回-1;
}
返回0;
}
#否则
静态整数初始化线程(布尔警告)
{
//如果不是OpenMP构建,则不执行任何操作
返回0;
}
#恩迪夫
//处理声音文件
静态void\u进程文件(SoundTouch*pSoundTouch,const char*inFileName,const char*outFileName)
{
int nSamples;
内部通道;
int buffSizeSamples;
SAMPLETYPE sampleBuffer[BUFF_SIZE];
//打开输入文件
波纹填充物(填充物名称);
int sampleRate=infle.getSampleRate();
int bits=infle.getNumBits();
nChannels=infle.getNumChannel();
//创建输出文件
波形输出文件输出文件(输出文件名称、采样器、位、通道);
pSoundTouch->setSampleRate(采样器);
pSoundTouch->setChannels(nChannels);
断言(nChannels>0);
buffSizeSamples=BUFF_大小/n通道;
//处理从输入文件读取的样本
而(infle.eof()==0)
{
int-num;
//从输入文件中读取样本块
num=infle.read(sampleBuffer,BUFF_SIZE);
nSamples=num/n通道;
//将样本输入SoundTouch处理器
pSoundTouch->putSamples(采样缓冲区、nsSamples);
//从SoundTouch处理器读取准备好的样本并将其写入输出文件。
//注:
//-“receiveSamples”不一定返回任何样本
//在一些回合中!
//-另一方面,在某些回合中,“接收样品”可能会有更多
//准备好的样品比“样品缓冲区”中的样品更合适,因此
//“receiveSamples”调用的迭代次数与调用的次数相同
//输出样本。
做
{
nSamples=pSoundTouch->receiveSamples(sampleBuffer,buffSizeSamples);
写入(采样缓冲区、nSamples*nChannels);
}而(nSamples!=0);
}
//现在输入文件已被处理,但“刷新”了最后几个已处理的示例
//隐藏在SoundTouch的内部处理管道中。
pSoundTouch->flush();
做
{
nSamples=pSoundTouch->receiveSamples(sampleBuffer,buffSizeSamples);
写入(采样缓冲区、nSamples*nChannels);
}而(nSamples!=0);
}
外部“C”DLL\u公共jstring Java\u net\u surina\u soundtouch\u soundtouch\u getVersionString(JNIEnv*env,jobject thiz)
{
const char*verStr;
LOGV(“JNI调用SoundTouch.getVersionString”);
//调用示例SoundTouch例程
verStr=SoundTouch::getVersionString();
///gomp_tls存储错误解决方法-请参阅_init_threading()函数中的注释!
_初始线程(假);
int线程=0;
#pragma-omp并行
{
#布拉格omp原子
线程++;
}
LOGV(“JNI线程计数%d”,线程);
//以字符串形式返回版本
返回env->NewStringUTF(verStr);
}
外部“C”DLL_PUBLIC jlong Java_net_surina_soundtouch_soundtouch_newInstance(JNIEnv*env,jobject thiz)
{
返回(jlong)(新SoundTouch());
}
外部“C”DLL_PUBLIC void Java_net_surina_soundtouch_soundtouch_deleteInstance(JNIEnv*env,jobject thiz,jlong handle)
{
SoundTouch*ptr=(SoundTouch*)手柄;
删除ptr;
}
外部“C”DLL\u公共无效Java\u网络\u surina\u soundtouch\u soundtouch
externalNativeBuild.ndkBuild.path = 'jni/Android.mk'
ndk { abiFilters 'armeabi-v7a' }
sourceSets.main.jniLibs.srcDir 'libs'