1对1直播源码实现录音和播放

1.1对1直播源码部分开发,实现录音和播放
2.实现so库有效时间限制

/**
* 引用和声明JNI库和函数的类
*/
public class RecoderJni {
static {
System.loadLibrary("recoder-lib");
}

//native interface
public native int play(String filePath);

public native int playStop();

public native int record(String filePath);

public native int stopRecod();

public native int setAvailableTime(long avatime);

public native long getSetTime();
}

 

代码 opensl.h:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <SLES/OpenSLES.h>
/* Header for class com_test_recoder_RecoderJni */

#ifndef _Included_com_test_recoder_RecoderJni
#define _Included_com_test_recoder_RecoderJni
#ifdef __cplusplus
extern "C" {
#endif

/*
* Class: com_test_recoder_RecoderJni
* Method: play
* Signature: (Ljava/lang/String;)I //函数签名
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_play
(JNIEnv *, jobject, jstring);

/*
* Class: com_test_recoder_RecoderJni
* Method: playStop
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_playStop
(JNIEnv *, jobject);

/*
* Class: com_test_recoder_RecoderJni
* Method: record
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_record
(JNIEnv *, jobject, jstring);

/*
* Class: com_test_recoder_RecoderJni
* Method: stopRecod
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_stopRecod
(JNIEnv *, jobject);
/*
* Class: com_test_recoder_RecoderJni
* Method: setAvailableTime
* Signature: (Ljava/lang/long)
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJniy_setAvailableTime
(JNIEnv *, jobject, jlong);
/*
* Class: com_test_recoder_RecoderJni
* Method: getSetTime
* Signature: ()I
*/
JNIEXPORT jlong JNICALL Java_com_test_recoder_RecoderJni_getSetTime
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

 

 

录音和播放openslRecord.c

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <stdio.h>
#include <android/log.h>
#include <malloc.h>
#include <time.h>

#define LOG_TAG "opensl-record"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
/* Header for class com_test_recoder_RecoderJni */


#ifndef _Included_com_test_recoder_RecoderJni
#define _Included_com_test_recoder_RecoderJni
#ifdef __cplusplus
extern "C" {
#endif

#define NB_BUFFERS_IN_QUEUE 1

/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_ANDROIDCONFIGURATION
* on the AudioRecorder object */
#define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 2

/* Size of the recording buffer queue */
#define NB_BUFFERS_IN_QUEUE 1
/* Size of each buffer in the queue */
#define BUFFER_SIZE_IN_SAMPLES 8192
#define BUFFER_SIZE_IN_BYTES (2 * BUFFER_SIZE_IN_SAMPLES)
/* Local storage for Audio data */
int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES];


static SLObjectItf engineSL = NULL;
SLObjectItf recorder_object; //录制对象,这个对象我们从里面获取了2个接口
SLRecordItf recordItf; //录制接口
SLAndroidSimpleBufferQueueItf recorder_buffer_queue; //Buffer接口
int8_t *pcm_data; //数据缓存区
static FILE *gFile = NULL;

typedef long long int64;
long long timefromj;

SLEngineItf CreateRecordSL() {
//1 创建引擎对象
SLresult re;
SLEngineItf en; //存引擎接口
re = slCreateEngine(&engineSL, 0, 0, 0, 0, 0);
if (re != SL_RESULT_SUCCESS) return NULL;

//2 实例化 SL_BOOLEAN_FALSE等待对象创建
re = (*engineSL)->Realize(engineSL, SL_BOOLEAN_FALSE);
if (re != SL_RESULT_SUCCESS) return NULL;

//3 获取接口
re = (*engineSL)->GetInterface(engineSL, SL_IID_ENGINE, &en);
if (re != SL_RESULT_SUCCESS) return NULL;
return en;
}

//数据回调函数
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {

fwrite(pcm_data, BUFFER_SIZE_IN_BYTES, 1, gFile);
//取完数据,需要调用Enqueue触发下一次数据回调
(*bq)->Enqueue(bq, pcm_data, BUFFER_SIZE_IN_BYTES);

}

 

/** 获取当前时间
* @param jniEnv
* @param instance
* @return
*/
int64 getSystemTime(){
struct timeval tv; //获取一个时间结构
gettimeofday(&tv, NULL); //获取当前时间
int64 t = tv.tv_sec;
t *=1000;
t +=tv.tv_usec/1000;
return t;
}

/*
* Class: com_test_recoder_RecoderJni
* Method: record
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_record
(JNIEnv *jniEnv, jobject instance, jstring path) {
int64 time = getSystemTime();
LOGE("current_time ,current_time=%lld ", time);
LOGE("timefromj ,timefromj=%lld ", timefromj);

if(time > timefromj){ //指定时间
LOGE("current_time is fail ");
return -1;
}
SLresult re;
const char *file_path = (*jniEnv)->GetStringUTFChars(jniEnv, path, NULL);
gFile = fopen(file_path, "w");
if (!gFile) {
LOGE("file open failed");
return -1;
}
(*jniEnv)->ReleaseStringUTFChars(jniEnv, path, file_path);

//设置IO设备(麦克风)
SLDataLocator_IODevice io_device = {
SL_DATALOCATOR_IODEVICE, //类型 这里只能是SL_DATALOCATOR_IODEVICE
SL_IODEVICE_AUDIOINPUT, //device类型 选择了音频输入类型
SL_DEFAULTDEVICEID_AUDIOINPUT, //deviceID 对应的是SL_DEFAULTDEVICEID_AUDIOINPUT
NULL //device实例
};
SLDataSource data_src = {
&io_device, //SLDataLocator_IODevice配置输入
NULL //输入格式,采集的并不需要
};

//设置输出buffer队列
SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, //类型 这里只能是SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
2 //buffer的数量
};
//设置输出数据的格式
SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM, //输出PCM格式的数据
1, //输出的声道数量
SL_SAMPLINGRATE_44_1, //输出的采样频率,这里是44100Hz
SL_PCMSAMPLEFORMAT_FIXED_16, //输出的采样格式,这里是16bit
SL_PCMSAMPLEFORMAT_FIXED_16, //一般来说,跟随上一个参数
SL_SPEAKER_FRONT_LEFT, //双声道配置,如果单声道可以用 SL_SPEAKER_FRONT_CENTER
SL_BYTEORDER_LITTLEENDIAN //PCM数据的大小端排列
};
SLDataSink audioSink = {
&buffer_queue, //SLDataFormat_PCM配置输出
&format_pcm //输出数据格式
};

 

//1 创建引擎
SLEngineItf eng = CreateRecordSL();
if (eng) {
LOGE("CreateSL success! ");
} else {
LOGE("CreateSL failed! ");
}


//创建录制的对象,并且指定开放SL_IID_ANDROIDSIMPLEBUFFERQUEUE这个接口
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
re = (*eng)->CreateAudioRecorder(eng, //引擎接口
&recorder_object, //录制对象地址,用于传出对象
&data_src, //输入配置
&audioSink, //输出配置
1, //支持的接口数量
id, //具体的要支持的接口
req //具体的要支持的接口是开放的还是关闭的
);

if (re != SL_RESULT_SUCCESS) {
LOGE("CreateAudioRecorder failed!");
return -1;
}
1对1直播源码实现录音和播放
//实例化这个录制对象
re = (*recorder_object)->Realize(recorder_object, SL_BOOLEAN_FALSE);
if (re != SL_RESULT_SUCCESS) {
LOGE("Realize failed!");
}

//获取录制接口
re = (*recorder_object)->GetInterface(recorder_object, SL_IID_RECORD, &recordItf);
if (re != SL_RESULT_SUCCESS) {
LOGE("GetInterface1 failed!");
}
//获取Buffer接口
re = (*recorder_object)->GetInterface(recorder_object, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&recorder_buffer_queue);
if (re != SL_RESULT_SUCCESS) {
LOGE("GetInterface2 failed!");
}

//申请一块内存,注意RECORDER_FRAMES是自定义的一个宏,指的是采集的frame数量,具体还要根据你的采集格式(例如16bit)计算
pcm_data = malloc(BUFFER_SIZE_IN_BYTES);

//设置数据回调接口bqRecorderCallback,最后一个参数是可以传输自定义的上下文引用
re = (*recorder_buffer_queue)->RegisterCallback(recorder_buffer_queue, bqRecorderCallback, 0);
if (re != SL_RESULT_SUCCESS) {
LOGE("RegisterCallback failed!");
}
//设置录制器为录制状态 SL_RECORDSTATE_RECORDING
re = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
if (re != SL_RESULT_SUCCESS) {
LOGE("SetRecordState failed!");
}
//在设置完录制状态后一定需要先Enqueue一次,这样的话才会开始采集回调
re = (*recorder_buffer_queue)->Enqueue(recorder_buffer_queue, pcm_data, 8192);
if (re != SL_RESULT_SUCCESS) {
LOGE("Enqueue failed!");
}
return 0;
}


/*
* Class: com_test_recoder_RecoderJni
* Method: stopRecod
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_stopRecod
(JNIEnv *jniEnv, jobject instance) {
LOGE("STOP record");
if (recordItf != NULL) {
(*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
return 0;
} else {
return -1;
}
}

JNIEXPORT jint JNICALL Java_com_test_recoder_RecoderJni_setAvailableTime
(JNIEnv *jniEnv, jobject instance, jlong longtime) {
timefromj = longtime;
LOGE("jni receiver time ,send timefromj =%lld ", timefromj);
return 0;
}

JNIEXPORT jlong JNICALL Java_com_test_recoder_RecoderJni_getSetTime
(JNIEnv *jniEnv, jobject instance) {
// LOGE("jni receiver time ,send timefromj =%lld ", timefromj);
return timefromj;
}

 

 

#ifdef __cplusplus
}
#endif
#endif

 

以上就是1对1直播源码实现录音和播放, 更多内容欢迎关注之后的文章

posted @ 2021-08-16 14:25  云豹科技-苏凌霄  阅读(164)  评论(0编辑  收藏  举报