第二十八节 录制音频AudioRecord、OpenSL ES

2018-12-06  本文已影响13人  最美下雨天
image.png
image.png

AudioRecoder的使用非常简单
AudioRecordUitl.java

package com.ywl5320.audiorecord;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

public class AudioRecordUitl {

    private AudioRecord audioRecord;
    private int bufferSizeInBytes;
    private boolean start = false;
    private int readSize = 0;

    private OnRecordLisener onRecordLisener;

    public AudioRecordUitl() {
        bufferSizeInBytes = AudioRecord.getMinBufferSize(
                44100,
                AudioFormat.CHANNEL_IN_STEREO,
                AudioFormat.ENCODING_PCM_16BIT);

        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                44100,
                AudioFormat.CHANNEL_IN_STEREO,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSizeInBytes
                );
    }

    public void setOnRecordLisener(OnRecordLisener onRecordLisener) {
        this.onRecordLisener = onRecordLisener;
    }

    public void startRecord()
    {
        new Thread(){
            @Override
            public void run() {
                super.run();
                start = true;
                audioRecord.startRecording();
                byte[] audiodata = new byte[bufferSizeInBytes];
                while (start)
                {
                    readSize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
                    if(onRecordLisener != null)
                    {
                        onRecordLisener.recordByte(audiodata, readSize);
                    }
                }
                if(audioRecord != null)
                {
                    audioRecord.stop();
                    audioRecord.release();
                    audioRecord = null;
                }
            }
        }.start();
    }

    public void stopRecord()
    {
        start = false;
    }
    public interface OnRecordLisener{
        void recordByte(byte[] audioData, int readSize);
    }
}

MainActivity.java

package com.ywl5320.audiorecord;

import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private AudioRecordUitl audioRecordUitl = null;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=findViewById(R.id.button);
        path= Environment.getExternalStorageDirectory()+"/audio.pcm";
        try {
            fileOutputStream=new FileOutputStream(new File(path));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    private String path;
    private FileOutputStream fileOutputStream;
    public void recordaudio(View view) {

        if(audioRecordUitl == null)
        {
            button.setText("结束录制");
            audioRecordUitl = new AudioRecordUitl();
            audioRecordUitl.setOnRecordLisener(new AudioRecordUitl.OnRecordLisener() {
                @Override
                public void recordByte(byte[] audioData, int readSize) {
                    Log.d("abc", "readSize is : " + readSize);
                    try {
                        fileOutputStream.write(audioData);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            audioRecordUitl.startRecord();
        }
        else
        {
            try {
                fileOutputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
            button.setText("开始录制");
            audioRecordUitl.stopRecord();
            audioRecordUitl = null;
        }
    }
}

image.png image.png

OpenSL ES既能播放音频,也能录制音频(都是对pcm数据来说的)
区别:
录制

(*engineItf)->CreateAudioRecorder(engineItf, &recordObj, &audioSrc, &audioSnk, 1, id, req);

播放

 (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 2, ids, req);

native-lib.cpp

#include <jni.h>
#include <string>

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include "RecordBuffer.h"
#include "AndroidLog.h"

SLObjectItf slObjectEngine = NULL;
SLEngineItf  engineItf = NULL;

SLObjectItf  recordObj = NULL;
SLRecordItf  recordItf = NULL;

SLAndroidSimpleBufferQueueItf recorderBufferQueue = NULL;

RecordBuffer *recordBuffer;

FILE *pcmFile = NULL;

bool finish = false;


void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    fwrite(recordBuffer->getRecordBuffer(), 1, 4096, pcmFile);
    if(finish)
    {
        LOGE("录制完成");
        (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
        //
        (*recordObj)->Destroy(recordObj);
        recordObj = NULL;
        recordItf = NULL;
        (*slObjectEngine)->Destroy(slObjectEngine);
        slObjectEngine = NULL;
        engineItf = NULL;
        delete(recordBuffer);
    } else{
        LOGE("正在录制");
        //入队,bqRecorderCallback会循环被调用
        (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recordBuffer->getRecordBuffer(), 4096);
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_ywl5320_openslesrecord_MainActivity_startRecord(JNIEnv *env, jobject instance,
                                                         jstring path_) {

    if(finish)
    {
        return;
    }
    const char *path = env->GetStringUTFChars(path_, 0);
    finish = false;
    pcmFile = fopen(path, "w");
    recordBuffer = new RecordBuffer(4096);

    slCreateEngine(&slObjectEngine, 0, NULL, 0, NULL, NULL);
    (*slObjectEngine)->Realize(slObjectEngine, SL_BOOLEAN_FALSE);
    (*slObjectEngine)->GetInterface(slObjectEngine, SL_IID_ENGINE, &engineItf);



    SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
                                      SL_IODEVICE_AUDIOINPUT,
                                      SL_DEFAULTDEVICEID_AUDIOINPUT,
                                      NULL};
    SLDataSource audioSrc = {&loc_dev, NULL};


    SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
            2
    };


    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
    };

    SLDataSink audioSnk = {&loc_bq, &format_pcm};

    const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};

    (*engineItf)->CreateAudioRecorder(engineItf, &recordObj, &audioSrc, &audioSnk, 1, id, req);
    (*recordObj)->Realize(recordObj, SL_BOOLEAN_FALSE);
    (*recordObj)->GetInterface(recordObj, SL_IID_RECORD, &recordItf);

    (*recordObj)->GetInterface(recordObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue);

    //入队
    (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recordBuffer->getRecordBuffer(), 4096);

    (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, NULL);

    (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);

    env->ReleaseStringUTFChars(path_, path);
}


extern "C"
JNIEXPORT void JNICALL
Java_com_ywl5320_openslesrecord_MainActivity_stopRecord(JNIEnv *env, jobject instance) {

    // TODO
    finish = true;

}

RecordBuffer.cpp
课件中用了两个数组,但是感觉是没有起到什么作用的

//
// Created by yangw on 2018-9-3.
//

#include "RecordBuffer.h"

RecordBuffer::RecordBuffer(int buffersize) {
    buffer = new short *[1];
    buffer[0] = new short[buffersize];
}

short *RecordBuffer::getRecordBuffer() {
    return buffer[0];
}

RecordBuffer::~RecordBuffer() {
    delete  buffer[0];
    delete buffer;
}



上一篇 下一篇

猜你喜欢

热点阅读