AudioTrack流不稳定

时间:2015-03-10 06:32:15

标签: android audio android-asynctask audiotrack

我正在尝试通过服务器将音频发送到我播放的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数据包?我应该尝试在服务中进行接收吗?

3 个答案:

答案 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.)