Android OpenSL介绍 并实现播放PCM功能

目录

  1. Android 万能音频播放器 一 C++多线程解码音频数据
  2. Android 万能音频播放器 二 C++队列存放AvPacket
  3. OpenSL介绍 并实现播放PCM功能

    前言

    简单来说OpenSL ES是一个嵌入式、跨平台、免费的、音频 处理库,本文旨在介绍OpenSL的使用方法和参数设置,绝大部分内容参考Android官方NDKdemo,地址为android NDK demo,想学NDK开发的伙伴可以去参考一下,受益良多。

    使用流程

    1、创建接口对象
    2、设置混音器
    3、创建播放器(录音器)
    4、设置缓冲队列和回调函数
    5、设置播放状态
    6、启动回调函数

    接口说明

    1、类接口:SLObjectItf
    通过SLObjectItf接口类我们可以创建所需要的各种类型的类接口,比如:
    创建引擎接口对象:SLObjectItf engineObject
    创建混音器接口对象:SLObjectItf outputMixObject
    创建播放器接口对象:SLObjectItf playerObject
    2、具体的接口类
    引擎:SLEngineItf
    播放器:SLPlayItf
    声音控制器:SLVolumeItf等等

    创建三部曲
    如:创建引擎接口对象( createrealizeget )

SLObjectItf engineObject = NULL;//用SLObjectItf声明引擎接口对象  
SLEngineItf engineEngine = NULL;//声明具体的引擎对象实例  
void createEngine()  
{  
    SLresult result;//返回结果  
    //第一步:创建引擎 
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);

    //第二步:实现(Realize)engineObject接口对象
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 

    //第三部:通过engineObject的GetInterface方法初始化engineEngine 
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

代码实现

#include 
#include 
#include 
#include 
#include "androidLog.h"
#include 
#include 

//引擎对象
SLObjectItf enginObject = NULL;
//引擎接口
SLEngineItf engineItf = NULL;

//混音器对象(混音器作用是做声音处理)
SLObjectItf outputmixObject = NULL;
//混音器环境接口
SLEnvironmentalReverbItf outputEnvironmentalReverbItf = NULL;
const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;

//播放器对象
SLObjectItf pcmPlayerObject = NULL;
//播放接口
SLPlayItf playItf = NULL;
//播放队列
SLAndroidSimpleBufferQueueItf simpleBufferQueueItf = NULL;


FILE *pcmFile = NULL;
uint8_t *outbuffer;
void* buffer;

//从pcm文件中读取数据
int getPCMbuffer(void** pcm){
    //读取到的字节数
    int size = 0;
    while (!feof(pcmFile)){
        size = fread(outbuffer,1,44100 * 2 * 2 / 2,pcmFile);
        if (outbuffer==NULL){
            LOGI("pcm文件读取完毕");
            break;
        } else{
            LOGI("pcm文件读取中");
        }
        *pcm = outbuffer;
        break;
    }
    return size;
}

void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf simpleBufferQueueItf1,void* data){
    int size = getPCMbuffer(&buffer);
    LOGI("pcm读取大小为:%d",size);

    if (buffer!=NULL){
        LOGI("放入播放队列");

        //放入播放队列
        (*simpleBufferQueueItf1)->Enqueue(simpleBufferQueueItf1,buffer,size);
    }
}


extern "C"
JNIEXPORT void JNICALL
Java_com_zhongcheng_opensl_MainActivity_playPCM(JNIEnv *env, jobject instance, jstring url_) {
    const char *url = env->GetStringUTFChars(url_, 0);

    SLresult result;
    pcmFile = fopen(url,"r");
    if (pcmFile==NULL){
        LOGI("文件不存在");

        return;
    }
    LOGI("文件存在");

    outbuffer = (uint8_t *) malloc(44100 * 2 * 2 / 2);

    //初始化引擎对象并由对象得到接口
    slCreateEngine(&enginObject, 0, 0, 0, 0, 0);
    (*enginObject)->Realize(enginObject, SL_BOOLEAN_FALSE);
    result = (*enginObject)->GetInterface(enginObject, SL_IID_ENGINE, &engineItf);
    if (SL_RESULT_SUCCESS!=result){
        LOGI("引擎接口创建失败!");
        return;
    }
    //需要做的声音处理功能数组
    const SLInterfaceID mid[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean mird[1] = {SL_BOOLEAN_FALSE};
    result = (*engineItf)->CreateOutputMix(engineItf, &outputmixObject,1,mid,mird);

    if (SL_RESULT_SUCCESS!=result){
        LOGI("混音器对象创建失败!");
        return;
    }

    //得到上面声明的处理功能的接口
    (*outputmixObject)->Realize(outputmixObject,SL_BOOLEAN_FALSE);
    result = (*outputmixObject)->GetInterface(outputmixObject,SL_IID_ENVIRONMENTALREVERB,&outputEnvironmentalReverbItf);
    if (SL_RESULT_SUCCESS!=result){
        LOGI("混音器接口创建失败!");
        return;
    }
    //混音器环境属性设置
    result = (*outputEnvironmentalReverbItf)->SetEnvironmentalReverbProperties(outputEnvironmentalReverbItf,&reverbSettings);

    if (SL_RESULT_SUCCESS!=result){
        LOGI("混音器参数设置失败!");
    }

    //播放队列
    SLDataLocator_AndroidBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
    SLDataFormat_PCM format_pcm = {
            SL_DATAFORMAT_PCM, //格式
            2,//声道数
            SL_SAMPLINGRATE_44_1,//采样率
            SL_PCMSAMPLEFORMAT_FIXED_16,//采样位数 一定要与播放的pcm的一样 要不然可能快也可能会慢
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_SPEAKER_FRONT_RIGHT|SL_SPEAKER_FRONT_LEFT,//声道布局 前右|前左
            SL_BYTEORDER_LITTLEENDIAN
    };
    //播放源
    SLDataSource dataSource = {&android_queue,&format_pcm};
    //混音器
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,outputmixObject};
    //关联混音器
    SLDataSink audiosnk = {&outputMix,NULL};
    //要实现的功能
    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};//队列播放
    const SLboolean irds[1] = {SL_BOOLEAN_FALSE};
    (*engineItf)->CreateAudioPlayer(engineItf,&pcmPlayerObject,&dataSource,&audiosnk,1,ids,irds);
    (*pcmPlayerObject)->Realize(pcmPlayerObject,SL_BOOLEAN_FALSE);
    //创建播放接口
    result = (*pcmPlayerObject)->GetInterface(pcmPlayerObject,SL_IID_PLAY,&playItf);

    if (SL_RESULT_SUCCESS!=result){
        LOGI("播放器接口创建失败!");
        return;
    }

    //得到Androidbufferqueue接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject,SL_IID_BUFFERQUEUE,&simpleBufferQueueItf);
    //注册回掉函数
    (*simpleBufferQueueItf)->RegisterCallback(simpleBufferQueueItf,pcmBufferCallBack,NULL);
    //设置播放状态
    (*playItf)->SetPlayState(playItf,SL_PLAYSTATE_PLAYING);

    //第一次手动调用回掉函数 开始播放
    pcmBufferCallBack(simpleBufferQueueItf,NULL);

    env->ReleaseStringUTFChars(url_, url);
}

你可能感兴趣的:(音视频,android,音视频开发)