AAudio进行音频采集的实现

只愿长相守 提交于 2020-01-15 18:13:34

使用AAudio进行音频采集

前提

OpenSL ES对音频的采集方面有的不兼容,准备实现一个通过AAudio进行音频采集。我刚接触只是踩坑。
上网搜了很久,关于AAudio的资料不多。个人觉得参考NDK官网AAudio介绍韩曙亮博主的分析,足够理解AAudio的相关API用处了,具体的demo可参考Oboe项目test部分(直接搜“GitHub Oboe”就可以)。
我个人只是简单的实现了录音/播放功能。

使用软件和NDK:

  • 编辑软件:Android Studio。
  • NDK版本:r20。

1. 初始化

1.1头文件

	#include <aaudio/AAudio.h>	// 调用AAudio库
	#include <android/log.h>	// 打印log
	#include <iostream>
	using namespace std;

1.2 相关变量

	// AAudio相关变量
	AAudioStream *stream;
	AAudioStreamBuilder *builder = NULL;
	// 存储数据的相关变量
	char g_Buffer[1024 * 1024] = {0};	// 音频大小限制为1M,可自行修改
	int g_dataSize = 0;	// 存放数据大小
	int g_readIndex = 0;	// 用于定位文件写操作的位置

1.2 初始化StreamBuilder

	result=AAudio_createStreamBuilder(&builder);
	if(result!=AAUDIO_OK){
		LOGE("AAudio_createStreamBuildererror%d",result);
		return0;
	}

1.3 相关配置

	//myAAudioStreamDataCallbackPlay是采集音频数据或者播放音频数据的函数,类似于线程的线程函数。
	AAudioStreamBuilder_setDataCallback(builder,myAAudioStreamDataCallbackPlay,this);
	
	//AAUDIO_PERFORMANCE_MODE_LOW_LATENCY是低延迟方式。
	AAudioStreamBuilder_setPerformanceMode(builder,AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

1.4 设置具体参数

	AAudioStreamBuilder_setDeviceId(builder,18);//设置音频流设备ID
	
	//设置音频流方向,AAUDIO_DIRECTION_INPUT是录音,AAUDIO_DIRECTION_OUTPUT是播放
	AAudioStreamBuilder_setDirection(builder,AAUDIO_DIRECTION_OUTPUT);
	
	//设置共享模式,独占模式性能更高,延迟更低;
	AAudioStreamBuilder_setSharingMode(builder,AAUDIO_SHARING_MODE_SHARED);
	
	AAudioStreamBuilder_setSampleRate(builder,48000);//设置Rate
	
	AAudioStreamBuilder_setChannelCount(builder,2);//设置音频通道个数
	
	AAudioStreamBuilder_setFormat(builder,AAUDIO_FORMAT_PCM_I16);//设置音频流样本格式
	
	AAudioStreamBuilder_setBufferCapacityInFrames(builder,4096);//在帧中设置缓冲区容量

1.5 获取帧大小

	int32_tsizeInFrames = AAudioStream_getBufferSizeInFrames(stream);
	LOGI("sizeInFrames = %d",sizeInFrames);

1.6 获取音频流设备ID:

	int32_tDeviceId = AAudioStream_getDeviceId(stream);

1.5 打开Stream

	result=AAudioStreamBuilder_openStream(builder,&stream);
	if(result!=AAUDIO_OK){
		LOGE("AAudioStreamBuilder_openStreamerror%d",result);
		return0;
	}
	
	result=AAudioStream_requestStart(stream);//状态请求。开启音频流,即录音/播放
	if(result!=AAUDIO_OK){
		LOGE("AAudioStream_requestStarterror%d",result);
		return0;
	}

2. 数据的采集和播放

2.1 录音

aaudio_data_callback_result_tmyAAudioStreamDataCallback(
	AAudioStream*stream,
	void*userData,
	void*audioData,
	int32_tnumFrames){
		// 把录音数据存储到本地
		//staticFILE*fp=fopen("/sdcard/aaudio_record.pcm","wb");
		//if(fp){
		//	fwrite(audioData,1,2*numFrames*sizeof(short),fp);
		//}
		//LOGI("myAAudioStreamDataCallbackcall%d,fp:%p",numFrames,fp);
		
		// 把录音数据存储到临时变量中
		memcpy(g_Buffer+g_dataSize,audioData,2*numFrames*sizeof(short));
		g_dataSize+=2*numFrames*sizeof(short);
		returnAAUDIO_CALLBACK_RESULT_CONTINUE;
	}

2.2 播放

	aaudio_data_callback_result_tmyAAudioStreamDataCallbackPlay(
	AAudioStream*stream,
	void*userData,
	void*audioData,
	int32_tnumFrames){
		// 从本地视频文件中获取数据
		//staticFILE*fp=fopen("/sdcard/aaudio_record.pcm","rb");
		//LOGI("myAAudioStreamDataCallbackPlaycall%d,fp:%p",numFrames,fp);
		//if(fp){
			//size_treadSize=fread(audioData,1,2*numFrames*sizeof(short),fp);
			//if(readSize>0){
			//	returnAAUDIO_CALLBACK_RESULT_CONTINUE;
			//}
		//}
		//returnAAUDIO_CALLBACK_RESULT_STOP;
		
		// 在临时变量中获取数据
		LOGI("myAAudioStreamDataCallbackPlaynumFrames:%d,g_dataSize:%d",numFrames,g_dataSize);
		constintreadSize=numFrames*2*sizeof(short);
		if(g_readIndex+readSize<g_dataSize){
			memcpy(audioData,g_Buffer+g_readIndex,readSize);
			g_readIndex+=readSize;
			returnAAUDIO_CALLBACK_RESULT_CONTINUE;
		}else
			returnAAUDIO_CALLBACK_RESULT_STOP;
	}

其他

关于项目:

  1. 具体的实现直接设置几个按钮:开始录音,停止录音,开始播放,停止播放就可以了。
  2. 具体的代码就不上传了,代码量不多,主要时间花费在Android Studio的工程配置上了。

参考资料:
Android NDK中AAudio介绍
由于官网文件都是英文,看着也比较枯燥,我找了个整理好的大佬博客:韩博主的博客主页
其中一篇AAudio的分析博客链接:https://blog.csdn.net/shulianghan/article/details/103005057

PS:对于AAudio只是初学者,如有不对的地方欢迎指出。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!