Android OpenSL ES - issue with .wav file sampled at 44.1Khz

794 views Asked by At

I'm trying to convert some of my OpenAL code to OpenSL ES for my Android usage (Kitkat 4.4.4) on Genymotion and encountered an issue with .wav files sampled at 44.1Khz. My application is a native one (glue).

I've followed the /native-audio sample of Android NDK samples and fragments from the excellent book Android NDK Beginners Guide, so my code behaves correctly on most of wav/PCM data, except those sampled at 44.1Khz. My specific code is this:

Engine init

  // create OpenSL ES engine
  SLEngineOption EngineOption[] = {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE};
  const SLInterfaceID lEngineMixIIDs[] = {SL_IID_ENGINE};
  const SLboolean lEngineMixReqs[] = {SL_BOOLEAN_TRUE};
  SLresult res = slCreateEngine(&mEngineObj, 1, EngineOption, 1, lEngineMixIIDs, lEngineMixReqs);
  res = (*mEngineObj)->Realize(mEngineObj, SL_BOOLEAN_FALSE);
  res = (*mEngineObj)->GetInterface(mEngineObj, SL_IID_ENGINE, &mEngine);   // get 'engine' interface
  // create output mix (AKA playback; this represents speakers, headset etc.)
  res = (*mEngine)->CreateOutputMix(mEngine, &mOutputMixObj, 0,NULL, NULL);
  res = (*mOutputMixObj)->Realize(mOutputMixObj, SL_BOOLEAN_FALSE);

Player init

  SLresult lRes;
  // Set-up sound audio source.
  SLDataLocator_AndroidSimpleBufferQueue lDataLocatorIn;
  lDataLocatorIn.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
  lDataLocatorIn.numBuffers = 1;   // 1 buffer for a one-time load
  // analyze and set correct PCM format
  SLDataFormat_PCM lDataFormat;
  lDataFormat.formatType = SL_DATAFORMAT_PCM;

  lDataFormat.numChannels = audio->wav.channels;     // etc. 1,2
  lDataFormat.samplesPerSec = audio->wav.sampleRate * 1000;   // etc. 44100 * 1000
  lDataFormat.bitsPerSample = audio->wav.bitsPerSample;   // etc. 16
  lDataFormat.containerSize = audio->wav.bitsPerSample;
  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 SLInterfaceID lSoundPlayerIIDs[] = { SL_IID_PLAY, SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  const SLboolean lSoundPlayerReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
  lRes = (*mEngine)->CreateAudioPlayer(mEngine, &mPlayerObj, &lDataSource, &lDataSink, 2, lSoundPlayerIIDs, lSoundPlayerReqs);
  if (lRes != SL_RESULT_SUCCESS) { return; }
  lRes = (*mPlayerObj)->Realize(mPlayerObj, SL_BOOLEAN_FALSE);
  if (lRes != SL_RESULT_SUCCESS) { return; }
  lRes = (*mPlayerObj)->GetInterface(mPlayerObj, SL_IID_PLAY, &mPlayer);
  if (lRes != SL_RESULT_SUCCESS) { return; }

  lRes = (*mPlayerObj)->GetInterface(mPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &mPlayerQueue);
  if (lRes != SL_RESULT_SUCCESS) { return; }
  // register callback on the buffer queue
  lRes = (*mPlayerQueue)->RegisterCallback(mPlayerQueue, bqPlayerQueueCallback, NULL);
  if (lRes != SL_RESULT_SUCCESS) { return; }
  lRes = (*mPlayer)->SetCallbackEventsMask(mPlayer, SL_PLAYEVENT_HEADATEND);
  if (lRes != SL_RESULT_SUCCESS) { return; }

  // ..fetch the data in 'audio->data' from opened FILE* stream and set 'datasize'

  // feed the buffer with data
  lRes = (*mPlayerQueue)->Clear(mPlayerQueue);   // remove any sound from buffer
  lRes = (*mPlayerQueue)->Enqueue(mPlayerQueue, audio->data, datasize);

The above works good for 8000, 22050 and 32000 samples/sec but on 41100 samples, 4 out of 5 times it will repeat itself lots of time on first play. It's like having a door knocking sound effect that actually loops many times (about 50 times) by a single ->SetPlayState(..SL_PLAYSTATE_PLAYING); and in speed. Any obvious error on my code? a multi-threaded issue with these sampling? Anyone else have this kind of problem? Should i downsample on 41.1Khz cases ? Could it be a Genymotion problem? tx

1

There are 1 answers

0
AudioBubble On

I solved this by downsampling from 44Khz to 22Khz. Interestingly, this only happens on sounds containing 1 channel and 44,100 samples; in all other cases there's no problem.