在Android 2.2中从麦克风录制时出现奇怪的失真

在Android 2.2中从麦克风录制时出现奇怪的失真,android,audio,audiorecord,Android,Audio,Audiorecord,我有一个应用程序可以从麦克风录制音频,然后对音频进行实时后处理,因此我必须使用AudioRecord类,而不是标准的MediaRecorder。我的录音代码如下: DataOutputStream dataOutputStreamInstance = new DataOutputStream(bufferedStreamInstance); android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT

我有一个应用程序可以从麦克风录制音频,然后对音频进行实时后处理,因此我必须使用
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();
DataOutputStream dataOutputStreamInstance=新的DataOutputStream(bufferedStreamInstance);
android.os.Process.setThreadPriority(android.os.Process.THREAD\u PRIORITY\u emergency\u AUDIO);
int bufferSize=AudioRecord.getMinBufferSize((int)采样器,通道配置,默认音频编码)*2;
short[]麦克风缓冲区=新的short[bufferSize];
float[]processingBuffer=新的float[bufferSize];
short[]outputBuffer=新的short[bufferSize];
AudioRecord麦克风记录=新的音频记录(MediaRecorder.AudioSource.MIC,44100,AudioFormat.CHANNEL\u CONFIGURATION\u MONO,AudioFormat.ENCODING\u PCM\u 16位,缓冲区大小);
microMoneCorder.startRecording();
while(isRecording){
已同步(互斥){…检查暂停条件、等待等…}
int numSamplesRead=micromonerecorder.read(micromonebuffer,0,bufferSize);
//将16位短数据转换为浮点
getFloatingPointBufferFromPcmData(麦克风缓冲区、处理缓冲区、缓冲区大小);
doProcessingStaff(processingBuffer,bufferSize);
if(numSamplesRead==AudioRecord.ERROR\u无效\u操作){
抛出新的IllegalStateException(“read()返回音频记录。错误\u无效\u操作”);
}
else if(numSamplesRead==录音。错误\u错误\u值){
抛出新的非法状态异常(“read()返回了AudioRecord.ERROR\u BAD\u VALUE”);
}
试一试{
//以16位短格式将输出转储到目标文件
getShortPcmBufferFromFloatingPointData(processingBuffer、outputBuffer、bufferSize);
对于(int bufferIndex=0;bufferIndex
上面的代码工作正常,我可以从设备上录制音频,我可以听到我的声音等等。问题是,几秒钟后,一种非常奇怪的失真模式开始出现,直到整个信号被淹没。下面是一个沉默录音的截图,我在麦克风上放了一些磁带,让应用程序录制一分钟左右:

原始wave文件可以是


由于我的效果处理代码,问题肯定是而不是,因为我已经试着对它进行注释,并且在这两种情况下都得到了相同的结果。我在网络上搜索过其他代码或可能遇到类似问题的人,但没有找到任何东西。

我根本不知道Android SDK,但是
getFloatingPointBufferFromPcmData
getShortPcmBufferFromFloatingPointData
看起来不像标准API函数,尽管有可爱的命名约定。:)

这些是你自己写的吗?也许他们正在使用共享状态并在循环迭代中累积结果?如果这些是您的实现,请共享这些实现的代码,以便我们可以帮助您确定实际问题

还有一种可能性是,您正在以错误的格式(位数、endianness)写入PCM数据,并且您的音频编辑器正在根据不同的格式解释数据,从而导致错误解码的音频数据,这看起来像是发生了某种累积效应

如果这两个查询都不能解决您的问题,那么我的下一个建议是为每个循环迭代创建一个新的microhonebuffer实例,而不是在while循环中使用单个实例

再说一次,我不是Android SDK专家,所以这些只是多年来处理各种API及其实现细节的经验得出的一般性建议


希望这有助于诊断您的问题

在静音模式下,可能会有一个自动增益控制,它会毫无理由地增加输入增益,试图找到“某些东西”供您记录(当然还有找到噪声地板)


如果你把你的电脑扬声器设置成播放一个很好的音频正弦波,会发生什么?噪音还是继续录正弦波?

Bah,事实上问题不是安卓的错——这是由我用来将原始PCM数据转换成WAV格式的软件引起的。由于ARM芯片是大端数,WAV是小端数,因此端数转换显然存在一些错误。当我们尝试在Audacity中打开原始PCM文件时,它们看起来很好。

谢谢您的建议。缓冲区转换函数和格式转换都没有问题(请参见我自己的答案)。然而,我确实添加了一个额外的检查,以查看从麦克风读取的字节数是否与预期的相同。令我惊讶的是,Android通常返回的字节数少于要求的字节数,因此我相应地修改了代码。缩短几个字节我认为不应导致您看到的这种累积效应。您是否尝试过将麦克风缓冲区(重新)分配移动到循环内?实际上,上面的代码工作得很好,假设我将
numSamplesRead
而不是
bufferSize
传递给缓冲区转换和处理函数。在我看到您解决了原始问题之前,我就发布了这篇文章。实际上,我确实建议了一些类似的问题;)是的,没错但是,这个bug出现在转换软件中,而不是我的Android代码中。不过,我确实对你的答案投了赞成票,因为它让我看到了正确的方向。