实时播放麦克风发出的声音

时间:2011-04-20 09:52:28

标签: android audio real-time record audio-recording

我一直在努力让我的应用程序录制来自麦克风的声音并以(近似)实时播放,但是没有成功。

我分别使用AudioRecord和AudioTrack类进行录制和播放。我尝试了不同的方法,我试图记录传入的声音并将其写入文件,它工作正常。我也尝试使用AudioTrack播放该文件后的声音,它也可以正常工作。问题是当我尝试实时播放声音时,而不是在写完文件后读取。

以下是代码:

//variables
private int audioSource = MediaRecorder.AudioSource.MIC;
private int samplingRate = 44100; /* in Hz*/
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private int bufferSize = AudioRecord.getMinBufferSize(samplingRate, channelConfig, audioFormat);
private int sampleNumBits = 16;
private int numChannels = 1;

// …

AudioRecord recorder = new AudioRecord(audioSource, samplingRate, channelConfig, audioFormat, bufferSize);
                recorder.startRecording();
                isRecording = true;

AudioTrack audioPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                        AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);

if(audioPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING)
    audioPlayer.play();

//capture data and record to file
int readBytes=0, writtenBytes=0;
do{
   readBytes = recorder.read(data, 0, bufferSize);

   if(AudioRecord.ERROR_INVALID_OPERATION != readBytes){
      writtenBytes += audioPlayer.write(data, 0, readBytes);
   }
}
while(isRecording);

抛出java.lang.IllegalStateException,原因是由未初始化的AudioTrack上调用的“play()”引起的。

但是,如果我更改AudioTrack初始化,例如使用8000Hz的采样率和8位样本格式(而不是16位),它不再抛出异常并且应用程序运行,尽管它会产生可怕的噪音。

当我从一个文件播放AudioTrack时,AudioTrack的初始化没有问题,我尝试了44100和16位并且它正常工作,产生正确的声音。

任何帮助?

4 个答案:

答案 0 :(得分:29)

所有原生Android音频均为encoded。您只能实时播放PCM格式,或使用特殊的streaming编解码器,我认为这在Android上并不重要。

关键是如果你想同时录制/播放音频,你必须创建自己的音频缓冲区并在那里存储原始PCM编码的音频样本(我不确定你是否在考虑呃!或者这是否完全在你头上,所以我会尽量清楚但不要嚼自己的口香糖。)

PCM是模拟信号的数字表示,其中音频samples是原始声波的一组“快照”。因为各种聪明的数学家和工程师都看到了尝试减少代表这些数据的位数的潜力,所以他们提出了各种encoders。编码(压缩)信号的表示与原始PCM信号非常不同,必须进行解码(en- cod -er + dec -oder = codec )。除非您使用特殊算法和媒体流编解码器,否则无法像您尝试的那样回放编码信号,因为它不是逐个样本编码,而是逐帧编码,您需要整个样本帧,如果不是完整的信号,则解码此帧。

这样做的方法是手动存储来自麦克风缓冲区的音频样本并手动将它们输入到输出缓冲区。您将不得不为此做一些编码,但我相信有一些开源应用程序可供您查看并在其源头达到高峰(除非您愿意稍后出售您的应用程序,当然,但那是一个完全不同的讨论)。

如果您正在为Android 2.3或更高版本开发并且不太害怕native code中的编程,则可以尝试使用OpenSL ES。 OpenSL ES的Android特定功能列于here。如果你的应用程序高度依赖音频处理,这个平台可以让你获得更灵活的音频操作,你可能会发现你需要的东西。

答案 1 :(得分:3)

  

抛出java.lang.IllegalStateException,原因是   由未播放的AudioTrack上的“play()”引起的。

这是因为缓冲区大小太小。我试过“bufferSize + = 2048;”,没关系。

答案 2 :(得分:0)

我遇到了类似的问题,我通过将此权限添加到清单文件来解决它:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

答案 3 :(得分:0)

确保您的var数据足以进行采样 例如:如果您使用amplingRate作为44100,则数据字节数组的长度应为44101或更大