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!
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.