Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android weird AudioTrack crash

I'm an Android App developer and I'm in trouble with the following crash report (i got 5/6 of those per day):

  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)

The OpenSL functions are called in JNI world.

Those are all the vars stored in the heap:

/* 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;

This is how I've initialized all the machinery:

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;
}

This is called to start the machinery.

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);
}

This is the callback that enqueue new samples

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);
}

And finally, this is how OpenSL is terminated

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");
}

I can't reproduce on my phone and on emulators... It just never crashes this way.

I ran out of ideas about how to fix this. Could someone help me to get rid of this crash?

update October 8th

I tried to remove logs as suggested. Crash still occours.

The problem affects Android 6.0, 7.0 and 7.1 (at least, I got no reports for different versions)

update October 9th

As requested by Amjad Khan:

This is the Android.mk that generates the library

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)

and this is the command ran to build the library (all ABIs are generated)

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

Thank you in advance.

like image 974
Davide Berra Avatar asked Sep 25 '17 10:09

Davide Berra


1 Answers

I have seen the crash it is same as my crash which is generated due to android logs, recently I uploaded the apk and found the same trace.

  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)

This backtrace was my recent update so I was doing the android log printing in my native file.

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

I was printing my data using logs to check when I uploaded I got that backtrace, So I have removed all the logs from native and the java function which are called from native.

Then, After I have done clean build and uploaded, so in the latest build it is not generated till now more than 5 build uploaded

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

And here u will find the way to easy find out the native bugs

  • Diagnosing Native Crashes.

  • Debugging Native Android Platform Code

like image 64
Amjad Khan Avatar answered Nov 14 '22 23:11

Amjad Khan