/*
*
* The WAV file is decoded using transcode-1.1.7 and then played using OpenSL ES
*
*/
Variables and structures used
WAV wav;//wav file PointerSLOBJECTITF Engineobject;//Engine ObjectSLENGINEITF Engineinterface;//Engine interfaceSLOBJECTITF Outputmixobject;//MixerSLOBJECTITF Audioplayerobject;//Player ObjectSLANDROIDSIMPLEBUFFERQUEUEITF ANDIOPLAYERBUFFERQUEUEITF;//Buffer Queue InterfaceSLPLAYITF Audioplayinterface;//Play InterfaceUnsignedChar*buffer;//Buffersize_t buffersize;//Buffer size//Contextstructplayercontext{wav wav; UnsignedChar*buffer; size_t buffersize; Playercontext (WAV wav, unsignedChar*buffer, size_t buffersize) { This->wav = wav; This->buffer = buffer; This->buffersize = buffersize; }};//Implementation ObjectvoidRealizeobject (SLOBJECTITFObject){//non-asynchronous (blocking)(*Object)->realize (Object, sl_boolean_false);}
Specific implementation process: 1. Open file
WAV wav = OpenWaveFile(env,jFileName);
*env,jstring jFileName){ *cFileName = env->GetStringUTFChars(jFileName,JNI_FALSE); WAVError err; WAV wav = wav_open(cFileName,WAV_READ,&err); LOGI("%d",wav_get_bitrate(wav)); env->ReleaseStringUTFChars(jFileName,cFileName); if0){ LOGE("%s",wav_strerror(err)); } return wav;}
2. Create the OpenSL es engine
//OpenSL ES在Android平台下默认是线程安全的,这样设置是为了为了兼容其他平台 SLEngineOption options[] = { {(SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE} }; slCreateEngine(&engineObject,ARRAY_LEN(engineObject),options,0,0,0//没有接口//实例化对象 //对象创建之后,处于未实例化状态,对象虽然存在但未分配任何资源,使用前先实例化(使用完之后destroy) RealizeObject(engineObject);
3. Get the Engine interface
(*engineObject)->GetInterface(engineObject,SL_IID_ENGINE,&engineInterface);
4. Create an output mixer
(*engineInterface)->CreateOutputMix(engineInterface,&outputMixObject,0,0,0)//没有接口 //实例化混音器 RealizeObject(outputMixObject);
5. Create a buffer to save the read to the audio database
//缓冲区的大小 bufferSize = wav_get_channels(wav) * wav_get_rate(wav) * wav_get_bits(wav); newunsignedchar[bufferSize];
6. Create an audio player with a buffer queue
CreateBufferQueueAudioPlayer(wav,engineInterface,outputMixObject,audioPlayerObject); //实例化音频播放器 RealizeObject(audioPlayerObject);
CreateBufferQueueAudioPlayer.cpp
extern"C"{#include "wavlib.h"}#include <SLES/OpenSLES.h>#include <SLES/OpenSLES_Android.h>#include <android/log.h>#define Array_len (a) (sizeof (a)/sizeof (a[0))//Create an audio playback objectvoidCreatebufferqueueaudioplayer (WAVWAV, SLENGINEITF engineengine, SLOBJECTITF outputmixobject, SLOBJECTITF &audioplayerobject) {//Android Simple buffer queue locator for data sourcesSldatalocator_androidsimplebufferqueue Datasourcelocator = {Sl_datalocator_androidsimplebufferqueue,//Locator type 1 //Number of buffers};//PCM data source formatSLDATAFORMAT_PCM Datasourceformat = {SL_DATAFORMAT_PCM,//format typeWav_get_channels (WAV),//Number of channelsWav_get_rate (WAV) * +,number of samples per//Hz/secWav_get_bits (WAV),//Number of bits per sampleWav_get_bits (WAV),//Container sizeSl_speaker_front_center,//Channel Shield Sl_byteorder_littleendian//byte order};//Data source is a simple buffer queue that contains the PCM formatSldatasource DataSource = {&datasourcelocator,//Data Locator&datasourceformat//Data format};//output hybrid locator for data receiversSldatalocator_outputmix Datasinklocator = {Sl_datalocator_outputmix,//Locator typeOutputmixobject//Output Mix};//Data locator is an output mixSldatasink Datasink = {&datasinklocator,//Locator 0 //Format};//Required InterfaceSlinterfaceid interfaceids[] = {Sl_iid_bufferqueue};//Required interface, if the required interface is not used, the request will failSlboolean requiredinterfaces[] = {sl_boolean_true//For Sl_iid_bufferqueue};//Create an audio player objectSlresult result = (*engineengine)->createaudioplayer (Engineengine, &audioplayerobject, &datasource, &datasink, Array_len (interfaceids), Interfaceids, R equiredinterfaces);}
7. Get the buffer queue interface buffer Interface
//通过缓冲区队列接口对缓冲区进行排序播放 (*audioPlayerObject)->GetInterface(audioPlayerObject,SL_IID_BUFFERQUEUE,&andioPlayerBufferQueueItf);
8. Register the audio player callback function
//当播放器完成对前一个缓冲区队列的播放时,回调函数会被调用,然后我们又继续读取音频数据,直到结束 //上下文,包裹参数方便再回调函数中使用 new PlayerContext(wav,buffer,bufferSize); (*andioPlayerBufferQueueItf)->RegisterCallback(andioPlayerBufferQueueItf,PlayerCallBack,ctx);
//callback functionvoidPlayercallback (SLANDROIDSIMPLEBUFFERQUEUEITF Andioplayerbufferqueue,void *Context) {Playercontext*CTx=(Playercontext*) context;//Read Datassize_t readsize=Wav_read_data (CTX -Wav,ctx -Buffer,ctx -buffersize);if(0 <ReadSize) {(*Andioplayerbufferqueue) -Enqueue (Andioplayerbufferqueue,ctx -Buffer,readsize); }Else{//destroy ContextClosewavefile (CTX -WAV);//Close fileDelete CTX -Buffer//Release cache}}
9. Get play interface to start playing music by using the Setplaystate function
//一旦播放器被设置为播放状态,该音频播放器开始等待缓冲区排队就绪 (*audioPlayerObject)->GetInterface(audioPlayerObject,SL_IID_PLAY,&audioPlayInterface); //设置播放状态 (*audioPlayInterface)->SetPlayState(audioPlayInterface,SL_PLAYSTATE_PLAYING);
10. Start by making the first buffer queue
PlayerCallBack(andioPlayerBufferQueueItf,ctx);
Full code
#include "com_dongnaoedu_jasonaudioplayer_audioplayer.h"extern "C"{#include "wavlib.h"}#include <SLES/OpenSLES.h>#include <SLES/OpenSLES_Android.h>#include <android/log.h>#include "CreateBufferQueueAudioPlayer.cpp"#define Logi (FORMAT,...) __android_log_print (Android_log_info, "Jason", format,# #__VA_ARGS__);#define LOGE (FORMAT,...) __android_log_print (Android_log_error, "Jason", format,# #__VA_ARGS__);#define Array_len (a) (sizeof (a)/sizeof (a[0))WAV wav;//wav file PointerSLOBJECTITF Engineobject;//Engine ObjectSLENGINEITF Engineinterface;//Engine interfaceSLOBJECTITF Outputmixobject;//MixerSLOBJECTITF Audioplayerobject;//Player ObjectSLANDROIDSIMPLEBUFFERQUEUEITF ANDIOPLAYERBUFFERQUEUEITF;//Buffer Queue InterfaceSLPLAYITF Audioplayinterface;//Play Interfaceunsigned Char*buffer;//Buffersize_t buffersize;//Buffer size//Contextstructplayercontext{wav wav;unsigned Char*buffer; size_t buffersize; Playercontext (WAV wav,unsigned Char*buffer, size_t buffersize) { This->wav = wav; This->buffer = buffer; This->buffersize = buffersize; }};//Open FileWAV openwavefile (jnienv *env,jstring jfilename) {Const Char*cfilename = Env->getstringutfchars (Jfilename,jni_false); Waverror err; WAV wav = Wav_open (CFILENAME,WAV_READ,&ERR); Logi ("%d", Wav_get_bitrate (WAV)); Env->releasestringutfchars (Jfilename,cfilename);if(wav = =0) {LOGE ('%s ', Wav_strerror (err)); }returnWAV;}//Close filevoidClosewavefile (WAV wav) {wav_close (WAV);}//Implementation ObjectvoidRealizeobject (Slobjectitf object) {//non-asynchronous (blocking)(*object)->realize (object,sl_boolean_false);}//callback functionvoidPlayercallback (SLANDROIDSIMPLEBUFFERQUEUEITF Andioplayerbufferqueue,void*context) {playercontext* CTX = (playercontext*) context;//Read Datassize_t readsize = Wav_read_data (ctx->wav,ctx->buffer,ctx->buffersize);if(0< ReadSize) {(*andioplayerbufferqueue)->enqueue (andioplayerbufferqueue,ctx->buffer,readsize); }Else{//destroy ContextClosewavefile (ctx->wav);//Close file Deletectx->buffer;//Release cache}}jniexportvoidJnicall Java_com_dongnaoedu_jasonaudioplayer_audioplayer_play (jnienv *env, Jclass jthiz, jstring jFileName) {//1. Opening a fileWAV wav = openwavefile (env,jfilename);//2. Creating the OpenSL es engine //opensl es is thread-safe by default on Android, so it is set up to be compatible with other platformsSlengineoption options[] = {{(SLuint32) Sl_engineoption_threadsafe, (SLuint32) sl_boolean_true}}; Slcreateengine (&engineobject,array_len (engineobject), Options,0,0,0);//No interface //instanced objects after the object is created, it is in an destroy state, the object exists but no resources are assigned, and is instantiated before use (after use)Realizeobject (Engineobject);//3. Getting the engine interface(*engineobject)->getinterface (engineobject,sl_iid_engine,&engineinterface);//4. Creating an output mixer(*engineinterface)->createoutputmix (Engineinterface,&outputmixobject,0,0,0);//No interface //instancing mixerRealizeobject (Outputmixobject);//5. Creating a buffer to save the read to the audio database //size of bufferbuffersize = wav_get_channels (WAV) * WAV_GET_RATE (WAV) * wav_get_bits (WAV); Buffer =New unsigned Char[BufferSize];//6. Creating an audio player with a buffer queueCreatebufferqueueaudioplayer (Wav,engineinterface,outputmixobject,audioplayerobject);//Instantiate an audio playerRealizeobject (Audioplayerobject);//7. Getting the buffer queue interface buffer queues Interface //Sort buffers by Buffer queue interface to play(*audioplayerobject)->getinterface (AUDIOPLAYEROBJECT,SL_IID_BUFFERQUEUE,&ANDIOPLAYERBUFFERQUEUEITF);//8. Registering the audio player callback function //When the player finishes playing against the previous buffer queue, the callback function is called, and then we continue to read the audio data until the end //context, wrap parameters easy to use in callback functionPlayercontext *ctx =NewPlayercontext (wav,buffer,buffersize); (*ANDIOPLAYERBUFFERQUEUEITF)->registercallback (ANDIOPLAYERBUFFERQUEUEITF,PLAYERCALLBACK,CTX);//9. Get play interface to start playing music by setplaystate function //Once the player is set to play, the audio player begins to wait for the buffer to queue ready(*audioplayerobject)->getinterface (audioplayerobject,sl_iid_play,&audioplayinterface);//Set playback status(*audioplayinterface)->setplaystate (audioplayinterface,sl_playstate_playing);//10. Start by getting the first buffer enqueuedPlayercallback (ANDIOPLAYERBUFFERQUEUEITF,CTX);//Close file //closewavefile (WAV);}
Android Audio and Video learning 7th: decoding with OpenSL es