Android AudioRecord的问题?

dak*_*ira 5 audio android pcm sample-rate audiorecord

我一直在搞乱Android API的AudioRecord功能,并发现了一些奇怪的行为.

背景信息:我的手机是HTC Incredible我使用Eclipse插件进行Android开发与模拟器.目标平台或操作系统是2.2 ...因为它是我的手机使用的.

一些代码:

bufferSize = AudioRecord.getMinBufferSize(FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
Run Code Online (Sandbox Code Playgroud)

这是我用来设置AudioRecord API的代码.现在,对于模拟器,它将FREQUENCY设置为8000以使其工作.回来的缓冲区大小为640.对于手机,我使用44100.这里的一个问题是看起来波形的PCM数据似乎是8位有符号波.我得到的值从-127到128.我认为价值AudioFormat.ENCODING_PCM_16BIT会产生不同的东西.

我用线程处理音频,

public void run() {
  while(isRecording) {
    audioRecord.startRecording();
    byte[] data = new byte[bufferSize];
    audioRecord.read(data, 0, bufferSize);
    listener.setData(data);
    handleData(data);
  }
  audioRecord.release();
}
Run Code Online (Sandbox Code Playgroud)

我有一种方法可以使用a以图形方式实时显示相应的波形SurfaceView.MIC似乎有很多噪音.我也从模拟器和手机中得到了这个噪音.我是否需要通过某种过滤器运行数据?我想用这些数据计算一些有趣的FFT和东西只是为了解决这个问题.但我需要以某种方式减少噪音.

有没有其他人经历过这一点.有没有人有办法解决吗?

我很感激你的时间和回应,谢谢,dk

Gra*_*ers 12

当您从"AudioFormat.ENCODING_PCM_16BIT"流中读取字节时,它实际上将每个样本的高字节和低字节都作为2个连续字节.如果你只是将每个字节作为一个样本(而不是它实际上的一半样本),这似乎是非常嘈杂的,加上第一个字节的签名将是错误的(它以小端顺序).

要从流中获取有意义的数据,请通过短路读取,例如

public void run() {
  while(isRecording) {
    audioRecord.startRecording();
    short[] data = new short[bufferSize/2];
    audioRecord.read(data, 0, bufferSize/2);
    listener.setData(data);
    handleData(data);
  }
  audioRecord.release();
}
Run Code Online (Sandbox Code Playgroud)


小智 9

问这个问题已经有一段时间了,所以我不知道是否再回答这个问题.

您从-127到128获取值的原因是您正在读取一个字节数组,每个字节都包含一个带符号的8位数字.对于16位音频,读入一组短路.

我恐怕无法帮助解决噪音问题.

  • Peter,就这样考虑一下,如果他使用每个样本的低字节,那么这些值会非常嘈杂,因为应该有8个更高字节的更高幅度信息.这些信息会更加一致.我假设'短'调整也解决了噪音问题. (4认同)

Tom*_*Tom 3

我也许能帮上一点忙。不过我的情况和你一样,所以我只能告诉你我的经历。

我相信您可以像这样获得设备的首选 SampleRate:

int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
Run Code Online (Sandbox Code Playgroud)

16Bit 编码模式是唯一适用于 AudioRecord 的编码模式。我不确定为什么你会得到类似 8Bit 的输出(对吗?)。也许有人知道。

我也不确定你如何从检索到的字节中提取幅度,你这样做了吗?

最后,我相信您需要使用周期性侦听器函数,如下所示:

int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
int channelMode = AudioFormat.CHANNEL_IN_MONO;
int encodingMode = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelMode, encodingMode);

AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelMode, encodingMode, bufferSize);

recorder.setPositionNotificationPeriod(intervalFrames);
recorder.setRecordPositionUpdateListener(recordListener);
recorder.startRecording();

private RecordListener recordListener = new RecordListener();
private class RecordListener implements AudioRecord.OnRecordPositionUpdateListener {
    public void onMarkerReached(AudioRecord recorder) {
        Log.v("MicInfoService", "onMarkedReached CALL");
    }

    public void onPeriodicNotification(AudioRecord recorder) {
        Log.v("MicInfoService", "onPeriodicNotification CALL");
    }
}
Run Code Online (Sandbox Code Playgroud)

这里有两个大问题我无法回答,也想知道我自己的答案:

  1. 间隔帧应该设置什么?
  2. 为什么监听器方法从未被调用?

我希望我能提供更多帮助。

  • IntervalFrames 是您想要通知的样本数,如果您以 8000 进行采样,则 IntervalFrames = 4000 将每 1/(8000/4000) = 0.5 秒调用一次通知侦听器。您需要开始读取要调用的侦听器函数,还需要确保读取缓冲区大小 >= IntervalFrames。 (3认同)