Android 奇怪的 AudioTrack 崩溃

标签 android audio opensl

我是一名 Android 应用程序开发人员,我遇到了以下崩溃报告的麻烦(我每天收到 5/6 的崩溃报告):

  native: pc 00000000000418e0  /system/lib/libc.so (tgkill+12)
  native: pc 0000000000040d59  /system/lib/libc.so (pthread_kill+32)
  native: pc 000000000001c7eb  /system/lib/libc.so (raise+10)
  native: pc 000000000001999d  /system/lib/libc.so (__libc_android_abort+34)
  native: pc 0000000000017550  /system/lib/libc.so (abort+4)
  native: pc 0000000000008d53  /system/lib/libcutils.so (__android_log_assert+86)
  native: pc 000000000006e2c3  /system/lib/libmedia.so (_ZN7android11ClientProxy13releaseBufferEPNS_5Proxy6BufferE+94)
  native: pc 000000000006c11d  /system/lib/libmedia.so (_ZN7android10AudioTrack13releaseBufferEPKNS0_6BufferE+112)
  native: pc 000000000006c987  /system/lib/libmedia.so (_ZN7android10AudioTrack18processAudioBufferEv+1350)
  native: pc 000000000006d7f3  /system/lib/libmedia.so (_ZN7android10AudioTrack16AudioTrackThread10threadLoopEv+194)
  native: pc 0000000000010079  /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+112)
  native: pc 000000000004065b  /system/lib/libc.so (_ZL15__pthread_startPv+30)
  native: pc 000000000001a021  /system/lib/libc.so (__start_thread+6)

OpenSL 函数在JNI 世界中被调用。

这些是存储在堆中的所有变量:

/* OpenSL ES audio stuff */
SLObjectItf engineObject = NULL;
SLEngineItf engineEngine = NULL;
SLObjectItf outputMixObject = NULL;
SLObjectItf playerObject = NULL;
SLPlayItf   playerPlay = NULL;
SLVolumeItf playerVolume = NULL;
SLAndroidSimpleBufferQueueItf playerBufferQueue = NULL;
char        openSLinited = 0;

int16_t     audioBuffer1[48000];
int16_t     audioBuffer2[48000];
int16_t    *currentAudioBuffer;

这就是我初始化所有机器的方式:

void Java_com_myapp_myappname_MyActivity_jniOpenSLInit(JNIEnv *env,
                                                       jobject thiz,
                                                       jint freq)
{
    SLresult result;

    // create engine
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    assert(SL_RESULT_SUCCESS == result);

    // realize the engine
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the engine interface, which is needed to create other objects
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE,
                                           &engineEngine);
    assert(SL_RESULT_SUCCESS == result);

    // create output mix
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject,
                                              0, NULL, NULL);
    assert(SL_RESULT_SUCCESS == result);

    // realize the output mix
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    SLuint32 SLfreq;
    if (freq == 44100)
        SLfreq = SL_SAMPLINGRATE_44_1;
    else
        SLfreq = SL_SAMPLINGRATE_48;

    SLDataLocator_AndroidSimpleBufferQueue loc_bufq =
        {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SLfreq,
                                   SL_PCMSAMPLEFORMAT_FIXED_16,
                                   SL_PCMSAMPLEFORMAT_FIXED_16,
                                   SL_SPEAKER_FRONT_LEFT |
                                   SL_SPEAKER_FRONT_RIGHT,
                                   SL_BYTEORDER_LITTLEENDIAN};

    SLDataSource audioSrc = {&loc_bufq, &format_pcm};

    /* configure audio sink */
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX,
                                          outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};

    const SLInterfaceID idsAudioPlayer[2] = {SL_IID_BUFFERQUEUE,
                                             SL_IID_VOLUME };

    const SLboolean reqAudioPlayer[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };

    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject,
                                                &audioSrc,
                                                &audioSnk, 2, idsAudioPlayer,
                                                reqAudioPlayer);
    assert(SL_RESULT_SUCCESS == result);

    // realize the player
    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the play interface
    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY,
                                           &playerPlay);
    assert(SL_RESULT_SUCCESS == result);

    // get the volume interface
    result = (*playerObject)->GetInterface(playerObject, SL_IID_VOLUME,
                                           &playerVolume);
    assert(SL_RESULT_SUCCESS == result);

    // get the buffer queue interface
    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
                                           &playerBufferQueue);
    assert(SL_RESULT_SUCCESS == result);

    // register callback on the buffer queue
    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue,
                                                    audio_player_cb, NULL);
    assert(SL_RESULT_SUCCESS == result);

    // done!
    openSLinited = 1;
}

这被称为启动机器。

void openSLStart()
{
    bzero(audioBuffer1, 96000);
    bzero(audioBuffer2, 96000);

    if (!openSLinited)
        return;

    (*playerBufferQueue)->Enqueue(playerBufferQueue, audioBuffer1,
                                  4096 * 4);
    (*playerBufferQueue)->Enqueue(playerBufferQueue, audioBuffer2,
                                  4096 * 4);

    currentAudioBuffer = audioBuffer1;

    // set the player's state to playing
    (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
}

这是入队新样本的回调

void audio_player_cb(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    if (!openSLinited)
        return;

    assert(bq == playerBufferQueue);
    assert(NULL == context);

    // switch between audio buffer 1 and 2
    if (currentAudioBuffer == audioBuffer1)
        currentAudioBuffer = audioBuffer2;
    else
        currentAudioBuffer = audioBuffer1;

    // this function read samples (4096 16 bit samples) from an internal buffer
    sound_read_samples(4096, currentAudioBuffer);

    // feed openSL machine
    (*playerBufferQueue)->Enqueue(playerBufferQueue, currentAudioBuffer,
                                  4096 * 2);
}

最后,这就是 OpenSL 的终止方式

void Java_com_myfirm_myappname_MyActivity_jniOpenSLTerm(JNIEnv *env,
                                                        jobject thiz)
{
    // shutdown every created object
    if (playerObject)
    {
        // stop the player
        SLresult result = (*playerPlay)->SetPlayState(playerPlay,
                                                      SL_PLAYSTATE_STOPPED);

        if (SL_RESULT_SUCCESS == result)
            utils_log("Player succesfully stopped");

        (*playerObject)->Destroy(playerObject);
        playerObject = NULL;
        playerPlay = NULL;
    }

    if (outputMixObject)
    {
        (*outputMixObject)->Destroy(outputMixObject);
        outputMixObject = NULL;
    }

    if (engineObject)
    {
        (*engineObject)->Destroy(engineObject);
        engineObject = NULL;
    }

    openSLinited = 0;

    utils_log("OpenSLTerm complete");
}

我无法在我的手机和模拟器上重现......它永远不会以这种方式崩溃。

我想不出如何解决这个问题。有人可以帮我摆脱这次崩溃吗?

10 月 8 日更新

我尝试按照建议删除日志。崩溃仍然发生。

这个问题影响到 Android 6.0、7.0 和 7.1(至少,我没有收到不同版本的报告)

10 月 9 日更新

根据 Amjad Khan 的要求:

这是生成库的Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libmyapp-jni
LOCAL_SRC_FILES := src.c src2.c src3.c 
LOCAL_LDLIBS := -llog -landroid -ljnigraphics -lGLESv2 -lOpenSLES
LOCAL_CFLAGS += -O3 -DNDEBUG

include $(BUILD_SHARED_LIBRARY)

这是构建库的命令(生成所有 ABI)

/cygdrive/c/Android/ndk/ndk-build.cmd NDK_DEBUG=0 APP_BUILD_SCRIPT=./Android.mk NDK_PROJECT_PATH=. 

提前谢谢你。

最佳答案

我看到的崩溃和我的崩溃是一样的,是由于android日志产生的,最近我上传了apk,发现了同样的踪迹。

  native: pc 0000000000048793  /system/lib/libc.so (pthread_kill+34)
  native: pc 000000000001d5d5  /system/lib/libc.so (raise+10)
  native: pc 0000000000019111  /system/lib/libc.so (__libc_android_abort+34)
  native: pc 0000000000017174  /system/lib/libc.so (abort+4)
  native: pc 000000000000c481  /system/lib/libcutils.so (__android_log_assert+112)
  native: pc 0000000000025595  /system/lib/libhwui.so
  native: pc 00000000000270d1  /system/lib/libhwui.so
  native: pc 000000000002b959  /system/lib/libhwui.so (_ZN7android10uirenderer12renderthread12RenderThread10threadLoopEv+80)
  native: pc 000000000000e35d  /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+140)
  native: pc 000000000006830b  /system/lib/libandroid_runtime.so (_ZN7android14AndroidRuntime15javaThreadShellEPv+102)
  native: pc 0000000000048263  /system/lib/libc.so (_ZL15__pthread_startPv+22)
  native: pc 0000000000019b5d  /system/lib/libc.so (__start_thread+6)

这个回溯是我最近的更新,所以我在我的 native 文件中打印 android 日志。

__android_log_print(ANDROID_LOG_ERROR, "TRACKERS", "%s", Str);

我使用日志打印我的数据以检查我何时上传我得到了那个回溯,所以我已经删除了 native 的所有日志和从 native 调用的 java 函数。

然后,在我完成干净的构建并上传之后,所以在最新的构建中它不会生成,直到现在上传了超过 5 个构建

Android-specific log support

contains various definitions that an app can use to send log messages to the kernel from native code. For more information about these definitions, see the comments in .

You can write your own wrapper macros to access this functionality. If you wish to perform logging, your native module should link to /system/lib/liblog.so. Implement this linking by including the following line in your Android.mk file:

LOCAL_LDLIBS := -llog

在这里你会找到轻松找出原生错误的方法

关于Android 奇怪的 AudioTrack 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46403487/

相关文章:

android - Android、服务器和图像创建之间的架构难题

java - 如何在自定义键盘中播放声音

javascript - AudioJS - 停止使用 javascript?

android - 在 Android 上使用 OpenSL 从内存中播放 PCM WAVE 声音

android - attachAuxEffect 和 OpenSL ES

java - libgdx 在触摸位置绘制图像

java - 字符串比较应该相等时却不相等

c# - 将音频文件转换为 mp3

C - 为什么用 & 而不是 switch/if 来比较常量?

java - 在 Android 中使用 DecimalFormat 格式化数字