在 Android 2.2 中从麦克风录制时出现奇怪的失真
Posted
技术标签:
【中文标题】在 Android 2.2 中从麦克风录制时出现奇怪的失真【英文标题】:Strange distortion while recording from microphone in Android 2.2 【发布时间】:2010-10-14 14:53:37 【问题描述】:我有一个应用程序可以从麦克风录制音频,然后实时对音频执行一些后处理,所以我必须使用AudioRecord
类而不是标准的MediaRecorder
。我的录制代码是这样的:
DataOutputStream dataOutputStreamInstance = new DataOutputStream(bufferedStreamInstance);
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
int bufferSize = AudioRecord.getMinBufferSize((int)sampleRate, channelConfiguration, DEFAULT_AUDIO_ENCODING) * 2;
short[] microphoneBuffer = new short[bufferSize];
float[] processingBuffer = new float[bufferSize];
short[] outputBuffer = new short[bufferSize];
AudioRecord microphoneRecorder = new AudioRecord(MediaRecorder.Audiosource.MIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
microphoneRecorder.startRecording();
while(isRecording)
synchronized(mutex) ... check for pause condition, wait, etc. ...
int numSamplesRead = microphoneRecorder.read(microphoneBuffer, 0, bufferSize);
// Convert 16-bit short data to floating point
getFloatingPointBufferFromPcmData(microphoneBuffer, processingBuffer, bufferSize);
doProcessingStuff(processingBuffer, bufferSize);
if(numSamplesRead == AudioRecord.ERROR_INVALID_OPERATION)
throw new IllegalStateException("read() returned AudioRecord.ERROR_INVALID_OPERATION");
else if(numSamplesRead == AudioRecord.ERROR_BAD_VALUE)
throw new IllegalStateException("read() returned AudioRecord.ERROR_BAD_VALUE");
try
// Dump the output to the target file in 16-bit short format
getShortPcmBufferFromFloatingPointData(processingBuffer, outputBuffer, bufferSize);
for(int bufferIndex = 0; bufferIndex < numSamplesRead; bufferIndex++)
dataOutputStreamInstance.writeShort(outputBuffer[bufferIndex]);
catch(Exception e)
Log.e("MyApp", "Error while writing audio data to file: " + e.getMessage());
e.getStackTrace();
microphoneRecorder.stop();
上面的代码工作正常,我实际上可以从设备录制音频,我听到我的声音等等。问题是,几秒钟后,一种非常奇怪的失真模式开始出现,直到整个信号被淹没。这是我通过将一些磁带放在麦克风上并让应用程序录制一分钟左右来制作的静音录音的屏幕截图:
原始波形文件可以是downloaded here。
由于我的效果处理代码,问题绝对不是,因为我尝试将其注释掉并在两种情况下得到相同的结果。我在网上搜索了其他代码或可能遇到类似问题的人,但没有找到任何东西。
【问题讨论】:
【参考方案1】:我根本不了解 Android SDK,但 getFloatingPointBufferFromPcmData
和 getShortPcmBufferFromFloatingPointData
看起来不像标准 API 函数,尽管命名约定很好。 :)
这些是你自己写的吗?也许他们正在使用共享状态并在循环迭代中累积结果?如果这些是您的实现,请分享这些代码,以便我们帮助您确定实际问题。
还有可能您以错误的格式(位数、字节序)写出 PCM 数据,并且您的音频编辑器正在根据不同的格式解释数据,从而导致出现错误解码的音频数据好像发生了某种累积效应。
如果这些查询都不能帮助您解决问题,那么我的下一个建议是为每个循环迭代创建一个新的麦克风缓冲区实例,而不是在 while 循环中使用单个实例。
再次重申,我不是 Android SDK 专家,因此这些只是根据多年处理几乎所有类型的 API 及其实现细节的经验得出的一般性建议。
希望这有助于诊断您的问题!
【讨论】:
感谢您的建议。任何一个缓冲区转换函数都没有问题,格式转换也没有问题(请参阅我自己的答案)。但是,我确实添加了额外的检查,以查看从麦克风读取的字节数与预期的相同,令我惊讶的是,Android 通常返回的字节数少于要求的字节数,因此我相应地调整了我的代码。 缩短几个字节我认为不会导致您看到的这种累积效应。您是否尝试过将麦克风缓冲区(重新)分配移动到循环内? 其实上面的代码工作得很好,假设我将numSamplesRead
而不是bufferSize
传递给缓冲区转换和处理函数。
我在看到您解决原始问题之前发布了该内容。【参考方案2】:
在静音的情况下,可能会有一个自动增益控制,它会超出合理地增加输入增益,试图找到“东西”让你记录(当然还有找到本底噪声)
如果您将 PC 扬声器设置为播放美妙的音频正弦波会发生什么 - 噪音仍然出现还是您继续记录正弦波?
【讨论】:
【参考方案3】:呸,实际上问题不是 Android 的问题——它是由我用来将原始 PCM 数据转换为 WAV 格式的软件引起的。由于ARM芯片是大端,WAV是小端,字节序转换显然有一些错误。当我们尝试在 Audacity 中打开原始 PCM 文件时,它们看起来很好。
【讨论】:
我确实提出了一些类似这些问题的建议;) 是的,没错。 :) 但是,错误出在转换软件中,而不是我的 Android 代码中。不过,我确实赞成你的回答,因为它让我找到了正确的方向。以上是关于在 Android 2.2 中从麦克风录制时出现奇怪的失真的主要内容,如果未能解决你的问题,请参考以下文章
尝试从屏幕+麦克风录制流时出现“DOMException:因关机而失败”
将 AVAudioSession 模式设置为 AVAudioSessionModeVideoChat 时出现麦克风低语音录制问题