【问题标题】:Playing back sound coming from microphone in real-time实时播放来自麦克风的声音
【发布时间】:2011-08-09 08:45:23
【问题描述】:

我一直试图让我的应用程序记录来自麦克风的声音并(大约)实时回放,但没有成功。

我分别使用 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 位,它工作正常,产生了正确的声音。

有什么帮助吗?

【问题讨论】:

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


    【解决方案1】:

    确保您的 var 数据足以用于 samplingRate 例如:如果您使用 samplingRate 为 44100 您的数据字节数组的长度应该是 44101 或更多

    【讨论】:

      【解决方案2】:

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

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

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

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

      如果您正在为 Android 2.3 或更高版本进行开发并且不太害怕使用 native code 进行编程,您可以尝试使用 OpenSL ES。 OpenSL ES 的 Android 特定功能在here 中列出。该平台允许您更灵活地处理音频,如果您的应用高度依赖音频处理,您可能会找到所需的内容。

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 是你需要的。
        【解决方案4】:

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

        这是因为缓冲区大小太小。我试了“bufferSize += 2048;”,就可以了。

        【讨论】:

        • +1。我有同样的问题。用更大的缓冲区大小初始化AudioTrack 解决了这个问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-22
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多