Search code examples
androidc++android-ndkopensl

OpenSL on Android plays at a higher rate than it should


I managed to create an OpenSL context and all so that it plays sound.
But I still have a problem: I set the samplesPerSec for my Player to 44.100 Hz but it actually runs at ~ 70.000 Hz. How could one fix that?

Well I'll show you what I've done (full at Source Code):

In PolyOpenSLInterface.cpp I'm initializing OpenSL and start enqueuing a buffer to my SLAndroidSimpleBufferQueueItf. I create the Player the following way:

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

SLDataFormat_PCM lDataFormat;
lDataFormat.formatType = SL_DATAFORMAT_PCM;
lDataFormat.numChannels = POLY_NUM_CHANNELS;
lDataFormat.samplesPerSec = SL_SAMPLINGRATE_44_1; //sampling rate 44.100Hz
lDataFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
lDataFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
if(POLY_NUM_CHANNELS > 1){
    lDataFormat.channelMask = SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_LEFT;
} else {
    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[] = { SL_IID_PLAY, SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean lSoundPlayerReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };

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

My registered callback looks like this (I take the already used buffer and write the next samples into it and enqueue the buffer again):

void OpenSLAudioInterface::queueCallback(SLAndroidSimpleBufferQueueItf caller, void* pContext){
    OpenSLAudioInterface *audioInterface = (OpenSLAudioInterface*) pContext;
    if(audioInterface->buffer && audioInterface->getMixer()) {
        int16_t *out = (int16_t*)audioInterface->buffer;
        audioInterface->getMixer()->mixIntoBuffer(out, POLY_FRAMES_PER_BUFFER);
        (*(audioInterface->mPlayerQueue))->Enqueue(audioInterface->mPlayerQueue, out, sizeof(int16_t)*POLY_FRAMES_PER_BUFFER*POLY_NUM_CHANNELS);
    }
}

So can anyone explain, why the sound is played ~2 times faster than it should be and why the samples I need to mix to fill the buffer exceed the 44.100Hz by a factor of ~2?
Do I need to use a circular buffer (is the one I'm using here still being used by OpenSL?)?

Thanks for every suggestions and help in advance!


Solution

  • So I solved this issue.
    I actually initialized OpenSL twice and therefore also started to write to two concurrent bufferqueues from one source - this lead to half the frames not being properly played.