Search code examples
c++android-ndkopensl

Android OpenSL ES crashes while initialization


so I am stuck with porting Polycode to Android.
I am trying to implement an audio inteface via OpenSL ES. I read some articles, tried to copy as much as possible from the android ndk examples and so on but nothing worked - reliably - for me..

I am using the latest Android Studio (2.1.1) and hence the latest NDK (12RC1). For tests I am using my Fairphone 2 (API level 21) and the Emulator (Nexus 5 API level 23).

The app is usually crashing when calling CreateAudioPlayer, sometimes when realizing the player object, sometimes at SetPlayState. But it also happens that the complete initialization just works. This is device independent.

On my Fairphone I get these warnings when realizing the player object:

org.polycode.templateapp D/AudioTrack: TrackOffload: AudioTrack Offload disabled by property, returning false
org.polycode.templateapp W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by client

My init code looks like this:

SLresult lRes;

const SLInterfaceID lEngineMixIIDs[]={SL_IID_ENGINE};
const SLboolean lEngineMixReqs[]={SL_BOOLEAN_TRUE};
const SLuint32 lOutputMixIIDCount=0;
const SLInterfaceID lOutputMixIIDs[]={};
const SLboolean lOutputMixReqs[]={};

lRes = slCreateEngine(&mEngineObj, 0, NULL, 1, lEngineMixIIDs, lEngineMixReqs);
lRes = (*mEngineObj)->Realize(mEngineObj,SL_BOOLEAN_FALSE);
lRes = (*mEngineObj)->GetInterface(mEngineObj, SL_IID_ENGINE, &mEngine);

lRes=(*mEngine)->CreateOutputMix(mEngine, &mOutputMixObj,lOutputMixIIDCount,lOutputMixIIDs, lOutputMixReqs);
lRes=(*mOutputMixObj)->Realize(mOutputMixObj, SL_BOOLEAN_FALSE);

SLDataLocator_AndroidSimpleBufferQueue lDataLocatorIn;
lDataLocatorIn.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
lDataLocatorIn.numBuffers = 1;

SLDataFormat_PCM lDataFormat;
lDataFormat.formatType = SL_DATAFORMAT_PCM;
lDataFormat.numChannels = 1; // Mono sound.
lDataFormat.samplesPerSec = SL_SAMPLINGRATE_44_1;
lDataFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
lDataFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
lDataFormat.channelMask = SL_SPEAKER_FRONT_CENTER;
lDataFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;

SLDataSource lDataSource;
lDataSource.pLocator = &lDataLocatorIn;
lDataSource.pFormat = &lDataFormat;

SLDataLocator_OutputMix lDataLocatorOut;
lDataLocatorOut.locatorType = SL_DATALOCATOR_OUTPUTMIX;
lDataLocatorOut.outputMix = mOutputMixObj;

SLDataSink lDataSink;
lDataSink.pLocator = &lDataLocatorOut;
lDataSink.pFormat = NULL;

const SLuint32 lSoundPlayerIIDCount = 2;
const SLInterfaceID lSoundPlayerIIDs[3] = { SL_IID_PLAY, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };
const SLboolean lSoundPlayerReqs[3] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };

lRes = (*mEngine)->CreateAudioPlayer(mEngine, &mPlayerObj, &lDataSource, &lDataSink, lSoundPlayerIIDCount, lSoundPlayerIIDs, lSoundPlayerReqs);
lRes = (*mPlayerObj)->Realize(mPlayerObj, SL_BOOLEAN_FALSE);

lRes = (*mPlayerObj)->GetInterface(mPlayerObj, SL_IID_PLAY, &mPlayer);
lRes = (*mPlayerObj)->GetInterface(mPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &mPlayerQueue);

lRes = (*mPlayerQueue)->RegisterCallback(mPlayerQueue, OpenSLAudioInterface::queueCallback, this);

lRes = (*mPlayer)->SetPlayState(mPlayer, SL_PLAYSTATE_PLAYING);

What I was wondering about: is there anything I have to wait for to be initialized before I can start initializing OpenSL?
At the moment I am initializing OpenSL from thread started in onCreate. onCreate is still waiting to be finished.

Or do I miss any Android configuration or permission to use OpenSL? Or is there just something wrong with my code?

For full code see: https://github.com/fodinabor/Polycode/tree/OpenSL/src/core/PolyOpenSLAudioInterface.cpp
and https://github.com/fodinabor/Polycode/tree/OpenSL/include/polycode/core/PolyOpenSLAudioInterface.h

Android Studio projects are in: https://github.com/fodinabor/Polycode/tree/OpenSL/build/android (the TemplateApp is what I'm using for tests)

Any help or even tips are welcome!


Solution

  • Okay, so I tried to initialize OpenSL after the Native Window is created - and this seems to be working. So I guess it has been a threading issue.

    I don't think it needs to be after native window is created but it has to be after "ANativeActivity_onCreate" finished.