Android AudioRecord入门知识与简易APP调试

AudioRecord PCM音频采集流程

PCM音频采集java程序对AudioRecord常见的调用方法大致如下

// 对象创建:new
audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);
其中,数据缓冲区大小bufferSizeInBytes可以使用方法 AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) 获得。

// 启动音频采集
audioRecord.startRecording();

// 停止采集
audioRecord.stop();
即:new一个audioRecord之后就可以start()启动音频采集,通过stop()停止采集。
备注:AudioRecord没有提供暂停的API,目前所实现的暂停,就是不断的使用停止和再次录制,形成多个文件,然后再合并成一个文件并转码成wav。

// 释放资源
audioRecord.release();

创建AudioRecord对象的参数分析

转自https://blog.csdn.net/weixin_30673611/article/details/98935421

第一个参数:audioSource音频源

第二个参数:采样率sampleRateInHz(赫兹)

只能在4000到192000的范围内取值
在AudioFormat类里
public static final int SAMPLE_RATE_HZ_MIN = 4000; 最小4000
public static final int SAMPLE_RATE_HZ_MAX = 192000; 最大192000

第三个参数:channelConfig 声道配置 描述音频声道的配置,例如左声道/右声道/前声道/后声道。

在AudioFormat类里:
public static final int CHANNEL_IN_LEFT = 0x4; //左声道
public static final int CHANNEL_IN_RIGHT = 0x8; //右声道
public static final int CHANNEL_IN_FRONT = 0x10; //前声道
public static final int CHANNEL_IN_BACK = 0x20; //后声道
public static final int CHANNEL_IN_LEFT_PROCESSED = 0x40;
public static final int CHANNEL_IN_RIGHT_PROCESSED = 0x80;
public static final int CHANNEL_IN_FRONT_PROCESSED = 0x100;
public static final int CHANNEL_IN_BACK_PROCESSED = 0x200;
public static final int CHANNEL_IN_PRESSURE = 0x400;
public static final int CHANNEL_IN_X_AXIS = 0x800;
public static final int CHANNEL_IN_Y_AXIS = 0x1000;
public static final int CHANNEL_IN_Z_AXIS = 0x2000;
public static final int CHANNEL_IN_VOICE_UPLINK = 0x4000;
public static final int CHANNEL_IN_VOICE_DNLINK = 0x8000;
public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT; //单声道
public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT); //立体声道(左右声道)

第四个参数audioFormat 音频格式 表示音频数据的格式。

注意!一般的手机设备可能只支持 16位PCM编码,如果其他的都会报错为坏值.
public static final int ENCODING_PCM_16BIT = 2; //16位PCM编码
public static final int ENCODING_PCM_8BIT = 3; //8位PCM编码
public static final int ENCODING_PCM_FLOAT = 4; //4位PCM编码
public static final int ENCODING_AC3 = 5;
public static final int ENCODING_E_AC3 = 6;
public static final int ENCODING_DTS = 7;
public static final int ENCODING_DTS_HD = 8;
//MP3编码 此格式可能会因为不设备不支持报错
public static final int ENCODING_MP3 = 9;
public static final int ENCODING_AAC_LC = 10;
public static final int ENCODING_AAC_HE_V1 = 11;
public static final int ENCODING_AAC_HE_V2 = 12;

给音频文件添加头部信息,并且转换格式成wav

偏移地址命名·内容
01-03ChunkId“RIFF”
04-07ChunkSize下个地址开始到文件尾的总字节数(此Chunk的数据大小)
08-11fccType“WAVE”
12-15SubChunkId1"fmt ",最后一位空格。
16-19SubChunkSize1一般为16,表示fmt Chunk的数据块大小为16字节
20-21FormatTag1:表示是PCM 编码
22-23Channels 声道数单声道为1,双声道为2
24-27Channels采样率
28-31BytesPerSec码率 :采样率 * 采样位数 * 声道个数,bytePerSecond = sampleRate * (bitsPerSample / 8) * channels
32-33BlockAlign每次采样的大小:位宽*声道数/8
34-35BitsPerSample位宽
36-39SubChunkId2“data”
40-43SubChunkSize2音频数据的长度
44-…data音频数据

AudioRecord APP 调试

1. 录音保存时外部存储权限问题

Android5.0. 之后,将录音文件保存在emulator外部存储器时,需要动态获取外部存储器的存储权限:

  1. 在AndroidManifest.xml文件中添加如下内容:
<!--音频录制权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--读取和写入存储权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  1. 在MainActivity.java中添加申请权限代码
// 动态申请外部存储读写权限
private void requestPermissions() {
	if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
		//没有授权,编写申请权限代码
    	ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
	} else {
		Log.d("AudioRecorder", "requestPermissions: 有写SD权限");
	}
	if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
		//没有授权,编写申请权限代码
		ActivityCompat.requestPermissions(MainActivity.this, new String[] 			        {Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
	} else {
		Log.d("AudioRecorder", "requestMyPermissions: 有读SD权限");
	}
}

2. 文件保存路径问题

// 过时方法

private static final String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/AudioRecordFile";

// 保存路径:
/storage/emulated/0/Android/data/packname/files/MUSIC/AudioRecordFile

private static String filePath;
......
private String getFilePath(Context context) {
	filePath = context.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath() + "/AudioRecordFile/";
	return filePath;
}

顺便贴出各种保存路径对应的方法:
//路径:./storage/emulator/0/Android/data/类名/DCIM/ DIR_NAME
context.getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath() + File.separator + DIR_NAME;
1). Environment.getDataDirectory() = /data
这个方法是获取内部存储的根路径
2). getFilesDir().getAbsolutePath() = /data/user/0/packname/files
这个方法是获取某个应用在内部存储中的files路径
3). getCacheDir().getAbsolutePath() = /data/user/0/packname/cache
这个方法是获取某个应用在内部存储中的cache路径
4). getDir(“myFile”, MODE_PRIVATE).getAbsolutePath() = /data/user/0/packname/app_myFile
这个方法是获取某个应用在内部存储中的自定义路径
方法2,3,4的路径中都带有包名,说明他们是属于某个应用
…………………………………………………………………………………………
5). Environment.getExternalStorageDirectory().getAbsolutePath() = /storage/emulated/0
这个方法是获取外部存储的根路径
6)、Environment.getExternalStoragePublicDirectory(“”).getAbsolutePath() = /storage/emulated/0
这个方法是获取外部存储的根路径
7). getExternalFilesDir(“”).getAbsolutePath() = /storage/emulated/0/Android/data/packname/files
这个方法是获取某个应用在外部存储中的files路径
8). getExternalCacheDir().getAbsolutePath() = /storage/emulated/0/Android/data/packname/cache
这个方法是获取某个应用在外部存储中的cache路径

3. 输入输出流文件操作报错:Attempt to invoke virtual method ‘java.io.File android.content.Context,getExternalFilesDir(java.lang.String)’ on a null object reference.

Context context = this;
getFilePath()方法调用获取文件路径:

private String getFilePath(Context context) {
	filePath = context.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath() + "/AudioRecordFile/";
	return filePath;
}

4. 录音暂停生成多个pcm文件产生文件覆盖问题:设置currentFileName变量保存文件名

private static String fileName = "AudioRecordTest"; //文件名
......
private void writeDatatoFile() {
	......
	String currentName = fileName;

	// 设置currentName,在文件名后面加一个数字,防止暂停录音产生的文件覆盖问题
	if(status == Status.STATUS_PAUSE) {
		currentName += fileNameList.size();
	}
	currentName += ".pcm";
	fileNameList.add(currentName);
	// 向列表添加PCM文件路径+文件名
	pcmFileList.add(filePath + currentName);
    ......
}

5. 多个pcm文件打包转成wav格式, wav文件大小为0

将保存文件(文件路径+文件名)的列表设置为全局变量,每次录音产生pcm文件时都将完整文件路径+文件名加入列表(见问题4代码)

6. 打包apk时报错: could not determine the dependencies of task’: app: lintVitalRelease’.

在build.gradle(:app)中加入代码:

lintOptions {
	checkReleaseBuilds false
	abortOnError false
}

7. 打包时ERROR: Key was created with errors:

Warning:
JKS 秘钥库使用专用格式。建议使用 “keytool -importkeystore -srckeystore home/user/AndroidStudioProject/AudioRecordDemo/apk/AudioRecoder.jks -destkeystore home/user/AndroidStudioProject/AudioRecordDemo/apk/AudioRecoder.jks -deststoretype pkcs12” 迁移到行业标准格式PKCS12.
参考:android打包生成APK

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值