(一) 简单介绍
1.1 AudioRecord
AudioRecord是android捕捉音频的其中的一个工具。
另外一个工具是MediaRecorder
关于这两个工具的比较网上有很多,大家可以看看。
1.2 AudioTrack
AudioTrack是播放PCM流的,android其实还有,
SoundPool 类
MediaPlayer 类
JetPlayer 类
AudioTrack 类
1.3 PCM格式
AudioRecord捕捉到的是PCM的格式:
PCM: 模拟音频信号经过模数转换(AD变换)直接形成的二进制序列,该文件没有附加的文件头和文件结束标志。
PCM文件格式简介:
http://wenku.baidu.com/link?url=78-ueL3a...
1.4 音频有关的术语:
采用频率(the sampling rate):模拟信息转成数字信号的采样率。
采样位数:8位 或者 16位 去存储每一次的采样结果。
声道数:单声道,立体声道(2)。
比特率(Bit rate )/位率:声音中的比特率是指将模拟声音信号转换成数字声音信号后,单位时间内的二进制数据量,是间接衡量音频质量的一个指标。
比特率(bps) = 采样频率(HZ) 采样位数(Bit) 声道数
(二) AudioRecord的使用
private void _record(String path) {
// 录音调用的方法。如果文件已经存在,则覆盖。
File file = new File(path);
// 创建输出流 , 缓存输出流。
try {
OutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
/**
* 1. 录音来源
* 2. 采样频率
* 3. STEREO 双声道,MONO 单声道
* 4. 编码制式和采样的位数。ENCODING_PCM_16BIT
* 5. 采集数据需要的缓冲区大小。
*/
AudioRecord audioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC,
frequency,
channelConfiguration,
audioEncoding,
bufferSize);
short[] buffer = new short[bufferSize];
audioRecord.startRecording();
isRecording = true;
//listener
if (onRecordStartedLister!=null) {
onRecordStartedLister.onStarted();
}
while (isRecording) {
int bufferReadResult = audioRecord.read(buffer,0,bufferSize); // 从 AudioRecord中读取 0 - bufferSize
for (int i=0;i<bufferReadResult;i++) {
dos.writeShort(buffer[i]); // 写入 dos 中
}
}
audioRecord.stop();
audioRecord.release();
dos.close();
os.close();
bos.close();
//listener
if (onRecordStoppedLister!=null) {
onRecordStoppedLister.onStopped();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("FileNotFoundException", e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.e("IOException2", e.getMessage());
}
}
步骤:
1.首先,你得有个路径 Path:例如,(存储卡的根目录)
String file = Environment.getExternalStorageDirectory().getAbsolutePath() + "/wang_ni_ma.pcm";
2.创建输出流:
OutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
3.新建 AudioRecord 的对象:
AudioRecord audioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC,
11025,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize);
参数的说明:
① 音频的来源,就是你使用什么进行捕捉,这里的MIC是指麦克风
② 音频的采样频率,有些低端机型支持的频率可能不能太高。
③ 音频的声道数,AudioRecord只支持,单双声道。MONO单声道。STEREO 双声道
④ 音频的采样位数:有8,16Bit。
⑤ 采集数据需要的缓冲区大小
这个大小最好用函数计算出来:
其也需要三个参数:采样率,声道数,采样位数。
int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
4.这里BB几句。
while (isRecording) {
int bufferReadResult = audioRecord.read(buffer,0,bufferSize); // 从 AudioRecord中读取 0 - bufferSize
for (int i=0;i<bufferReadResult;i++) {
dos.writeShort(buffer[i]); // 写入 dos 中
}
}
while里面是核心,audioRecord.read方法,从0到bufferSize读取,放到buffer中,
然后就dos.writeShort(buffer[i])写入 dos 中。
isRecording,Boolen变量,我们可以通过button的触发,把它变成false,就结束录音了。
(三) AudioTrack的使用
代码例子如下:
private void _play(String path) {
// 1. PCM文件所在位置
File file = new File(path);
// 2. 计算 Buff 大小
int buffSize = AudioTrack.getMinBufferSize(frequency,channelConfiguration,audioEncoding);
try {
// 3. 创建一个输入流 DataInputStream
InputStream is = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(is);
DataInputStream dis = new DataInputStream(bis);
// 4. 创建播放器 audioTrack
/**
1)指定在流的类型
STREAM_ALARM:警告声
STREAM_MUSCI:音乐声,例如music等
STREAM_RING:铃声
STREAM_SYSTEM:系统声音
STREAM_VOCIE_CALL:电话声音
2)音频的采样率
3)音频 声道数
CHANNEL_CONFIGURATION_MONO 单声道
CHANNEL_CONFIGURATION_STEREO 双声道
4)采样位数
AudioFormat.ENCODING_PCM_16BIT 16 bit
AudioFormat.ENCODING_PCM_8BIT 8 bit
5) 缓存大小
由函数直接得出。
AudioTrack.getMinBufferSize
6) 模式
AudioTrack.MODE_STREAM
AudioTrack.MODE_STATIC
AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。
STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。
这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。
这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。
而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,
后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。
这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。
*/
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
frequency,
channelConfiguration,
audioEncoding,
buffSize,
AudioTrack.MODE_STREAM
);
// 5. 读取 file 到 music array 中
/**
* 1)建立缓存数组 music[]
* 2)从 PCM 流文件读出,每 20 次,
* 3)放到 audioTrack.write 中,播放。
*/
int i=0;
short[] music = new short[20];
audioTrack.play();
// listener
if (onPlayStartedLister != null) {
onPlayStartedLister.onStarted();
}
while (dis.available()>0) { // 判断PCM流文件是否结束
music[i] = dis.readShort(); // 从PCM文件中,以流的形式读出存放在 music 中
if (i==19) { // 定义每次读出 20 的数据后,播放。
audioTrack.write(music, 0, 20);
i = 0;
}
else {
i++;
}
}
dis.close();
bis.close();
is.close();
audioTrack.stop();
// listener
if (onPlayStoppedListener!=null) {
onPlayStoppedListener.onPlayStop();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
其中,对象AudioTrack的参数需要和AudioRecord的录音格式一致。
其他需要BB的,在注释里面也挺清楚的了。
(四) 总结
第一次写文章,也许,很多地方需要改进,或者是理解错了,希望大家指出来,那也是大家共同进步了。今天是搞了一下午,有点成果了,Audio系统,其实算是挺底层的了,有大神已经说得很好了:http://www.cnblogs.com/innost/archive/20...,有时间也可以去研究一下。