美文网首页使用FFMpeg 模仿Android MediaPlayer
播放器基础--OpenSL ES音频播放

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

作者: llm_5243 | 来源:发表于2020-06-20 16:10 被阅读0次

    介绍

    官网

    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 头文件 <SLES/OpenSLES.h> 和 <SLES/OpenSLES_Platform.h> 允许音频输入和输出。<SLES/OpenSLES_Android.h> 和 <SLES/OpenSLES_AndroidConfiguration.h> 中提供了其他 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;
    
    • 基本流程


      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<AudioChannel *>(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音频播放

        本文链接:https://www.haomeiwen.com/subject/idqbxktx.html