Android:如何使用OpenSL ES更改音乐的播放速度

我正在做一个音乐播放器,在这个音乐播放器里我需要改变速度(音乐的播放速度)而不改变音高。

我无法find任何原生的android类来这样做。 我尝试过SoundPool,但它不适用于大型音乐文件,而且它似乎也不适用于许多设备。 我也试过AudioTrack,但是再次没有运气。

现在我正在尝试使用OpenSL ES处理音乐的android NDKaudio示例。 现在我只想在这个例子中添加设置回放速度function。

任何人都可以告诉我如何添加更改播放速率function吗?

Solutions Collecting From Web of "Android:如何使用OpenSL ES更改音乐的播放速度"

我已经解决了我的问题。 这里是我的OpenSL ES完整的本地代码,如果有人需要这个:

#include <jni.h> #include<android/log.h> // LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog 넣어주세요 #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OSLESMediaPlayer", __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "OSLESMediaPlayer", __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "OSLESMediaPlayer", __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "OSLESMediaPlayer", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "OSLESMediaPlayer", __VA_ARGS__) // for native audio #include <SLES/OpenSLES.h> #include <SLES/OpenSLES_Android.h> #include <assert.h> #include <sys/types.h> // engine interfaces static SLObjectItf engineObject = NULL; static SLEngineItf engineEngine; // URI player interfaces static SLObjectItf uriPlayerObject = NULL; static SLPlayItf uriPlayerPlay; static SLSeekItf uriPlayerSeek; static SLPlaybackRateItf uriPlaybackRate; // output mix interfaces static SLObjectItf outputMixObject = NULL; // playback rate (default 1x:1000) static SLpermille playbackMinRate = 500; static SLpermille playbackMaxRate = 2000; static SLpermille playbackRateStepSize; //Pitch static SLPitchItf uriPlaybackPitch; static SLpermille playbackMinPitch = 500; static SLpermille playbackMaxPitch = 2000; // create the engine and output mix objects JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_createEngine( JNIEnv* env, jclass clazz) { SLresult result; // create engine LOGD("create engine"); result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); assert(SL_RESULT_SUCCESS == result); // realize the engine LOGD("realize the engine"); result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // get the engine interface, which is needed in order to create other objects LOGD("get the engine interface"); result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); assert(SL_RESULT_SUCCESS == result); // create output mix, with environmental reverb specified as a non-required interface LOGD("create output mix"); const SLInterfaceID ids[1] = {SL_IID_PLAYBACKRATE}; const SLboolean req[1] = {SL_BOOLEAN_FALSE}; result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req); assert(SL_RESULT_SUCCESS == result); // realize the output mix LOGD("realize the output mix"); result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); } JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_releaseEngine( JNIEnv* env, jclass clazz) { // destroy URI audio player object, and invalidate all associated interfaces if (uriPlayerObject != NULL) { (*uriPlayerObject)->Destroy(uriPlayerObject); uriPlayerObject = NULL; uriPlayerPlay = NULL; uriPlayerSeek = NULL; } // destroy output mix object, and invalidate all associated interfaces if (outputMixObject != NULL) { (*outputMixObject)->Destroy(outputMixObject); outputMixObject = NULL; } // destroy engine object, and invalidate all associated interfaces if (engineObject != NULL) { (*engineObject)->Destroy(engineObject); engineObject = NULL; engineEngine = NULL; } } /* void OnCompletion(JNIEnv* env, jclass clazz) { jclass cls = env->GetObjectClass(thiz); if (cls != NULL) { jmethodID mid = env->GetMethodID(cls, "OnCompletion", "()V"); if (mid != NULL) { env->CallVoidMethod(thiz, mid, 1234); } } }*/ void playStatusCallback(SLPlayItf play, void* context, SLuint32 event) { //LOGD("playStatusCallback"); } // create URI audio player JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_createAudioPlayer( JNIEnv* env, jclass clazz, jstring uri) { SLresult result; // convert Java string to UTF-8 const jbyte *utf8 = (*env)->GetStringUTFChars(env, uri, NULL); assert(NULL != utf8); // configure audio source // (requires the INTERNET permission depending on the uri parameter) SLDataLocator_URI loc_uri = { SL_DATALOCATOR_URI, (SLchar *) utf8 }; SLDataFormat_MIME format_mime = { SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED }; SLDataSource audioSrc = { &loc_uri, &format_mime }; // configure audio sink SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject }; SLDataSink audioSnk = { &loc_outmix, NULL }; // create audio player const SLInterfaceID ids[2] = { SL_IID_SEEK, SL_IID_PLAYBACKRATE }; const SLboolean req[2] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_TRUE }; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &uriPlayerObject, &audioSrc, &audioSnk, 2, ids, req); // note that an invalid URI is not detected here, but during prepare/prefetch on Android, // or possibly during Realize on other platforms assert(SL_RESULT_SUCCESS == result); // release the Java string and UTF-8 (*env)->ReleaseStringUTFChars(env, uri, utf8); // realize the player result = (*uriPlayerObject)->Realize(uriPlayerObject, SL_BOOLEAN_FALSE); // this will always succeed on Android, but we check result for portability to other platforms if (SL_RESULT_SUCCESS != result) { (*uriPlayerObject)->Destroy(uriPlayerObject); uriPlayerObject = NULL; return JNI_FALSE; } // get the play interface result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay); assert(SL_RESULT_SUCCESS == result); // get the seek interface result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_SEEK, &uriPlayerSeek); assert(SL_RESULT_SUCCESS == result); // get playback rate interface result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAYBACKRATE, &uriPlaybackRate); assert(SL_RESULT_SUCCESS == result); /* // get playback pitch interface result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PITCH, &uriPlaybackPitch); assert(SL_RESULT_SUCCESS == result);*/ // register callback function result = (*uriPlayerPlay)->RegisterCallback(uriPlayerPlay, playStatusCallback, 0); assert(SL_RESULT_SUCCESS == result); result = (*uriPlayerPlay)->SetCallbackEventsMask(uriPlayerPlay, SL_PLAYEVENT_HEADATEND); // head at end assert(SL_RESULT_SUCCESS == result); SLmillisecond msec; result = (*uriPlayerPlay)->GetDuration(uriPlayerPlay, &msec); assert(SL_RESULT_SUCCESS == result); // no loop result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, SL_BOOLEAN_TRUE, 0, msec); assert(SL_RESULT_SUCCESS == result); SLuint32 capa; result = (*uriPlaybackRate)->GetRateRange(uriPlaybackRate, 0, &playbackMinRate, &playbackMaxRate, &playbackRateStepSize, &capa); assert(SL_RESULT_SUCCESS == result); result = (*uriPlaybackRate)->SetPropertyConstraints(uriPlaybackRate, 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 = (*uriPlaybackPitch)->GetPitchCapabilities(uriPlaybackPitch, &playbackMinPitch, &playbackMaxPitch); assert(SL_RESULT_SUCCESS == result);*/ /* SLpermille minRate, maxRate, stepSize, rate = 1000; SLuint32 capa; (*uriPlaybackRate)->GetRateRange(uriPlaybackRate, 0, &minRate, &maxRate, &stepSize, &capa); (*uriPlaybackRate)->SetRate(uriPlaybackRate, minRate); */ return JNI_TRUE; } JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_releaseAudioPlayer( JNIEnv* env, jclass clazz) { // destroy URI audio player object, and invalidate all associated interfaces if (uriPlayerObject != NULL) { (*uriPlayerObject)->Destroy(uriPlayerObject); uriPlayerObject = NULL; uriPlayerPlay = NULL; uriPlayerSeek = NULL; uriPlaybackRate = NULL; } } void setPlayState(SLuint32 state) { SLresult result; // make sure the URI audio player was created if (NULL != uriPlayerPlay) { // set the player's state result = (*uriPlayerPlay)->SetPlayState(uriPlayerPlay, state); assert(SL_RESULT_SUCCESS == result); } } SLuint32 getPlayState() { SLresult result; // make sure the URI audio player was created if (NULL != uriPlayerPlay) { SLuint32 state; result = (*uriPlayerPlay)->GetPlayState(uriPlayerPlay, &state); assert(SL_RESULT_SUCCESS == result); return state; } return 0; } // play JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_play(JNIEnv* env, jclass clazz) { setPlayState(SL_PLAYSTATE_PLAYING); } // stop JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_stop(JNIEnv* env, jclass clazz) { setPlayState(SL_PLAYSTATE_STOPPED); } // pause JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_pause(JNIEnv* env, jclass clazz) { setPlayState(SL_PLAYSTATE_PAUSED); } // pause JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_isPlaying( JNIEnv* env, jclass clazz) { return (getPlayState() == SL_PLAYSTATE_PLAYING); } // set position JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_seekTo( JNIEnv* env, jclass clazz, jint position) { if (NULL != uriPlayerPlay) { //SLuint32 state = getPlayState(); //setPlayState(SL_PLAYSTATE_PAUSED); SLresult result; result = (*uriPlayerSeek)->SetPosition(uriPlayerSeek, position, SL_SEEKMODE_FAST); assert(SL_RESULT_SUCCESS == result); //setPlayState(state); } } // get duration JNIEXPORT jint Java_com_swssm_waveloop_audio_OSLESMediaPlayer_getDuration( JNIEnv* env, jclass clazz) { if (NULL != uriPlayerPlay) { SLresult result; SLmillisecond msec; result = (*uriPlayerPlay)->GetDuration(uriPlayerPlay, &msec); assert(SL_RESULT_SUCCESS == result); return msec; } return 0.0f; } // get current position JNIEXPORT jint Java_com_swssm_waveloop_audio_OSLESMediaPlayer_getPosition( JNIEnv* env, jclass clazz) { if (NULL != uriPlayerPlay) { SLresult result; SLmillisecond msec; result = (*uriPlayerPlay)->GetPosition(uriPlayerPlay, &msec); assert(SL_RESULT_SUCCESS == result); return msec; } return 0.0f; } //llllllllllllllllllll JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setPitch( JNIEnv* env, jclass clazz, jint rate) { if (NULL != uriPlaybackPitch) { SLresult result; result = (*uriPlaybackPitch)->SetPitch(uriPlaybackPitch, rate); assert(SL_RESULT_SUCCESS == result); } } JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setRate( JNIEnv* env, jclass clazz, jint rate) { if (NULL != uriPlaybackRate) { SLresult result; result = (*uriPlaybackRate)->SetRate(uriPlaybackRate, rate); assert(SL_RESULT_SUCCESS == result); } } JNIEXPORT jint Java_com_swssm_waveloop_audio_OSLESMediaPlayer_getRate( JNIEnv* env, jclass clazz) { if (NULL != uriPlaybackRate) { SLresult result; SLpermille rate; result = (*uriPlaybackRate)->GetRate(uriPlaybackRate, &rate); assert(SL_RESULT_SUCCESS == result); return rate; } return 0; } // create URI audio player JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setLoop( JNIEnv* env, jclass clazz, jint startPos, jint endPos) { SLresult result; result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, SL_BOOLEAN_TRUE, startPos, endPos); assert(SL_RESULT_SUCCESS == result); return JNI_TRUE; } // create URI audio player JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setNoLoop( JNIEnv* env, jclass clazz) { SLresult result; if (NULL != uriPlayerSeek) { // enable whole file looping result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN); assert(SL_RESULT_SUCCESS == result); } return JNI_TRUE; } 

只需使用ndk-build命令编译并使用它。 如果有人在改变球场方面取得成功,请告诉我解决scheme。

这里是android.mk文件

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := audio-tools LOCAL_SRC_FILES := OSLESMediaPlayer.c LOCAL_CFLAGS := -DHAVE_CONFIG_H -DFPM_ARM -ffast-math -O3 LOCAL_LDLIBS += -lOpenSLES -llog include $(BUILD_SHARED_LIBRARY) 

和Application.mk文件

 APP_STL := gnustl_static APP_CPPFLAGS += -fexceptions -frtti APP_ABI := armeabi armeabi-v7a 

而包装类,你可以直接在你的项目中使用它的function

 package com.swssm.waveloop.audio; public class OSLESMediaPlayer { public native void createEngine(); public native void releaseEngine(); public native boolean createAudioPlayer(String uri); public native void releaseAudioPlayer(); public native void play(); public native void stop(); public native void pause(); public native boolean isPlaying(); public native void seekTo(int position); public native int getDuration(); public native int getPosition(); public native void setPitch(int rate); public native void setRate(int rate); public native int getRate(); public native void setLoop( int startPos, int endPos ); public native void setNoLoop(); public interface OnCompletionListener { public void OnCompletion(); } private OnCompletionListener mCompletionListener; public void SetOnCompletionListener( OnCompletionListener listener ) { mCompletionListener = listener; } private void OnCompletion() { mCompletionListener.OnCompletion(); int position = getPosition(); int duration = getDuration(); if( position != duration ) { int a = 0; } else { int c = 0; } } } 

这可能有一些帮助(取自NDK OpenSL文档):

回放速度

支持的播放速率范围和function可能因平台版本和实现而异,因此应在运行时通过查询PlaybackRate :: GetRateRange或PlaybackRate :: GetCapabilitiesOfRate来确定。

也就是说,对于典型的速率范围的一些指导可能是有用的:在Android 2.3中,典型地支持从500每千米到2000每千米的单个回放速率范围,具有属性SL_RATEPROP_NOPITCHCORAUDIO。 在Android 4.0中,PCM格式的数据源通常支持相同的速率范围,而其他格式的统一速率范围则支持相同的速率范围。