我正在尝试通过服务器将音频发送到我播放的Android手机(流媒体)。 服务器每50毫秒发送一次音频字节。
此解决方案有效,但不适合(在同一循环中接收和写入录音带(写作需要一些时间))
private class SoundTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
[...]
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 16000,4, AudioFormat.ENCODING_PCM_16BIT, BUF_SIZE, AudioTrack.MODE_STREAM);
[...]
byte[] output;
at.play();
byte[] buf = new byte[BUF_SIZE];
//Here is the loop
while(true)
{
DatagramPacket pack = new DatagramPacket(buf, BUF_SIZE);
socket.receive(pack);
at.write(pack.getData(), 0, pack.getLength());
}
}
}
所以我尝试将接收和写入分成两个线程,但它不起作用,声音在几秒钟之后就会断电!
我的两个线程(使用ArrayBlockingQueue)
制片人:
public void run() {
[...]
byte[] buf = new byte[bufferSize];
while(true)
{
DatagramPacket pack = new DatagramPacket(buf, bufferSize);
socket.receive(pack);
queueAudio.put(pack);
}
}
消费者:
public void run() {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 16000, 4, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
audioTrack.play();
while(true)
{
DatagramPacket packet;
try
{
packet = queueAudio.take();
audioTrack.write(packet.getData(), 0, packet.getData().length);
}
我注意到当我的队列大小等于1时声音是正常的,当它高于1时(2-3秒后)声音不稳定。
有人可以向我解释为什么我的录音机不工作? 提前谢谢!
编辑:
好的,我明白了这个问题。问题来自UDP数据包的接收,通常我每50毫秒接收一次数据包。
我计算接收两个数据包之间的时间间隔,看来有时候这个时间间隔优于100毫秒,之后就不到1毫秒!!!
当发生这种情况时,声音变得不稳定。我简单地解决了这个问题:当间隔小于1毫秒时,我不会将数据放入队列中。
这样可行,声音不会起伏不定,但有时候会有很少的声音。
我该如何解决这个问题?有没有办法定期接收我的UDP数据包?我应该尝试在服务中进行接收吗?
答案 0 :(得分:1)
您应该为AudioTrack使用比您写入的块大小更大的缓冲区大小。来自AudioTrack类的文档:
bufferSizeInBytes 读取音频数据以进行播放的内部缓冲区的总大小(以字节为单位)。如果track的创建模式是MODE_STREAM,你可以用小于或等于这个大小的块将数据写入这个缓冲区,而 通常使用总大小的1/2的块来允许双缓冲 。
使用更大的缓冲区创建AudioTrack:
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC,
16000, 4,
AudioFormat.ENCODING_PCM_16BIT,
BUF_SIZE * 2, // use a buffer twice the size of
// the chunks you will write to it
AudioTrack.MODE_STREAM);
但是继续写相同大小的块。希望双缓冲可以消除波动。如果这不起作用,您也可以尝试增加BUF_SIZE
。
答案 1 :(得分:1)
好的,我明白了这个问题。 问题来自UDP数据包的接收,通常我Shoud每50毫秒接收一次数据包。
我计算接收两个数据包之间的时间间隔,看来有时候这个间隔优于100毫秒,之后就是小于1毫秒 !!!
当发生这种情况时,声音变得不稳定。 我简单地解决了这个问题:当间隔时间低于1毫秒时,我不会将数据放入队列中。
这很有效,但声音并不松软,但有时会有很少的声音。
我该如何解决这个问题?有没有办法定期接收我的UDP数据包? 我应该尝试在服务中进行接收吗?
答案 2 :(得分:0)
首先,确保AudioTrack没有等待消耗音频,而在其缓冲区中没有其他内容可以播放,因此尝试不从网络流式传输PCM数据以验证瓶颈不是来自您的流。描述您的代码以确定瓶颈来自哪里。
其次,不要写入onProgressUpdate
内的AudioTrack,因为这是在UI线程内完成的,写入AudioTrack是阻塞的。您需要在另一个独立的线程中创建,启动和提供AudioTrack对象。
最后,如果您计划播放音频的时间超过几秒钟,我建议不要使用AsyncTask,引用文档:AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)