Android AudioRecord 问题?
Posted
技术标签:
【中文标题】Android AudioRecord 问题?【英文标题】:Android AudioRecord questions? 【发布时间】:2011-06-10 03:06:17 【问题描述】:我一直在搞乱 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);
这是我用来设置 AudioRecord API 的代码。现在,对于模拟器来说,它喜欢将 FREQUENCY 设置为 8000 以使其工作。返回缓冲区大小 640。对于手机,我使用 44100。这里的一个问题是,波形的结果 PCM 数据似乎是八位有符号波形。我得到从 -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();
我有一种方法可以使用SurfaceView
以图形方式实时显示到相应的波形。 MIC 似乎有很多噪音。我也从模拟器和手机中得到这种噪音。我是否需要通过某种过滤器运行数据?我想用这些数据来计算一些有趣的 FFT 和一些东西,只是为了玩波。但我需要以某种方式减少噪音。
有没有其他人也遇到过这种情况。有人有解决办法吗?
感谢您的时间和回复, 谢谢, dk
【问题讨论】:
【参考方案1】:当您从“AudioFormat.ENCODING_PCM_16BIT”流中读取字节时,它实际上为您提供了每个样本的高字节和低字节作为 2 个连续字节。如果您只是将每个字节作为样本(而不是实际上的一半样本),这看起来会非常嘈杂,而且第一个字节的签名将是错误的(它是 little endian 顺序)。
要从流中获取有意义的数据,请通过短裤读取,例如
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();
【讨论】:
在这种情况下监听器会做什么......?我也有类似的问题,请查看我的问题***.com/questions/9413998/…【参考方案2】:这个问题被问到已经有一段时间了,所以我不知道回答这个问题是否有意义。
您获得从 -127 到 128 的值的原因是您正在读取一个字节数组,每个字节都包含一个有符号的 8 位数字。对于 16 位音频,读入一个 short 数组。
恐怕我无法解决噪音问题。
【讨论】:
彼得,这样想,如果他使用每个样本的低字节,那么这些值会非常嘈杂,因为应该还有 8 个字节的更高幅度信息。这些信息会更加一致。我假设“短”调整也解决了噪音问题。 @mike,我也有类似的问题,请查看我的问题***.com/questions/9413998/…....帮助!!!【参考方案3】:我也许能帮上一点忙。不过,我的情况和你一样,所以我只能告诉你我的经历。
我相信您可以像这样获得设备的首选 sampleRate:
int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
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");
这里有两个大问题我无法回答,也想知道自己的答案:
-
intervalFrames 应该设置什么?
为什么从不调用监听器方法?
我希望我能提供更多帮助。
【讨论】:
我已经使用一些 FFT 技术降低了噪音,并且我有一些代码示例说明如何。我现在正在旅行,但想在我回来时继续讨论。感谢您的意见。 intervalFrames 是您希望收到通知的样本数,如果您以 8000 采样,intervalFrames = 4000 将每 1/(8000/4000) = 0.5 秒调用一次通知侦听器。您需要开始读取以调用侦听器函数,还需要确保您的读取缓冲区大小 >= intervalFrames。 +1 for getNativeOutputSampleRate();你是如何解决你的问题的?我也在为类似的问题而苦苦挣扎? ***.com/questions/9413998/… 我无法使用 getNativeOutputSampleRate() 在模拟器中创建 AudioRecord 实例...有人能说出原因吗?2. Why are the listener methods never called?
。这是因为你必须在开始录制后立即调用read()。即在达到间隔后调用监听器(interval - 从AudioRecord读取intervalFrames。)aRecorder.startRecording(); aRecorder.read(buffer, 0, buffer.length);
如果添加此行,将调用回调【参考方案4】:
这个开源项目有大量的帮助类来帮助你获取音频数据并尝试分析它:
https://github.com/gast-lib/gast-lib
它有一个AsyncTask
它有一些东西可以控制AudioRecorder
它甚至有一个simple frequency estimation algorithm
【讨论】:
以上是关于Android AudioRecord 问题?的主要内容,如果未能解决你的问题,请参考以下文章
Android:AudioRecord 类问题:从不调用回调
无法在 Android 中使用 AudioRecord 进行录制
在 Android 上更改 AudioRecord 的比特率