[Cmake-Android音视频]OpenSLES音频播放

[Cmake-Android]音视频总结:

 

OpenSL ES 介绍

OpenSL ES 是一个针对嵌入式系统的开放硬件音频加速库,也可以将其视为一套针对嵌入式平台的音频标准,全称为: Open Sound Library for Embedded Systems ,它提供了一套高性能、 低延迟的音频功能实现方法,并且实现了软硬件音频性能的跨平台部署,大大降低了上层处理音频应用的开发难度。

在 Android 开发中,Google 官方从 Android 2.3 (API 9)开始,便支持了 OpenSL ES 标准 ,并且对其进行了扩展。本文介绍的 OpenSL ES 是针对 Android NDK 开发。

OpenSL ES 播放声音流程

代码实现:

在cmake文件中引入opensl es的库

target_link_libraries( # Specifies the target library.
        native-lib
        OpenSLES
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})
#include <jni.h>
#include <string>
#include <android/log.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

#define LOGTAG "native-lib"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOGTAG, __VA_ARGS__)

static SLObjectItf engineSL= NULL;
SLEngineItf CreateSL()
{
    SLresult re;
    SLEngineItf en;
    re = slCreateEngine(&engineSL, 0, 0, 0, 0, 0);
    if (re != SL_RESULT_SUCCESS) return NULL;
    re = (*engineSL)->Realize(engineSL, SL_BOOLEAN_FALSE);
    if (re != SL_RESULT_SUCCESS) return NULL;
    re = (*engineSL)->GetInterface(engineSL, SL_IID_ENGINE, &en);
    if (re != SL_RESULT_SUCCESS) return NULL;
    return en;

}

//回调
void pcmCall(SLAndroidSimpleBufferQueueItf bf, void *content)
{
    LOGI(" pcmCall");
    static FILE *fp = NULL;
    static char *buf = NULL;

    if (!buf)
    {
        buf = new char[1024*1024];
    }

    if (!fp)
    {
        fp = fopen("/sdcard/output.pcm", "rb");
    }

    if (!fp) return;;
    if (feof(fp) == 0)
    {
        int len = fread(buf, 1, 1024, fp);
        if (len > 0)
        {
            (*bf)->Enqueue(bf, buf, len);
        }
    }
}


extern "C" JNIEXPORT jstring JNICALL
Java_lucas_testopensl_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";

    //1创建引擎
    SLEngineItf eng = CreateSL();
    if (eng)
    {
        LOGI("CreateSL success") ;
    } else{
        LOGI("CreateSL success");
    }

    //2.创建混音器
    SLObjectItf mix = NULL;
    SLresult re = 0;
    re = (*eng)->CreateOutputMix(eng, &mix, 0, 0, 0);
    if (re != SL_RESULT_SUCCESS)
    {
        LOGI("CreateOutputMix failed");
    }

    re = (*mix)->Realize(mix, SL_BOOLEAN_FALSE);
    if (re != SL_RESULT_SUCCESS)
    {
        LOGI("mix Realize failed");
    }

    SLDataLocator_OutputMix out_mix = {SL_DATALOCATOR_OUTPUTMIX, mix};
    SLDataSink audioSink = {&out_mix, 0};

    //3配置音频信息
    //缓冲队列
    SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 10};

    //音频格式
    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 dataSource = {&que, &pcm};

    //4创建播放器
    SLObjectItf player = NULL;
    SLPlayItf iplayer = NULL;
    SLAndroidSimpleBufferQueueItf pcmQue = NULL;
    const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[] = {SL_BOOLEAN_TRUE};
    re = (*eng)->CreateAudioPlayer(eng, &player, &dataSource, &audioSink, sizeof(ids)/sizeof(SLInterfaceID), ids, req);
    if (re != SL_RESULT_SUCCESS)
    {
        LOGI("CreateAudioPlayer failed");
    } else{
        LOGI("CreateAudioPlayer success");
    }

    (*player)->Realize(player, SL_BOOLEAN_FALSE);

    //获取player接口
    re = (*player)->GetInterface(player, SL_IID_PLAY, &iplayer);
    if (re != SL_RESULT_SUCCESS)
    {
        LOGI("GetInterface SL_IID_PLAY failed");
    }else{
        LOGI("GetInterface SL_IID_PLAY success");
    }

    //获取buffer队列接口
    re = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &pcmQue);
    if (re != SL_RESULT_SUCCESS)
    {
        LOGI("GetInterface SL_IID_BUFFERQUEUE failed");
    }else{
        LOGI("GetInterface SL_IID_BUFFERQUEUE success");
    }

    //设置回调函数   在播放队列为空的时候调用  第一次必须先放点数据进去
    (*pcmQue)->RegisterCallback(pcmQue, pcmCall, 0);

    //设置为播放状态
    (*iplayer)->SetPlayState(iplayer, SL_PLAYSTATE_PLAYING);

    //启动队列回调
    (*pcmQue)->Enqueue(pcmQue, "", 1);

    return env->NewStringUTF(hello.c_str());
}

猜你喜欢

转载自blog.csdn.net/adolph_lu/article/details/93349809