Android上的PCM缓冲区队列的OpenSL SL_IID_RATEPITCH和SL_IID_VOLUME

时间:2013-11-18 04:32:32

标签: android-ndk opensl

我在Android NDK上使用PCM缓冲区队列在OpenSL ES中创建了一个多声道音频系统。尽管Android文档说支持这两个接口,但我似乎无法让操作系统支持SL_IID_RATEPITCH和SL_IID_VOLUME。下面是我的初始化代码。我做错了吗?

static SLresult InitChannel(int i)
{
    SLresult lRes;
    OpenSLChannel *channel = &sndc[i];

    // Initialize stuff for playing PCM channels
    // Set-up sound audio source.
    SLDataLocator_AndroidSimpleBufferQueue lDataLocatorIn;
    lDataLocatorIn.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
    // At most one buffer in the queue.
    lDataLocatorIn.numBuffers = 1;

    SLDataFormat_PCM lDataFormat;
    lDataFormat.formatType = SL_DATAFORMAT_PCM;
    lDataFormat.numChannels = 1; // Mono sound.
    lDataFormat.samplesPerSec = SL_SAMPLINGRATE_22_05; // BASE_FREQUENCY
    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;

    // Create and realize the sound player.
    // We are going to need its SL_IID_PLAY and also SL_IID_BUFFERQUEUE interface
    // now available thanks to the data locator configured in the previous step.
    const SLuint32 lSoundPlayerIIDCount = 4;
    const SLInterfaceID lSoundPlayerIIDs[] = { SL_IID_PLAY, SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_RATEPITCH };
    const SLboolean lSoundPlayerReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE };

    lRes = (*mEngine)->CreateAudioPlayer(mEngine, &channel->mPlayerObj, &lDataSource, &lDataSink, lSoundPlayerIIDCount, lSoundPlayerIIDs, lSoundPlayerReqs);
    if (lRes != SL_RESULT_SUCCESS)
        return lRes;

    lRes = (*channel->mPlayerObj)->Realize(channel->mPlayerObj, SL_BOOLEAN_FALSE);
    if (lRes != SL_RESULT_SUCCESS)
        return lRes;

    lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_PLAY, &channel->mPlayer);
    if (lRes != SL_RESULT_SUCCESS)
        return lRes;

    lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_BUFFERQUEUE, &channel->mPlayerQueue);
    if (lRes != SL_RESULT_SUCCESS)
        return lRes;

    // Get Volume Interface
    lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_VOLUME, &channel->mVolume);
    if (lRes != SL_RESULT_SUCCESS)
    {
        Err_Printf("Volume interface not supported.\n");
//      return lRes;
    }

    lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_RATEPITCH, &channel->mRatePitch);
    if (lRes != SL_RESULT_SUCCESS)
    {
        Err_Printf("RatePitch interface not supported.\n");
//      return lRes;
    }

    lRes = (*channel->mPlayerQueue)->RegisterCallback(channel->mPlayerQueue, SoundFinished, channel);
//  slCheckErrorWithStatus(lRes, "Problem registering player callback (Error %d).", lRes);
    lRes = (*channel->mPlayer)->SetCallbackEventsMask(channel->mPlayer, SL_PLAYEVENT_HEADATEND);
//  slCheckErrorWithStatus(lRes, "Problem registering player callback mask (Error %d).", lRes);
}

//
// SystemInit
//
// Initialization for
// the sound subsystem.
//
void SystemInit(void)
{
    mEngineObj = NULL;
    mEngine = NULL;
    mOutputMixObj = NULL;

    Err_Printf("Starting OpenSL ES...\n");
    SLresult lRes;
    const SLuint32 lEngineMixIIDCount = 1;
    const SLInterfaceID lEngineMixIIDs[] = { SL_IID_ENGINE };
    const SLboolean lEngineMixReqs[] = { SL_BOOLEAN_TRUE };
    const SLuint32 lOutputMixIIDCount = 2;
    const SLInterfaceID lOutputMixIIDs[] = { SL_IID_VOLUME, SL_IID_RATEPITCH };
    const SLboolean lOutputMixReqs[] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE };

    lRes = slCreateEngine(&mEngineObj, 0, NULL, lEngineMixIIDCount, lEngineMixIIDs, lEngineMixReqs);
    if (lRes != SL_RESULT_SUCCESS)
        goto ERROR; // lolwut?

    lRes = (*mEngineObj)->Realize(mEngineObj, SL_BOOLEAN_FALSE);
    if (lRes != SL_RESULT_SUCCESS)
        goto ERROR;

    lRes = (*mEngineObj)->GetInterface(mEngineObj, SL_IID_ENGINE, &mEngine);
    if (lRes != SL_RESULT_SUCCESS)
        goto ERROR;

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

    int i;
    for (i = 0; i < NUMCHANNELS; i++)
    {
        lRes = InitChannel(i);
        if (lRes != SL_RESULT_SUCCESS)
            goto ERROR;
    }

    return;

ERROR:
    Err_Printf("Error while starting OpenSL ES.");
    SystemShutdown();
}

1 个答案:

答案 0 :(得分:1)

支持SL_IID_VOLUME,但它只允许衰减(最大增益为0)。 OpenAL的0.0-1.0的近似值是:

float attenuation = 1.0f / 1024.0f + gain * 1023.0f / 1024.0f;
float db = 3 * log10(attenuation) / log10(2);
SLmillibel setGain = (SLmillibel)(db * 1000);

不支持SL_IID_RATEPITCH,但SL_IID_PLAYBACKRATE是。不幸的是,它只允许此时将速度设置为0.5到2.0。