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直播源码实现录音和播放, 更多内容欢迎关注之后的文章