Search code examples
androidjava-native-interfaceandroid-ndk

Unable to create Audio player via OpenSL ES


I have been trying to create an Audio player via the OpenSL ES API's for Android. However, I get an error when I try to run my code, which signals that I fed a bad parameter to CreateAudioPlayer():

05-16 12:16:40.593: ERROR/libOpenSLES(2020): channelMask=0x100 numChannels=1
05-16 12:16:40.593: ERROR/AudioProcessor_Native(2020): Invalid parameter found
05-16 12:16:40.593: ERROR/AudioProcessor_Native(2020): Unable to create player object

However, I have not been able to find any bad or invalid parameters. I've checked any one of them, and haven't found anything on the web that should suggest that my combination is invalid. The code looks like this:

JNIEXPORT jboolean JNICALL Java_org_test_opensl_AudioProcessor_initPlayer(JNIEnv* env, jobject thiz){
    SLresult result;
    // Configure Buffer Queue.
    SLDataLocator_AndroidSimpleBufferQueue bufferQueue;
    bufferQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
    bufferQueue.numBuffers = MAX_BUFFERS;
    // Configure data format.
    SLDataFormat_PCM pcm;
    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
    pcm.channelMask = SL_SPEAKER_BACK_CENTER;
    pcm.containerSize = 16;
    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
    pcm.formatType = SL_DATAFORMAT_PCM;
    pcm.numChannels = 1;
    pcm.samplesPerSec = SL_SAMPLINGRATE_8;
    // Configure Audio Source.
    SLDataSource source;
    source.pFormat = &pcm;
    source.pLocator = &bufferQueue;
    // Configure output mix.
    SLDataLocator_OutputMix outputMix;
    outputMix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
    outputMix.outputMix = outputMixObject;
    // Configure Audio sink.
    SLDataSink sink;
    sink.pFormat = NULL;
    sink.pLocator = &outputMix;
    // Create Audio player.
    const SLInterfaceID ids[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};
    result = (*engineInstance)->CreateAudioPlayer(engineInstance, &playerObject, &source,
                                                  &sink, 1, ids, req);
    if(checkError(result, "Unable to create player object") == -1){
        return JNI_FALSE;
    }
    // Realize Audio player.
    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
    if(checkError(result, "Unable to realize player object") == -1){
        return JNI_FALSE;
    }
    // Get the Audio player interface.
    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerInstance);
    if(checkError(result, "Unable to get player interface") == -1){
        return JNI_FALSE;
    }
    // Get the Player Buffer Queue interface.
    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
                                           &playerBufferQueue);
    if(checkError(result, "Unable to get player buffer interface") == -1){
        return JNI_FALSE;
    }
    // Set the player's state to playing.
    result = (*playerInstance)->SetPlayState(playerInstance, SL_PLAYSTATE_PLAYING);
    if(checkError(result, "Unable to set player's state to playing") == -1){
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

Where checkError() is a self-defined error checking method.

Anybody got any ideas on why this would fail? As I've said, all the parameters look valid to me, and I've checked for invalid combinations in the source, outputmix or sink objects, which there weren't...


Solution

  • I've fixed this not by good, sufficient documentation, but more by luck. It turns out that my PCM properties in the SLDataFormat_PCM object weren't in the right order....

    When I changed it to:

    // Configure data format.
    SLDataFormat_PCM pcm;
    pcm.formatType = SL_DATAFORMAT_PCM;
    pcm.numChannels = 1;
    pcm.samplesPerSec = SL_SAMPLINGRATE_8;
    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
    pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
    pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
    

    it would create the AudioPlayer without a hitch...

    I don't know why this happened though, maybe it is because it is a struct that needs to be set in the correct sequence? I don't know... I can't really imagine it though... Unless it is more of a memory map for one or more variables, in which I can imagine....

    Anyway, I fixed it... sigh