美文网首页
OpenSLES播放、录制、声道切换、音量控制

OpenSLES播放、录制、声道切换、音量控制

作者: 曾大稳丶 | 来源:发表于2018-06-25 16:17 被阅读0次
    1. OpenSLES(Open Sound Library for Embedded Systems)无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化, 高性能,低响应时间的音频功能实现方法,并实现软/硬件音频性能的直接跨平台部署,降低执行难度,促进高级音频市场的发展。

    2. Android里面ndk->platforms-> android-xx -> arch-xx ->usr->lib目录里面包含了ndk内置的so,可以看到支持了libOpenSLES.so

    3. githubgooglesamples/android-ndk可以看到ndk库的sample,里面native-audio目录就是OpenSLESsample

    1. OpenSLES播放主要步骤如下:
    1. 创建接口对象
    2. 设置混音器
    3. 创建播放器(录音器)
    4. 设置缓冲队列和回调函数
    5. 设置播放状态
    6. 启动回调函数
    7. 销毁

    4.1 创建接口对象

    
        // 引擎接口
        SLObjectItf engineObject = NULL;
        SLEngineItf engineEngine = NULL;
        
        // 创建引擎对象
         slCreateEngine(&engineObject,  0, NULL, 0, NULL, NULL);
         (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
         (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    
    
    

    4.2 设置混音器

    
        //混音器
        SLObjectItf outputMixObject = NULL;
        SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
        SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
        
        
        const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
        const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
        (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);
        (void)result;
        result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
        (void)result;
        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb);
        if (SL_RESULT_SUCCESS == result) {
            result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties( outputMixEnvironmentalReverb, &reverbSettings);
            (void)result;
        }
        
        SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    
    
    

    4.3 创建播放器

    
        //pcm
        SLObjectItf pcmPlayerObject = NULL;
        SLPlayItf pcmPlayerPlay = NULL;
        SLVolumeItf pcmPlayerVolume = NULL;
        
        
        SLDataLocator_AndroidSimpleBufferQueue android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
        SLDataFormat_PCM pcm={
                    SL_DATAFORMAT_PCM,//播放pcm格式的数据
                    2,//2个声道(立体声)
                    SL_SAMPLINGRATE_44_1,//44100hz的频率
                    SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
                    SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
                    SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右)
                    SL_BYTEORDER_LITTLEENDIAN//结束标志
         };
        
        SLDataSource slDataSource = {&android_queue, &pcm};
        SLDataSink audioSnk = {&outputMix, NULL};
       // SL_IID_BUFFERQUEUE:缓冲  SL_IID_VOLUME:音量  SL_IID_PLAYBACKRATE:微调功能 防止卡顿 微调功能 SL_IID_MUTESOLO:声道切换
        const SLInterfaceID ids[4] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_PLAYBACKRATE, SL_IID_MUTESOLO};
        const SLboolean req[4] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
        
         result = (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 3, ids, req);
            // 初始化播放器
        (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
        
            //得到接口后调用  获取Player接口
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    
    

    4.4 设置缓冲队列和回调函数

    
        //缓冲器队列接口
        SLAndroidSimpleBufferQueueItf pcmBufferQueue;
        void *buffer;
        uint8_t *out_buffer;
        
        void getPcmData(void **pcm){
            while(!feof(pcmFile))  {
                int size = static_cast<int>(fread(out_buffer,1,44100 * 2 * 2,pcmFile));
                if(out_buffer == NULL)  {
                    LOGI("%s  %d", "read end",size);
                    break;
                } else{
                    LOGI("%s  %d", "reading",size);
                }
                *pcm = out_buffer;
                break;
            }
        }
    
        void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void * context){
            //assert(NULL == context);
            getPcmData(&buffer);
            // for streaming playback, replace this test by logic to find and fill the next buffer
            if (NULL != buffer) {
                SLresult result;
                // enqueue another buffer
                result = (*pcmBufferQueue)->Enqueue(pcmBufferQueue, buffer, 44100 * 2 * 2);
                // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
                // which for this code example would indicate a programming error
            }
        }
    
    
        
    
        // 创建缓冲区和回调函数
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    
        //缓冲接口回调
        (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL);
        //获取音量接口
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume);
    
    
    

    4.5 设置播放状态

         (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    

    4.6 启动回调函数

         // 主动调用回调函数开始工作
        pcmBufferCallBack(pcmBufferQueue, NULL);
    
    

    4.7 销毁

        
    
         if (pcmPlayerObject != NULL) {
            (*pcmPlayerObject)->Destroy(pcmPlayerObject);
            pcmPlayerObject = NULL;
            pcmPlayerPlay = NULL;
            pcmBufferQueue = NULL;
            pcmPlayerVolume = NULL;
        }
        
        
        if (outputMixObject != NULL) {
            (*outputMixObject)->Destroy(outputMixObject);
            outputMixObject = NULL;
            outputMixEnvironmentalReverb = NULL;
        }
      
         if (engineObject != NULL) {
            (*engineObject)->Destroy(engineObject);
            engineObject = NULL;
            engineEngine = NULL;
        }
    
    

    示例代码如下:

    #include <jni.h>
    #include <string>
    
    
    extern "C"
    {
    #include <SLES/OpenSLES.h>
    #include <SLES/OpenSLES_Android.h>
    }
    
    #include <android/log.h>
    #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"zzw",FORMAT,##__VA_ARGS__);
    #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"zzw",FORMAT,##__VA_ARGS__);
    
    // 引擎接口
    SLObjectItf engineObject = NULL;
    SLEngineItf engineEngine = NULL;
    
    //混音器
    SLObjectItf outputMixObject = NULL;
    SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
    SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
    
    
    //pcm
    SLObjectItf pcmPlayerObject = NULL;
    SLPlayItf pcmPlayerPlay = NULL;
    SLVolumeItf pcmPlayerVolume = NULL;
    
    //缓冲器队列接口
    SLAndroidSimpleBufferQueueItf pcmBufferQueue;
    
    FILE *pcmFile;
    void *buffer;
    
    uint8_t *out_buffer;
    
    void getPcmData(void **pcm)
    {
        while(!feof(pcmFile))
        {
            int size = static_cast<int>(fread(out_buffer,1,44100 * 2 * 2,pcmFile));
            if(out_buffer == NULL)
            {
                LOGI("%s  %d", "read end",size);
                break;
            } else{
                LOGI("%s  %d", "reading",size);
            }
            *pcm = out_buffer;
            break;
        }
    }
    
    void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void * context)
    {
        //assert(NULL == context);
        getPcmData(&buffer);
        // for streaming playback, replace this test by logic to find and fill the next buffer
        if (NULL != buffer) {
            SLresult result;
            // enqueue another buffer
            result = (*pcmBufferQueue)->Enqueue(pcmBufferQueue, buffer, 44100 * 2 * 2);
            // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
            // which for this code example would indicate a programming error
        }
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_example_zzw_androidopenslaudio_MainActivity_palypcm(JNIEnv *env, jobject instance,
                                                                   jstring url_) {
        const char *url = env->GetStringUTFChars(url_, 0);
    
        // TODO
        //读取pcm文件
        pcmFile = fopen(url, "r");
        if(pcmFile == NULL)
        {
            LOGE("%s", "fopen file error");
            return;
        }
        out_buffer = (uint8_t *) malloc(44100 * 2 * 2);
    
    
        SLresult result;
        //第一步------------------------------------------
        // 创建引擎对象
        slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
        (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
        (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    
    
        //第二步-------------------------------------------
        // 创建混音器
        const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
        const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
        result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);
        (void)result;
        result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
        (void)result;
        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb);
        if (SL_RESULT_SUCCESS == result) {
            result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                    outputMixEnvironmentalReverb, &reverbSettings);
            (void)result;
        }
        SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    
        // 第三步--------------------------------------------
        // 创建播放器
        SLDataLocator_AndroidSimpleBufferQueue android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
        SLDataFormat_PCM pcm={
                SL_DATAFORMAT_PCM,//播放pcm格式的数据
                2,//2个声道(立体声)
                SL_SAMPLINGRATE_44_1,//44100hz的频率
                SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
                SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
                SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右)
                SL_BYTEORDER_LITTLEENDIAN//结束标志
        };
    
        SLDataSource slDataSource = {&android_queue, &pcm};
        SLDataSink audioSnk = {&outputMix, NULL};
        
        // SL_IID_BUFFERQUEUE:缓冲  SL_IID_VOLUME:音量  SL_IID_PLAYBACKRATE:微调功能 防止卡顿 微调功能 SL_IID_MUTESOLO:声道切换
        const SLInterfaceID ids[4] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_PLAYBACKRATE, SL_IID_MUTESOLO};
        const SLboolean req[4] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    
        result = (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 3, ids, req);
        // 初始化播放器
        (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
    
        //得到接口后调用  获取Player接口
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    
        //第四步---------------------------------------
        // 创建缓冲区和回调函数
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    
        //缓冲接口回调
        (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL);
        //获取音量接口
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume);
    
        //第五步----------------------------------------
        // 设置播放状态
        (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    
    
        //第六步----------------------------------------
        // 主动调用回调函数开始工作
        pcmBufferCallBack(pcmBufferQueue, NULL);
    
        env->ReleaseStringUTFChars(url_, url);
    }
    
    
    1. 暂停、继续、停止
      使用播放控制接口 SLPlayItf
        //暂停
        if (pcmPlayerPlay != NULL) {
            (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PAUSED);
        }
        //继续
        if (pcmPlayerPlay != NULL) {
            (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
        }
        //停止
        if (pcmPlayerPlay != NULL) {
            (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_STOPPED);
        }
    
    
    1. 音量控制
      使用音量控制接口 SLVolumeItf
    //初始化
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject,SL_IID_VOLUME,&pcmPlayerVolume);
    //设置音量
    (*pcmPlayerVolume)->SetVolumeLevel(pcmPlayerVolume, (100 - percent) * -50);
    
    

    可用示例

    void WlAudio::setVolume(int percent) {
        volumePercent = percent;
        if(pcmVolumePlay != NULL)
        {
            if(percent > 30)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -20);
            }
            else if(percent > 25)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -22);
            }
            else if(percent > 20)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -25);
            }
            else if(percent > 15)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -28);
            }
            else if(percent > 10)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -30);
            }
            else if(percent > 5)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -34);
            }
            else if(percent > 3)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -37);
            }
            else if(percent > 0)
            {
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -40);
            }
            else{
                (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, (100 - percent) * -100);
            }
        }
    }
    
    1. 声道控制

    采用声道控制接口SLMuteSoloItf接口

        SLMuteSoloItf  pcmMutePlay = NULL;
    
      //初始化
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_MUTESOLO, &pcmMutePlay);
        
      // 设置声道:
        (*pcmPlayPlayerMuteSolo)->SetChannelMute(
                    pcmPlayPlayerMuteSolo, 
                    1,  //0右声道1左声道
                    false //声道是否开启
                    );
    
    
    
    

    有效示例:

     SLMuteSoloItf  pcmMutePlay = NULL;
     //初始化
        ...
    void WlAudio::setMute(int mute) {
        this->mute = mute;
        if(pcmMutePlay != NULL)
        {
            if(mute == 0)//right
            {
                (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, false);
                (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, true);
            }
            else if(mute == 1)//left
            {
                (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, true);
                (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, false);
            }
            else if(mute == 2)//center
            {
                (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, false);
                (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, false);
            }
        }
    }
    
    1. 录音

    有效示例:

    
    #include <jni.h>
    #include <string>
    #include "AndroidLog.h"
    #include "RecordBuffer.h"
    
    
    #include <SLES/OpenSLES.h>
    #include <SLES/OpenSLES_Android.h>
    
    bool finish = false;
    FILE *recodeFile = NULL;
    
    
    const static int RECORDER_BUFFER_SIZE = 4096;
    
    SLObjectItf engineObject = NULL;
    SLEngineItf engineItf = NULL;
    
    SLObjectItf recordObj = NULL;
    SLRecordItf recordItf = NULL;
    SLAndroidSimpleBufferQueueItf recorderBufferQueue = NULL;
    
    RecordBuffer *recordBuffer = NULL;
    
    // this callback handler is called every time a buffer finishes recording
    void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
        fwrite(recordBuffer->getNowBuffer(), 1, RECORDER_BUFFER_SIZE * sizeof(short), recodeFile);
        if (finish) {
            LOGE("录制完成");
            //设置停止
            (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
    
            fclose(recodeFile);
    
            //释放资源
            (*recordObj)->Destroy(recordObj);
            recordObj = NULL;
            recordItf = NULL;
            (*engineObject)->Destroy(engineObject);
            engineObject = NULL;
            engineItf = NULL;
            delete (recordBuffer);
    
        } else {
            LOGE("正在录制");
            // 入队
            (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recordBuffer->getRecordBuffer(),
                                            RECORDER_BUFFER_SIZE * sizeof(short));
        }
    
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_zzw_openslesrecoder_MainActivity_startRecord(JNIEnv *env, jobject instance,
                                                          jstring path_) {
    
        const char *path = env->GetStringUTFChars(path_, 0);
        finish = false;
    
        recodeFile = fopen(path, "w+");
    
        //1. 创建引擎对象
        slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    
        //2. 实现引擎对象
        (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    
        //3. 获取引擎接口
        (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineItf);
    
    
    
        // configure audio source
        SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
                                          SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
        SLDataSource audioSrc = {&loc_dev, NULL};
    
        // configure audio sink
        SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
        SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, //PCM格式
                                       2,//立体声
                                       SL_SAMPLINGRATE_44_1,//44100HZ
                                       SL_PCMSAMPLEFORMAT_FIXED_16,//
                                       SL_PCMSAMPLEFORMAT_FIXED_16,
                                       SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, //左右声道
                                       SL_BYTEORDER_LITTLEENDIAN};//小尾端
        SLDataSink audioSnk = {&loc_bq, &format_pcm};
    
    
        // (requires the RECORD_AUDIO permission)
        const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
        const SLboolean req[1] = {SL_BOOLEAN_TRUE};
    
        //4. 配置获取录音的引擎对象
        (*engineItf)->CreateAudioRecorder(engineItf, &recordObj, &audioSrc,
                                          &audioSnk, 1, id, req);
    
        //5. 实现录音的引擎对象
        // realize the audio recorder
        (*recordObj)->Realize(recordObj, SL_BOOLEAN_FALSE);
    
        //6. 获取录音的引擎接口
        //get the record interface
        (*recordObj)->GetInterface(recordObj, SL_IID_RECORD, &recordItf);
    
    
        //7. 获取缓冲队列接口
        //get the buffer queue interface
        (*recordObj)->GetInterface(recordObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                                   &recorderBufferQueue);
    
        //8. 设置录音回掉
        (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback,
                                                 NULL);
    
        recordBuffer = new RecordBuffer(RECORDER_BUFFER_SIZE);
        //9. 入队
        (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recordBuffer->getRecordBuffer(),
                                        RECORDER_BUFFER_SIZE * sizeof(short));
    
        //10. 设置状态开启录音
        (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
        env->ReleaseStringUTFChars(path_, path);
    }
    
    
    
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_zzw_openslesrecoder_MainActivity_stopRecord(JNIEnv *env, jobject instance) {
    
        finish = true;
    }
    
    
    
    

    RecordBuffer.cpp:

    
    #include "RecordBuffer.h"
    
    
    
    RecordBuffer::RecordBuffer(int bufferSize) {
        buffer = new short *[2];
        for (int i = 0; i < 2; i++) {
            buffer[i] = new short[bufferSize];
        }
    }
    
    short *RecordBuffer::getRecordBuffer() {
        index++;
        if (index > 1) {
            index = 0;
        }
        return buffer[index];
    }
    
    RecordBuffer::~RecordBuffer() {
        for (int i = 0; i < 2; i++) {
            delete buffer[i];
        }
        delete buffer;
    }
    
    short *RecordBuffer::getNowBuffer() {
        return buffer[index];
    }
    
    

    RecordBuffer.h

    class RecordBuffer {
    
    public:
        short **buffer;
        int index = 0;
    
    public:
        RecordBuffer(int bufferSize);
        ~RecordBuffer();
    
        short *getRecordBuffer();
    
        short * getNowBuffer();
    
    
    };
    
    

    相关文章

      网友评论

          本文标题:OpenSLES播放、录制、声道切换、音量控制

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