Android OpenSL不支持SL_IID_PLAYBACKRATE?

时间:2014-01-07 06:47:11

标签: android android-ndk opensl

我使用NDK创建了一个音频乐器,为了获得低延迟性能,我选择OpenSL来播放音乐文件。但是我没能改变播放音乐的播放速度。 这是快照代码:

int OpenSLSoundPool::createOggAudioPlayer(const char *filename, int rate){
    SLresult result;
    AAsset* asset = AAssetManager_open(mMgr, filename, AASSET_MODE_UNKNOWN);
    if (NULL == asset) {
        return JNI_FALSE;
    }

    // open asset as file descriptor
    off_t start, length;
    int fd = AAsset_openFileDescriptor(asset, &start, &length);
    assert(0 <= fd);
    AAsset_close(asset);

    // configure audio source
    SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
    SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
    SLDataSource audioSrc = {&loc_fd, &format_mime};

    // configure audio sink
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};

    // create audio player
    const SLInterfaceID ids[4] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME, SL_IID_PLAYBACKRATE};
    const SLboolean req[4] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &fdPlayerObject, &audioSrc, &audioSnk,
            4, ids, req);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    // realize the player
    result = (*fdPlayerObject)->Realize(fdPlayerObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    // get the play interface
    result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_PLAY, &fdPlayerPlay);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    // get the seek interface
    result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_SEEK, &fdPlayerSeek);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    // get the mute/solo interface
    result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_MUTESOLO, &fdPlayerMuteSolo);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    // get the volume interface
    result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_VOLUME, &fdPlayerVolume);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    // get playback rate interface
    result = (*fdPlayerObject)->GetInterface(fdPlayerObject,
            SL_IID_PLAYBACKRATE, &fdPlayerRate);
    assert(SL_RESULT_SUCCESS == result);


    SLuint32 capa;
    result = (*fdPlayerRate)->GetRateRange(fdPlayerRate, 0,
                &playbackMinRate, &playbackMaxRate, &playbackRateStepSize, &capa);
    assert(SL_RESULT_SUCCESS == result);

    result = (*fdPlayerRate)->SetRate(fdPlayerRate, playbackMaxRate);
    assert(SL_RESULT_SUCCESS == result);

    SLpermille SLrate;
    result = (*fdPlayerRate)->GetRate(fdPlayerRate, &SLrate);
    assert(SL_RESULT_SUCCESS == result);

    // enable whole file looping
    result = (*fdPlayerSeek)->SetLoop(fdPlayerSeek, SL_BOOLEAN_FALSE, 0, SL_TIME_UNKNOWN);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;

    return JNI_TRUE;
}

关键点是:

result = (*fdPlayerRate)->SetRate(fdPlayerRate, playbackMaxRate);
assert(SL_RESULT_SUCCESS == result);

我尝试在playbackMaxRate和playbackMinRate之间设置值(在我的S3手机上,playbackMaxRate是2000,playbackMinRate是500)。但没有效果,android NDK doc说它支持SL_IID_PLAYBACKRATE。 我的代码有什么问题吗? 非常感谢。

1 个答案:

答案 0 :(得分:2)

您可以尝试将当前速率属性约束设置为SL_RATEPROP_PITCHCORAUDIO。默认音频属性为SL_RATEPROP_NOPITCHCORAUDIO。像这样:

SLuint32 capa;
result = (*fdPlayerRate)->GetRateRange(fdPlayerRate, 0,
            &playbackMinRate, &playbackMaxRate, &playbackRateStepSize, &capa);
assert(SL_RESULT_SUCCESS == result);

result = (*fdPlayerRate)->SetPropertyConstraints(fdPlayerRate,
                    SL_RATEPROP_PITCHCORAUDIO);

if (SL_RESULT_PARAMETER_INVALID == result) {
    LOGD("Parameter Invalid");
}
if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
    LOGD("Feature Unsupported");
}
if (SL_RESULT_SUCCESS == result) {
    assert(SL_RESULT_SUCCESS == result);
    LOGD("Success");
}

result = (*fdPlayerRate)->SetRate(fdPlayerRate, playbackMaxRate);
assert(SL_RESULT_SUCCESS == result);

这可能因平台版本和实施而异。它适用于我的Moto G.希望这会有所帮助。