<activity android:name=".OpenSLESActivity" />
cmake 配置OpenSLES
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
SHARED
native-lib.cpp
RecordBuffer.cpp
AndroidLog.h)
find_library(
log-lib
log )
target_link_libraries(
native-lib
${log-lib}
OpenSLES)
AndroidLog.h
#ifndef RTMPSUC_ANDROIDLOG_H
#define RTMPSUC_ANDROIDLOG_H
#include <android/log.h>
#define LOGD(FORMAT, ...) __android_log_print(ANDROID_LOG_DEBUG,"godv",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"godv",FORMAT,##__VA_ARGS__);
#define LOG_DEBUG false
#endif //RTMPSUC_ANDROIDLOG_H
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->getNowBuffer(), 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("正在录制");
(*recorderBufferQueue)->Enqueue(recorderBufferQueue, recordBuffer->getRecordBuffer(), 4096);
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_glivepush_OpenSLESActivity_startRecord(JNIEnv *env, jobject thiz, jstring path_) {
const char *path = env->GetStringUTFChars(path_, 0);
recordBuffer = new RecordBuffer(4096);
pcmFile = fopen(path, "w");
finish = false;
//创建引擎
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
};
//1 格式 2 声道数 3 采样率 4 位数 5 位数 6 通道布局(立体) 7 对齐
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 audioSink = {
&loc_bq,
&format_pcm
};
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
//创建录音器
(*engineItf)->CreateAudioRecorder(engineItf, &recordObj, &audioSrc, &audioSink, 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);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_glivepush_OpenSLESActivity_stopRecord(JNIEnv *env, jobject thiz) {
// TODO: implement stopRecord()
finish = true;
}
RecordBuffer.h
#ifndef RTMPSUC_RECORDBUFFER_H
#define RTMPSUC_RECORDBUFFER_H
class RecordBuffer {
public:
//二级指针 一维数组
short **buffer;
int index = -1;
public:
RecordBuffer(int bufferSize);
~RecordBuffer();
short *getRecordBuffer();
short *getNowBuffer();
};
#endif //RTMPSUC_RECORDBUFFER_H
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::getNowBuffer() {
return buffer[index];
}
short *RecordBuffer::getRecordBuffer() {
index++;
if (index > 1) {
index = 1;
}
return buffer[index];
}
RecordBuffer::~RecordBuffer() {
for (int i = 0; i < 2; i++) {
delete buffer[i];
}
delete buffer;
}
OpenSLESActivity
package com.example.glivepush;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class OpenSLESActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_open_sles);
}
public native void startRecord(String path);
public native void stopRecord();
public void startRecord(View view) {
startRecord(Environment.getExternalStorageDirectory().getAbsolutePath() + "/g_opensl_record.pcm");
}
public void stopRecord(View view) {
stopRecord();
}
}