AudioRecord 使用小结与注意事项
2017-08-10 09:40
976 查看
使用专门的线程读取数据,容易出现buffer overflow。
使用 setRecordPositionUpdateListener时,要注意两个问题:
一:
1.启动录音后,要先read buffer,才会通知激活 listener。
audioRecord.startRecording();
audioRecord.read(buffer, 0, buffer.length);
2.录音 通知周期 及 录音数据读取 buffer 的设定(重点:audioRecord.read()读取的大小最好是设定的缓冲区的一半,效果会好多)
audioRecord.setPositionNotificationPeriod(framePeriod);//也可以自己指定一个buffer大小,但是不能小于min buffer
bufferSize = AudioRecord.getMinBufferSize(sampleRate,channelConfig, audioFormat);
int framePeriod=framePeriod = bufferSize / (2 * bSamples * nChannels / 8);
//读取录音数据 的buffer 应该为bufferSize/2,否则会出现stop后,数据延时与混乱(数据未正确写入文件)
buffer = new byte[framePeriod * bSamples / 8 * nChannels];//buffer = new byte[bufferSize/2]
二:
避免录音阻塞主线程,利用反射,更改AudioRecord 对象中的 mInitializationLooper(Looper 对象) 属性,为我们指定的子线程的 looper,然后再设置setRecordPositionUpdateListener(这个方法中会用到mInitializationLooper
对象)
audioRecorder1=AudioRecorder1.getInstanse();
HandlerThread handlerThread=new HandlerThread("handlerThread");
handlerThread.start();
...
//利用反射,更改属性,为指定子线程的looper
field2.set(field.get(audioRecorder1), handlerThread.getLooper());
//设置监听
audioRecorder1.prepare();
//prepare 方法的实现
public void prepare() {
try {
if (state == State.INITIALIZING) {
audioRecorder.setRecordPositionUpdateListener(updateListener);
audioRecorder.setPositionNotificationPeriod(framePeriod);
if ((audioRecorder.getState() == AudioRecord.STATE_INITIALIZED)
& (filePath != null)) {
// write file header
OutputStream out = new FileOutputStream(filePath);
out.write(1);
out.close();
random = new RandomAccessFile(filePath, "rw");
random.setLength(0); // Set file length to
random.writeBytes("RIFF");
......
具体细节如下
audioRecorder1=AudioRecorder1.getInstanse();
HandlerThread handlerThread=new HandlerThread("handlerThread");
handlerThread.start();
try {
Field field=audioRecorder1.getClass().getDeclaredField("audioRecorder");
Field field2=field.getType().getDeclaredField("mInitializationLooper");
field.setAccessible(true);
field2.setAccessible(true);
System.out.println("--handlerThread-lp--"+handlerThread.getLooper());
System.out.println("--main-lp--"+Looper.getMainLooper());
field2.set(field.get(audioRecorder1), handlerThread.getLooper());
audioRecorder1.setOutputFile("/mnt/sdcard/audio11.wav");
audioRecorder1.prepare();
audioRecorder1.start();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
使用 setRecordPositionUpdateListener时,要注意两个问题:
一:
1.启动录音后,要先read buffer,才会通知激活 listener。
audioRecord.startRecording();
audioRecord.read(buffer, 0, buffer.length);
2.录音 通知周期 及 录音数据读取 buffer 的设定(重点:audioRecord.read()读取的大小最好是设定的缓冲区的一半,效果会好多)
audioRecord.setPositionNotificationPeriod(framePeriod);//也可以自己指定一个buffer大小,但是不能小于min buffer
bufferSize = AudioRecord.getMinBufferSize(sampleRate,channelConfig, audioFormat);
int framePeriod=framePeriod = bufferSize / (2 * bSamples * nChannels / 8);
//读取录音数据 的buffer 应该为bufferSize/2,否则会出现stop后,数据延时与混乱(数据未正确写入文件)
buffer = new byte[framePeriod * bSamples / 8 * nChannels];//buffer = new byte[bufferSize/2]
二:
避免录音阻塞主线程,利用反射,更改AudioRecord 对象中的 mInitializationLooper(Looper 对象) 属性,为我们指定的子线程的 looper,然后再设置setRecordPositionUpdateListener(这个方法中会用到mInitializationLooper
对象)
audioRecorder1=AudioRecorder1.getInstanse();
HandlerThread handlerThread=new HandlerThread("handlerThread");
handlerThread.start();
...
//利用反射,更改属性,为指定子线程的looper
field2.set(field.get(audioRecorder1), handlerThread.getLooper());
//设置监听
audioRecorder1.prepare();
//prepare 方法的实现
public void prepare() {
try {
if (state == State.INITIALIZING) {
audioRecorder.setRecordPositionUpdateListener(updateListener);
audioRecorder.setPositionNotificationPeriod(framePeriod);
if ((audioRecorder.getState() == AudioRecord.STATE_INITIALIZED)
& (filePath != null)) {
// write file header
OutputStream out = new FileOutputStream(filePath);
out.write(1);
out.close();
random = new RandomAccessFile(filePath, "rw");
random.setLength(0); // Set file length to
random.writeBytes("RIFF");
......
具体细节如下
audioRecorder1=AudioRecorder1.getInstanse();
HandlerThread handlerThread=new HandlerThread("handlerThread");
handlerThread.start();
try {
Field field=audioRecorder1.getClass().getDeclaredField("audioRecorder");
Field field2=field.getType().getDeclaredField("mInitializationLooper");
field.setAccessible(true);
field2.setAccessible(true);
System.out.println("--handlerThread-lp--"+handlerThread.getLooper());
System.out.println("--main-lp--"+Looper.getMainLooper());
field2.set(field.get(audioRecorder1), handlerThread.getLooper());
audioRecorder1.setOutputFile("/mnt/sdcard/audio11.wav");
audioRecorder1.prepare();
audioRecorder1.start();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
相关文章推荐
- .NET数组使用中的注意事项小结
- 使用Castle.ActiveRecord的注意事项之一:总览
- CSS display:none使用注意事项小结
- 使用Castle.ActiveRecord的注意事项之一:总览
- 使用Castle.ActiveRecord的注意事项之四:using (new SessionScope(FlushAction.Never))
- Storm中Spout使用注意事项小结
- css display:none使用注意事项小结
- iphone上使用Sqlite的注意事项小结
- linux下使用ssh管理VPS的注意事项小结
- javascript中的注释使用与注意事项小结
- 使用Castle.ActiveRecord的注意事项三:继承
- 使用Castle.ActiveRecord的注意事项之二:级联
- iphone上使用Sqlite的注意事项小结like
- Hive - 建表和加载数据指令小结 以及使用Load data指令的注意事项
- 使用Castle.ActiveRecord的注意事项之二:级联
- 使用Castle.ActiveRecord的注意事项四:using (new SessionScope(FlushAction.Never))
- 使用Castle.ActiveRecord的注意事项之三:继承
- 使用Castle.ActiveRecord的注意事项之一:总览
- iphone上使用Sqlite的注意事项小结like
- 使用Castle.ActiveRecord的注意事项之三:继承