Android AudioTrack.write()在播放整个缓冲区后返回

时间:2016-09-28 08:26:16

标签: android audio audiotrack

AudioTrack.write()。 Android文档说明

  

在流媒体模式下,写入通常会阻塞,直到所有数据都已排入队列进行播放,并且将返回完整的传输计数。

但是,在我的代码中,write()方法似乎要等到播放整个缓冲区,直到从扬声器开始。因此,例如,之后调用stop()方法或填充更多数据是不可能的。

录音带由以下内容初始化:

int mBufferSize = AudioTrack.getMinBufferSize(44100,
        AudioFormat.CHANNEL_OUT_MONO,
        AudioFormat.ENCODING_PCM_8BIT);
AudioTrack mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
        AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
        mBufferSize, AudioTrack.MODE_STREAM);
int duration = 44100*5;
short[] mBuffer = new short[duration];

on onCreate:

for (int i = 0; i < wavelength; i++) {
        waveform[i] = Math.sin(((double) i)/wavelength * 2 * Math.PI - Math.PI);
}
mAudioTrack.play();

点击一下按钮,这叫做:

private void playSound(double frequency, int duration) {
    int idx = 0;
    for (int i = 0; i < duration-1; i++) {
        idx = idx + (int) Math.ceil(frequency);
        if (idx > wavelength-1)
            idx = idx % wavelength;
        mBuffer[i] = (short) (waveform[idx] * Short.MAX_VALUE);
    }
    long startTime = System.currentTimeMillis();
    ret = mAudioTrack.write(mBuffer, 0, mBuffer.length);
    long runtime = System.currentTimeMillis() - startTime;
    debugText.setText(Long.toString(runtime));
}

时间戳显示write()调用只花了5秒钟,这是音频片段的长度,我不相信传输时间会完全相同。我想生成更多要播放的数据(可能是另一个频率),而之前的数据仍然在播放。我知道有些开发人员使用多个线程(我没有线程经验,所以我不知道怎么做),但是文档表明它也可能这样......

1 个答案:

答案 0 :(得分:1)

AudioTrack.write(...)的调用将阻塞,直到所有提供的数据都被复制到AudioTrack的流式缓冲区中。 AudioTrack缓冲区的大小(上面mBufferSize)设置为AudioTrack.getMinBufferSize(...),因此显然很小,肯定只有一秒钟的音频。

您想要入队的5秒音频数据显然不适合这么小的缓冲区。所以AudioTrack.write(...)必须重复填充该缓冲区,因为它正在被播放耗尽。在它返回之前,它必须将音频数据的最后部分排入队列。在它可以做到这一点之前,它必须至少等待除了最后mBufferSize个音频数据之外的所有内容。

如果您按不同金额增加mBufferSize,您应该开始看到AudioTrack.write来电阻止的时间更短。