目录
[3.1 初始化OpenSL](#3.1 初始化OpenSL)
[3.2 设置播放回掉](#3.2 设置播放回掉)
[3.3 使用FFmpeg计算出转换后的样本数目](#3.3 使用FFmpeg计算出转换后的样本数目)
一、背景
FFmpeg不能够操作Android的硬件设备,所以要在Android系统上面播放音频的话需要另找办法
二、方案
Android 环境下音频播放通常有两种方式------ AudioTrack 和 OpenSLES。AudioTrack 本身是Java实现,另外一种实现方式就是OpenSL ES 播放音频。
三、代码实现
3.1 初始化OpenSL
void AudioChannel::initOpenSL() {
//创建引擎
SLresult result;
// 创建引擎engineObject
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 初始化引擎engineObject
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 获取引擎接口engineEngine
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE,
&engineInterface);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 创建混音器outputMixObject
result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMixObject, 0, 0, 0);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 初始化混音器outputMixObject
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return;
}
/**
* 配置输入声音信息
*/
//创建buffer缓冲类型的队列 2个队列
SLDataLocator_AndroidSimpleBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
2};
//pcm数据格式
SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_44_1, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN};
//数据源 将上述配置信息放到这个数据源中
SLDataSource slDataSource = {&android_queue, &pcm};
//设置混音器
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&outputMix, NULL};
//需要的接口
const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
//创建播放器
(*engineInterface)->CreateAudioPlayer(engineInterface, &bqPlayerObject, &slDataSource,
&audioSnk, 1,
ids, req);
//初始化播放器
(*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
// 得到接口后调用 获取Player接口
(*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerInterface);
// 获得播放器接口
(*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
//设置回调
(*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);
// 设置播放状态
(*bqPlayerInterface)->SetPlayState(bqPlayerInterface, SL_PLAYSTATE_PLAYING);
bqPlayerCallback(bqPlayerBufferQueue, this);
}
3.2 设置播放回掉
//第一次主动调用在调用线程
//之后在新线程中回调
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
AudioChannel *audioChannel = static_cast<AudioChannel *>(context);
int datalen = audioChannel->getPcm();
if (datalen > 0) {
(*bq)->Enqueue(bq, audioChannel->buffer, datalen);
}
}
3.3 使用FFmpeg计算出转换后的样本数目
uint64_t dst_nb_samples = av_rescale_rnd(
swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples,
out_sample_rate,
frame->sample_rate,
AV_ROUND_UP);
// 转换,返回值为转换后的sample个数
int nb = swr_convert(swr_ctx, &buffer, dst_nb_samples,
(const uint8_t **) frame->data, frame->nb_samples);
//转换后多少数据
data_size = nb * out_channels * out_samplesize;
//音频的时间
clock = frame->best_effort_timestamp * av_q2d(time_base);
if (javaCallHelper) {
javaCallHelper->onProgress(THREAD_CHILD, clock);
}