Android AudioTrack.write() returns 播放整个缓冲区后
Android AudioTrack.write() returns after playing the whole buffer
AudioTrack.write()。 Android 文档说
In streaming mode, the write will normally block until all the data has been enqueued for playback, and will return a full transfer count.
但是,在我的代码中,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];
在 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 秒,这是音频剪辑的长度,我不相信传输时间会完全相同。我想在之前的数据仍在播放的同时生成更多要播放的数据(可能以其他频率)。我知道一些开发人员使用多线程(我没有线程方面的经验,所以我不知道该怎么做),但是文档表明也可以这样...
对 AudioTrack.write(...)
的调用会阻塞,直到所有提供的数据都已复制到 AudioTrack 的流缓冲区中。 AudioTrack 缓冲区的大小(mBufferSize
以上)设置为 AudioTrack.getMinBufferSize(...)
,因此显然很小,肯定只够播放几分之一秒的音频。
您要入队的 5 秒音频数据显然放不下这么小的缓冲区。因此 AudioTrack.write(...)
必须重复填充该缓冲区,因为它正在被播放耗尽。在它可以 return 之前,它必须将音频数据的最后一部分排入队列。在它可以这样做之前,它必须至少等到除了最后一个 mBufferSize
音频数据之外的所有内容都已播放。
如果您将 mBufferSize
增加不同的数量,您应该会开始看到 AudioTrack.write
呼叫阻塞的时间减少。
AudioTrack.write()。 Android 文档说
In streaming mode, the write will normally block until all the data has been enqueued for playback, and will return a full transfer count.
但是,在我的代码中,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];
在 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 秒,这是音频剪辑的长度,我不相信传输时间会完全相同。我想在之前的数据仍在播放的同时生成更多要播放的数据(可能以其他频率)。我知道一些开发人员使用多线程(我没有线程方面的经验,所以我不知道该怎么做),但是文档表明也可以这样...
对 AudioTrack.write(...)
的调用会阻塞,直到所有提供的数据都已复制到 AudioTrack 的流缓冲区中。 AudioTrack 缓冲区的大小(mBufferSize
以上)设置为 AudioTrack.getMinBufferSize(...)
,因此显然很小,肯定只够播放几分之一秒的音频。
您要入队的 5 秒音频数据显然放不下这么小的缓冲区。因此 AudioTrack.write(...)
必须重复填充该缓冲区,因为它正在被播放耗尽。在它可以 return 之前,它必须将音频数据的最后一部分排入队列。在它可以这样做之前,它必须至少等到除了最后一个 mBufferSize
音频数据之外的所有内容都已播放。
如果您将 mBufferSize
增加不同的数量,您应该会开始看到 AudioTrack.write
呼叫阻塞的时间减少。