|
|
|
@ -17,29 +17,28 @@ |
|
|
|
|
|
|
|
|
|
#define TAG "OpenSLPlayer" |
|
|
|
|
|
|
|
|
|
//引擎接口
|
|
|
|
|
//object of engine
|
|
|
|
|
SLObjectItf engineObject = NULL; |
|
|
|
|
SLEngineItf engineEngine; |
|
|
|
|
|
|
|
|
|
//输出混音器接口
|
|
|
|
|
//object of mixer
|
|
|
|
|
SLObjectItf outputMixObject = NULL; |
|
|
|
|
SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL; |
|
|
|
|
|
|
|
|
|
//缓冲播放器接口
|
|
|
|
|
//object of buffer
|
|
|
|
|
SLObjectItf bqPlayerObject = NULL; |
|
|
|
|
SLPlayItf bqPlayerPlay; |
|
|
|
|
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; |
|
|
|
|
SLEffectSendItf bqPlayerEffectSend; |
|
|
|
|
SLVolumeItf bqPlayerVolume; |
|
|
|
|
|
|
|
|
|
//音效设置
|
|
|
|
|
//audio effect
|
|
|
|
|
const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; |
|
|
|
|
void *buffer; |
|
|
|
|
size_t bufferSize; |
|
|
|
|
uint8_t *outputBuffer; |
|
|
|
|
size_t outputBufferSize; |
|
|
|
|
|
|
|
|
|
//FFmpeg相关
|
|
|
|
|
AVPacket packet; |
|
|
|
|
int audioStream; |
|
|
|
|
AVFrame *aFrame; |
|
|
|
@ -48,48 +47,40 @@ AVFormatContext *aFormatCtx; |
|
|
|
|
AVCodecContext *aCodecCtx; |
|
|
|
|
int frame_count = 0; |
|
|
|
|
|
|
|
|
|
int createAudioPlayer(int *rate, int *channel, const char *file_name) ; |
|
|
|
|
int createAudioPlayer(int *rate, int *channel, const char *file_name); |
|
|
|
|
|
|
|
|
|
// 释放相关资源
|
|
|
|
|
int releaseAudioPlayer(); |
|
|
|
|
|
|
|
|
|
// 获取PCM数据, 自动回调获取
|
|
|
|
|
int getPCM(void **pcm, size_t *pcmSize) ; |
|
|
|
|
int getPCM(void **pcm, size_t *pcmSize); |
|
|
|
|
|
|
|
|
|
//播放回调方法
|
|
|
|
|
//callback by player
|
|
|
|
|
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bufferQueueItf, void *context) { |
|
|
|
|
bufferSize = 0; |
|
|
|
|
getPCM(&buffer, &bufferSize); |
|
|
|
|
//如果buffer不为空,入待播放队列
|
|
|
|
|
if (NULL != buffer && 0 != bufferSize) { |
|
|
|
|
SLresult result; |
|
|
|
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer, bufferSize); |
|
|
|
|
if(result < 0){ |
|
|
|
|
if (result < 0) { |
|
|
|
|
LOGE(TAG, "Enqueue error..."); |
|
|
|
|
} else{ |
|
|
|
|
} else { |
|
|
|
|
LOGI(TAG, "decode frame count=%d", frame_count++); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//创建OpenSLES引擎
|
|
|
|
|
//create the engine of OpenSLES
|
|
|
|
|
void createEngine() { |
|
|
|
|
SLresult result; |
|
|
|
|
//创建引擎
|
|
|
|
|
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); |
|
|
|
|
LOGI(TAG, "slCreateEngine=%d", result); |
|
|
|
|
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); |
|
|
|
|
LOGI(TAG, "engineObject->Realize=%d", result); |
|
|
|
|
//获取引擎接口
|
|
|
|
|
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); |
|
|
|
|
LOGI(TAG, "engineObject->GetInterface=%d", result); |
|
|
|
|
//创建输出混音器
|
|
|
|
|
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0); |
|
|
|
|
LOGI(TAG, "CreateOutputMix=%d", result); |
|
|
|
|
//关联输出混音器
|
|
|
|
|
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); |
|
|
|
|
LOGI(TAG, "outputMixObject->Realize=%d", result); |
|
|
|
|
//获取reverb接口
|
|
|
|
|
result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, |
|
|
|
|
&outputMixEnvironmentalReverb); |
|
|
|
|
LOGI(TAG, "outputMixObject->GetInterface=%d", result); |
|
|
|
@ -101,12 +92,12 @@ void createEngine() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//创建带有缓冲队列的音频播放器
|
|
|
|
|
void createBufferQueueAudioPlayer(int rate, int channel, int bitsPerSample) { |
|
|
|
|
SLresult result; |
|
|
|
|
|
|
|
|
|
//配置音频源
|
|
|
|
|
SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; |
|
|
|
|
//config audio source
|
|
|
|
|
SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, |
|
|
|
|
2}; |
|
|
|
|
SLDataFormat_PCM format_pcm; |
|
|
|
|
format_pcm.formatType = SL_DATAFORMAT_PCM; |
|
|
|
|
format_pcm.numChannels = (SLuint32) channel; |
|
|
|
@ -120,66 +111,54 @@ void createBufferQueueAudioPlayer(int rate, int channel, int bitsPerSample) { |
|
|
|
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; |
|
|
|
|
SLDataSource audioSrc = {&buffer_queue, &format_pcm}; |
|
|
|
|
|
|
|
|
|
//配置音频池
|
|
|
|
|
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; |
|
|
|
|
SLDataSink audioSnk = {&loc_outmix, NULL}; |
|
|
|
|
|
|
|
|
|
//创建音频播放器
|
|
|
|
|
const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME}; |
|
|
|
|
const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; |
|
|
|
|
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, |
|
|
|
|
3, ids, req); |
|
|
|
|
LOGI(TAG, "CreateAudioPlayer=%d", result); |
|
|
|
|
|
|
|
|
|
//关联播放器
|
|
|
|
|
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); |
|
|
|
|
LOGI(TAG, "bqPlayerObject Realize=%d", result); |
|
|
|
|
|
|
|
|
|
//获取播放接口
|
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); |
|
|
|
|
LOGI(TAG, "GetInterface bqPlayerPlay=%d", result); |
|
|
|
|
|
|
|
|
|
//获取缓冲队列接口
|
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, |
|
|
|
|
&bqPlayerBufferQueue); |
|
|
|
|
LOGI(TAG, "GetInterface bqPlayerBufferQueue=%d", result); |
|
|
|
|
|
|
|
|
|
//注册缓冲队列回调
|
|
|
|
|
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); |
|
|
|
|
LOGI(TAG, "RegisterCallback=%d", result); |
|
|
|
|
|
|
|
|
|
//获取音效接口
|
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, |
|
|
|
|
&bqPlayerEffectSend); |
|
|
|
|
LOGI(TAG, "GetInterface effect=%d", result); |
|
|
|
|
|
|
|
|
|
//获取音量接口
|
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); |
|
|
|
|
LOGI(TAG, "GetInterface volume=%d", result); |
|
|
|
|
|
|
|
|
|
//开始播放音乐
|
|
|
|
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); |
|
|
|
|
LOGI(TAG, "SetPlayState=%d", result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int createAudioPlayer(int *rate, int *channel, const char *file_name) { |
|
|
|
|
//注册相关组件
|
|
|
|
|
|
|
|
|
|
av_register_all(); |
|
|
|
|
aFormatCtx = avformat_alloc_context(); |
|
|
|
|
|
|
|
|
|
//打开音频文件
|
|
|
|
|
if (avformat_open_input(&aFormatCtx, file_name, NULL, NULL) != 0) { |
|
|
|
|
LOGE(TAG, "Couldn't open file:%s\n", file_name); |
|
|
|
|
return -1; // Couldn't open file
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//寻找stream信息
|
|
|
|
|
if (avformat_find_stream_info(aFormatCtx, NULL) < 0) { |
|
|
|
|
LOGE(TAG, "Couldn't find stream information."); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//寻找音频stream
|
|
|
|
|
int i; |
|
|
|
|
audioStream = -1; |
|
|
|
|
for (i = 0; i < aFormatCtx->nb_streams; i++) { |
|
|
|
@ -192,21 +171,18 @@ int createAudioPlayer(int *rate, int *channel, const char *file_name) { |
|
|
|
|
LOGE(TAG, "Couldn't find audio stream!"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
//获取解码器context
|
|
|
|
|
|
|
|
|
|
aCodecCtx = aFormatCtx->streams[audioStream]->codec; |
|
|
|
|
//寻找音频解码器
|
|
|
|
|
AVCodec *aCodec = avcodec_find_decoder(aCodecCtx->codec_id); |
|
|
|
|
if (!aCodec) { |
|
|
|
|
fprintf(stderr, "Unsupported codec!\n"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
//打开解码器
|
|
|
|
|
if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0) { |
|
|
|
|
LOGE(TAG, "Could not open codec."); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
aFrame = av_frame_alloc(); |
|
|
|
|
// 设置格式转换
|
|
|
|
|
swr = swr_alloc(); |
|
|
|
|
av_opt_set_int(swr, "in_channel_layout", aCodecCtx->channel_layout, 0); |
|
|
|
|
av_opt_set_int(swr, "out_channel_layout", aCodecCtx->channel_layout, 0); |
|
|
|
@ -216,40 +192,35 @@ int createAudioPlayer(int *rate, int *channel, const char *file_name) { |
|
|
|
|
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); |
|
|
|
|
swr_init(swr); |
|
|
|
|
|
|
|
|
|
// 分配PCM数据缓存
|
|
|
|
|
outputBufferSize = 8196; |
|
|
|
|
outputBuffer = (uint8_t *) malloc(sizeof(uint8_t) * outputBufferSize); |
|
|
|
|
// 返回sample rate和channels
|
|
|
|
|
*rate = aCodecCtx->sample_rate; |
|
|
|
|
*channel = aCodecCtx->channels; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取PCM数据, 自动回调获取
|
|
|
|
|
int getPCM(void **pcm, size_t *pcmSize) { |
|
|
|
|
while (av_read_frame(aFormatCtx, &packet) >= 0) { |
|
|
|
|
int frameFinished = 0; |
|
|
|
|
//音频流
|
|
|
|
|
//is audio stream
|
|
|
|
|
if (packet.stream_index == audioStream) { |
|
|
|
|
avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet); |
|
|
|
|
//解码完一帧数据
|
|
|
|
|
//decode success
|
|
|
|
|
if (frameFinished) { |
|
|
|
|
// data_size为音频数据所占的字节数
|
|
|
|
|
int data_size = av_samples_get_buffer_size( |
|
|
|
|
aFrame->linesize, aCodecCtx->channels, |
|
|
|
|
aFrame->nb_samples, aCodecCtx->sample_fmt, 1); |
|
|
|
|
|
|
|
|
|
if (data_size > outputBufferSize) { |
|
|
|
|
outputBufferSize = (size_t) data_size; |
|
|
|
|
outputBuffer = (uint8_t *) realloc(outputBuffer, sizeof(uint8_t) * outputBufferSize); |
|
|
|
|
outputBuffer = (uint8_t *) realloc(outputBuffer, |
|
|
|
|
sizeof(uint8_t) * outputBufferSize); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 音频格式转换
|
|
|
|
|
swr_convert(swr, &outputBuffer, aFrame->nb_samples, |
|
|
|
|
(uint8_t const **) (aFrame->extended_data), |
|
|
|
|
aFrame->nb_samples); |
|
|
|
|
|
|
|
|
|
// 返回pcm数据
|
|
|
|
|
*pcm = outputBuffer; |
|
|
|
|
*pcmSize = (size_t) data_size; |
|
|
|
|
return 0; |
|
|
|
@ -259,7 +230,6 @@ int getPCM(void **pcm, size_t *pcmSize) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 释放相关资源
|
|
|
|
|
int releaseAudioPlayer() { |
|
|
|
|
av_packet_unref(&packet); |
|
|
|
|
av_free(outputBuffer); |
|
|
|
@ -275,20 +245,12 @@ AUDIO_PLAYER_FUNC(void, playAudio, jstring filePath) { |
|
|
|
|
const char *file_name = (*env)->GetStringUTFChars(env, filePath, NULL); |
|
|
|
|
LOGI(TAG, "file_name=%s", file_name); |
|
|
|
|
|
|
|
|
|
// 创建音频解码器
|
|
|
|
|
createAudioPlayer(&rate, &channel, file_name); |
|
|
|
|
|
|
|
|
|
// 创建播放引擎
|
|
|
|
|
createEngine(); |
|
|
|
|
|
|
|
|
|
// 创建缓冲队列音频播放器
|
|
|
|
|
createBufferQueueAudioPlayer(rate, channel, SL_PCMSAMPLEFORMAT_FIXED_16); |
|
|
|
|
|
|
|
|
|
// 启动音频播放
|
|
|
|
|
bqPlayerCallback(bqPlayerBufferQueue, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//停止播放,释放相关资源
|
|
|
|
|
AUDIO_PLAYER_FUNC(void, stop) { |
|
|
|
|
if (bqPlayerObject != NULL) { |
|
|
|
|
(*bqPlayerObject)->Destroy(bqPlayerObject); |
|
|
|
@ -311,6 +273,5 @@ AUDIO_PLAYER_FUNC(void, stop) { |
|
|
|
|
engineEngine = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 释放解码器相关资源
|
|
|
|
|
releaseAudioPlayer(); |
|
|
|
|
} |
|
|
|
|