调节Android AudioTrack的播放速度

时间:2018-07-13 06:50:27

标签: android streaming audiotrack

我目前正在尝试使用AudioTrack播放音频。音频通过网络接收,应用程序连续读取数据并添加到内部缓冲区。一个单独的线程正在消耗数据并使用AudioTrack进行播放。

问题:

  1. 音频播放会不断波动(感觉到音频以固定的间隔下降),使声音不清楚。
  2. 播放速度太快或太慢,使它们不切实际。

为了避免网络延迟和其他因素,我让应用程序等待,直到它读取足够的数据并在最后播放为止。

这使音频播放非常快。这是我使用的基本逻辑示例。

    sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT),
                    AudioTrack.MODE_STREAM);
audioTrack.play();

short shortBuffer[] = new short[AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT)];
while (!stopRequested){
    readData(shortBuffer);
    audioTrack.write(shortBuffer, 0, shortBuffer.length, AudioTrack.WRITE_BLOCKING);
}

说Android AudiTrack类没有内置功能可以根据环境条件控制音频播放是否正确?如果是这样,是否有更好的库以简化的方式播放音频?

2 个答案:

答案 0 :(得分:0)

就像@pskink用户所说的

  

您的sampleRate(或传递给   AudioTrack构造函数)无效。

因此,我将从检查您实际设置采样率的值开始。

作为参考,您还可以通过调用AudioTrack方法来设置setPlayBackParams的速度:

public void setPlaybackParams (PlaybackParams params)

如果选中AudioTrack docs,则可以看到PlaybackParams docs,并可以设置输出音频的speedpitch。然后可以传递该对象以在AudioTrack对象中设置播放参数。

但是,如果唯一的问题是原始构造函数sampleRate,则不太可能需要使用它(因为我们无法看到变量sampleRate的来源)。

答案 1 :(得分:0)

我看到的第一个问题是任意采样率。

AudioTrack.getNativeOutputSampleRate将返回声音系统使用的采样率。它可以是44100、48000、96000、192000或其他任何值。但是看起来您有来自某些独立来源的音频数据,它们以非常精确的采样率生成数据。

比方说,来自源的音频数据以每秒44100个样本进行采样。如果您从96000开始播放,它将加快速度并提高音调。

因此,请使用源提供的采样率设置以及通道数,采样格式等,而不依赖于系统默认值。

第二个:您确定readData过程始终足够快以成功填充缓冲区,无论缓冲区有多小,并且返回速度都比缓冲区播放的快?

您已经创建了AudioTrack,其中AudioTrack.getMinBufferSize是通过bufferSizeInBytes参数传递的。

getMinBufferSize函数返回可用于此参数的缓冲区的最小可能大小。假设它返回的大小对应于10ms长度的缓冲区。 这意味着应在此时间间隔内准备新数据。即先前返回的write返回控件和执行新的write之间的时间间隔应小于缓冲区的时间大小。

因此,如果readData功能由于某种原因可能会比该时间间隔更长的时间延迟,则播放将暂停该时间,您会听到播放中的小间隙。

readData可能延迟的原因可能多种多样:如果它正在从文件中读取数据,则可能会延迟等待IO操作;如果它分配了Java对象,则可能会碰到垃圾回收器的延迟;如果它使用自己的缓冲的另一种音频源的解码器,则可能会定期延迟重新填充缓冲。

但是无论如何,如果您没有创建某种实时合成器,应该对用户输入做出尽快反应,请始终使用合理的缓冲区大小,但不要小于返回的getMinBufferSize。即:

sampleRate = 44100;// sampling rate of the source

int bufSize = sampleRate * 4; // 1 second length; 4 - is the frame size: 2 chanels * 2 bytes per each sample
bufSize = max(bufSize, AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT)); // Not less than getMinBufferSize returns
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT,
                bufSize,
                AudioTrack.MODE_STREAM);