Android: Cómo cambiar la velocidad de reproducción de música con OpenSL ES

Estoy trabajando en un reproductor de música en el que necesito cambiar el tempo (velocidad de reproducción de la música) sin cambiar el tono.

No puedo encontrar ninguna clase nativa de Android para hacerlo. Intenté SoundPool pero no funciona con archivos de música grandes y tampoco parece funcionar en muchos dispositivos. También probé AudioTrack, pero nuevamente no tuve suerte.

Ahora estoy probando el ejemplo de audio android NDK que usa OpenSL ES para manejar música. Ahora solo quiero agregar la función de velocidad de reproducción establecida en este ejemplo.

¿Alguien puede mostrarme cómo agrego cambiar la función de velocidad de reproducción en él?

He solucionado mi problema. Aquí está mi código nativo completo para OpenSL ES en caso de que alguien lo necesite:

#include  #include // 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  #include  #include  #include  // 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; } 

Simplemente compile usando el ndk-build y ndk-build . Si alguien tiene éxito en cambiar tono, por favor dígame la solución.

Aquí está el archivo 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) 

y archivo Application.mk

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

Y la clase contenedora, puede usar su función directamente en su proyecto

 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; } } } 

Esto puede ser de alguna ayuda (tomado de la documentación de NDK OpenSL):

Velocidad de reproducción

El (los) rango (s) de velocidad de reproducción admitidos y las capacidades pueden variar según la versión de la plataforma y la implementación, por lo que debe determinarse en tiempo de ejecución mediante consultas con PlaybackRate :: GetRateRange o PlaybackRate :: GetCapabilitiesOfRate.

Dicho esto, algunas orientaciones sobre los rangos de tasas típicos pueden ser útiles: en Android 2.3, por lo general, se admite un rango de velocidad de reproducción única de 500 por mil a 2000 por mil inclusive, con la propiedad SL_RATEPROP_NOPITCHCORAUDIO. En Android 4.0, por lo general, se admite el mismo rango de velocidad para una fuente de datos en formato PCM, y un rango de velocidad unitaria para otros formatos.