播放器基础--OpenSL ES音频播放

介绍

官网

OpenSL ES (Open Sound Library for Embedded Systems)是针对嵌入式系统的一套无授权费,跨平台, 硬件加速的音频API。它提供了一套标准化,高性能,低延时的方法, 本地应用(C/C++)的开发者可以通过这套方对音频进行操作, 实现软/硬件音频性能的直接跨平台部署,降低执行难度,促进高级音频市场的发展

NDK 软件包中包括 Khronos Group 开发的 OpenSL ES™ 1.0.1 API 规范的 Android 专用实现。利用这个库,可以使用 C 或 C++ 实现高性能、低延迟的音频应用。

标准 OpenSL ES 头文件 允许音频输入和输出。 中提供了其他 Android 专用功能。

如何在Android中使用OpenSL ES

  • 在CMakeList.txt中添加OpenSL ES的引用
target_link_libraries( # Specifies the target library.
   
        OpenSLES

        )
  • 添加必要的头文件
    添加核心 OpenSL ES 功能集 OpenSLES.h
    添加 OpenSL ES [Android 扩展] OpenSLES_Android.h

代码示例

GitHub 页面提供了以下示例应用:

  • audio-echo 创建从输入到输出的往返循环。
  • native-audio 是一个简单的音频录制器/播放器。

Note that OpenSL ES is deprecated from Android 11, developers are recommended to use Oboe library instead.

OpenSL ES简单使用

  • 使用OpenSL相关API的通用步骤是:

1,创建对象(通过带有create的函数)
2,初始化(通过Realize函数)
3,获取接口来使用相关功能(通过GetInterface函数)

  • OpenSL使用回调机制来访问音频IO,回调方法仅仅是告诉我们:BufferQueue已经就绪,可以接受/获取数据了

  • OpenSL使用SLBufferQueueItf. Enqueue函数从(往)音频设备获取(放入)数据。

关于使用FFmpeg + opensl 实现Android播放器播放音频, 可以在回调函数里面获取解码后的音频数据,并调用Enqueue函数进行播放. 在开始播放的时候,需要手动启动回调机制,否则回调将不会被调用到。

  • 一个简单的音频播放大概需要以下的object:
   //引擎
    SLObjectItf engineObject = 0;
    //引擎接口
    SLEngineItf engineInterface = 0;
    //混音器
    SLObjectItf outputMixObject = 0;
    //播放器
    SLObjectItf bqPlayerObject = 0;
    //播放器接口
    SLPlayItf bqPlayerPlay = 0;
    //播放器队列接口
    SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = 0;
  • 基本流程


    播放器基础--OpenSL ES音频播放_第1张图片
    opensles.png

代码还在整理,先简单贴一下

void AudioChannel::audio_play() {
    /**
     * 1、创建引擎并获取引擎接口
     */
    SLresult result;
    // 1.1 创建引擎对象:SLObjectItf engineObject
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    // 1.2 初始化引擎
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    // 1.3 获取引擎接口 SLEngineItf engineInterface
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineInterface);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    /**
     * 2、设置混音器
     */
    // 2.1 创建混音器:SLObjectItf outputMixObject
    result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMixObject, 0,
                                                 0, 0);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    // 2.2 初始化混音器
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    /**
     * 3、创建播放器
     */
    //3.1 配置输入声音信息
    //创建buffer缓冲类型的队列 2个队列
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
                                                       2};
    //pcm数据格式
    //SL_DATAFORMAT_PCM:数据格式为pcm格式
    //2:双声道
    //SL_SAMPLINGRATE_44_1:采样率为44100
    //SL_PCMSAMPLEFORMAT_FIXED_16:采样格式为16bit
    //SL_PCMSAMPLEFORMAT_FIXED_16:数据大小为16bit
    //SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT:左右声道(双声道)
    //SL_BYTEORDER_LITTLEENDIAN:小端模式
    SLDataFormat_PCM format_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 audioSrc = {&loc_bufq, &format_pcm};

    //3.2 配置音轨(输出)
    //设置混音器
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};
    //需要的接口 操作队列的接口
    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};
    //3.3 创建播放器
    result = (*engineInterface)->CreateAudioPlayer(engineInterface, &bqPlayerObject, &audioSrc,
                                                   &audioSnk, 1, ids, req);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    //3.4 初始化播放器:SLObjectItf bqPlayerObject
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    //3.5 获取播放器接口:SLPlayItf bqPlayerPlay
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    if (SL_RESULT_SUCCESS != result) {
        return;
    }
    /**
     * 4、设置播放回调函数
     */
    //4.1 获取播放器队列接口:SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue
    (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue);

    //4.2 设置回调 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
    (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);

    /**
     * 5、设置播放器状态为播放状态
     */
    (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);

    /**
     * 6、手动激活回调函数
     */
    bqPlayerCallback(bqPlayerBufferQueue, this);
}
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
    AudioChannel *audioChannel = static_cast(context);
    int pcm_size = audioChannel->getPCM();
    if (pcm_size > 0) {
        (*bq)->Enqueue(bq, audioChannel->out_buffers, pcm_size);
    }
}

代码还在整理当中https://github.com/yizhongliu/FFMediaPlayer

官网
https://www.khronos.org/opensles/
https://developer.android.google.cn/ndk/guides/audio/opensl

参考
https://www.jianshu.com/p/2b8d2de9a47b
https://blog.csdn.net/Poisx/article/details/78336404

你可能感兴趣的:(播放器基础--OpenSL ES音频播放)