实时播放来自麦克风的声音 [英] Playing back sound coming from microphone in real-time

查看:35
本文介绍了实时播放来自麦克风的声音的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我分别使用 AudioRecord 和 AudioTrack 类进行录制和播放.我尝试了不同的方法,我尝试记录传入的声音并将其写入文件,并且效果很好.我还尝试在使用 AudioTrack 之后播放该文件中的声音,它也运行良好.问题是当我尝试实时播放声音时,而不是在写入文件后读取.

代码如下:

//变量private int audioSource = MediaRecorder.AudioSource.MIC;私有整数采样率 = 44100;/* 以赫兹为单位 */private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;private int bufferSize = AudioRecord.getMinBufferSize(samplingRate, channelConfig, audioFormat);私人 int sampleNumBits = 16;私人 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)音频播放器.播放();//捕获数据并记录到文件int readBytes=0,writeBytes=0;做{readBytes = recorder.read(data, 0, bufferSize);if(AudioRecord.ERROR_INVALID_OPERATION != readBytes){writeBytes += audioPlayer.write(data, 0, readBytes);}}while(isRecording);

抛出 java.lang.IllegalStateException 异常,原因是在未初始化的 AudioTrack 上调用了 play()".

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

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

有什么帮助吗?

解决方案

所有原生 Android 音频都是 编码.您只能实时播放 PCM 格式,或使用特殊的 streaming 编解码器,我认为这在 Android 上不是微不足道的.

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

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

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

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

I've been trying to get my application recording the sound coming from the microphone and playing it back in (approximately) real-time, however without success.

I'm using AudioRecord and AudioTrack classes for record and playback, respectively. I've tried different approaches, I've tried to record the incoming sound and write it to a file and it worked fine. I've also tried to playback sound from that file AFTER with AudioTrack and it worked fine too. The problem is when I try to play the sound in real-time, instead of reading a file after it's written.

Here is the code:

//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);

It is thrown a java.lang.IllegalStateException with the reason being caused by "play() called on a uninitialized AudioTrack".

However, if I change the AudioTrack initialization for example to use sampling rate 8000Hz and sample format 8 bits (instead of 16), it doesn't throw the exception anymore and the application runs, although it produces horrible noise.

When I play AudioTrack from a file, there is no problem with the initialization of the AudioTrack, I tried 44100 and 16 bits and it worked properly, producing the correct sound.

Any help ?

解决方案

All native Android audio is encoded. You can only play out PCM formats in real time, or use a special streaming codec, which I don't think is trivial on Android.

The point is that if you want to record/play out audio simultaneously, you would have to create your own audio buffer and store raw PCM-encoded audio samples in there (I'm not sure if you're thinking duh! or whether this is all over your head, so I'll try to be clear but not to chew your own gum).

PCM is a digital representation of an analog signal in which your audio samples are a set of "snapshots" of the original acoustic wave. Because all kinds of clever mathematicians and engineers saw the potential in trying to reduce the number of bits you represent this data with, they came up with all sorts of encoders. The encoded (compressed) signal is represented very differently from the raw PCM signal and has to be decoded (en-cod-er+dec-oder = codec). Unless you're using special algorithms and media streaming codecs, it's impossible to play back an encoded signal like you're trying to, because it's not encoded sample by sample, but rather frame by frame, where you need the whole frame of samples, if not the complete signal, to decode this frame.

The way to do it is to manually store audio samples coming from the microphone buffer and manually feeding them to the output buffer. You will have to do some coding for that, but I believe there are some open-source apps that you can look at and take a peak at their source (unless you're willing to sell your app later on, of course, but that's a whole different discussion).

If you're developing for Android 2.3 or later and are not too scared of programming in native code, you can try using OpenSL ES. The Android-specific features of OpenSL ES are listed here. This platform allows you somewhat more flexible audio manipulation and you might find just what you need, if your app will be highly reliant on audio processing.

这篇关于实时播放来自麦克风的声音的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆