【问题标题】:Audio Latency -Java program to Android program音频延迟-Java程序到Android程序
【发布时间】:2018-07-04 21:23:09
【问题描述】:

我有两个 Java 线程,一个在我的电脑上,另一个在 Android 手机上。我想通过 UDP 数据包(点对点连接)将从计算机上的音频线路获取的音频流式传输到 Android 手机。

除了有时音频滞后和我遇到的主要问题是延迟之外,一切正常。我尝试了不同的采样频率和不同的缓冲区大小,但两个设备之间仍然存在延迟(1-2 秒)。

这是我的代码。

Java 音频发送器

(new Thread(() -> {

            while (true) {
                   System.out.println(">>"+status);
                while (status) {

                    try {

                        int size = tdl.read(buffer, 0, buffer.length);
                        if(size>0){
                        DatagramPacket sendPacket
                                = new DatagramPacket(buffer, size, hostAddress, port);
                        socket.send(sendPacket);
                        }
                    } catch (IOException ex) {
                        Logger.getLogger(AudioSender.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (java.lang.NullPointerException ne) {

                    }
                }
            }

        })).start();

 public static void setUpAudioDriverInput() throws LineUnavailableException {
    if (tdl != null) {
        tdl.close();
    }

    int channels = 1;
    int sampleSize = 16;
    boolean bigEndian = false;

    format = new AudioFormat(rate, sampleSize, channels, true, bigEndian);

    DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);

    Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();

    Mixer mixer = AudioSystem.getMixer(mixerInfoFinal.get(lineIndex));

    tdl = (TargetDataLine) mixer.getLine(info);
    tdl.open(format);
    tdl.start();

}

Java Android 音频接收器

  public void getStreaming(){


       getThread = new Thread(new Runnable() {
        @Override
        public void run() {

            try {

                System.out.println("Thread Streamer is Starting..  status2"+ status2);

                int rate = Integer.parseInt(((Spinner) findViewById(R.id.rateSpinner)).getSelectedItem().toString());
                int bufferSize = Integer.parseInt(((Spinner) findViewById(R.id.bufferSizeSpinner)).getSelectedItem().toString());

                String payload = ((EditText) findViewById(R.id.nameEditText)).getText().toString();
                payload += "#" + rate;
                payload += "#" + bufferSize;
                payload += "#";

                System.out.println(">>>"+payload);

                InetAddress address = InetAddress.getByName(((EditText) findViewById(R.id.ipAddressEditText)).getText().toString());
                DatagramPacket dp = new DatagramPacket(payload.getBytes(),payload.length(),address,8088);
                socket.send(dp);

               byte[] buffer = new byte[bufferSize];

                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, rate, channelConfigOUT, audioFormat, buffer.length, AudioTrack.MODE_STREAM);
                audioTrack.play();


                DatagramPacket receivedPacket = new DatagramPacket(buffer,buffer.length);

                System.out.println("BufferSize "+ bufferSize);




                boolean skip=false;

                while(status2 && !Thread.currentThread().isInterrupted()){
                    try {
                        socket.receive(receivedPacket);
                    }catch(SocketTimeoutException ste){
                        skip=true;
                        Thread.currentThread().interrupt();
                        stopStreaming();

                    }
                    if(!skip) {
                        buffer = receivedPacket.getData();
                        audioTrack.write(buffer, 0, buffer.length);
                        System.out.println("aaa" + Thread.currentThread().getName());

                    }
                }

            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }



        }
    });

    getThread.start();

}

谢谢。

更新 我发现这是我尝试超级转发数据包的网络。对于另一个网络,延迟确实减少了不到半秒。昨天我可以用它看电影,延迟已达到极限。如果我会改进系统,我会告诉你的。

【问题讨论】:

    标签: java android audio


    【解决方案1】:

    您不应使用 TargetDataLine 读取大小来创建 DatagramPacket。 创建的数据包过多。

    最好的办法是读取几千字节的数据(即多次 tdl 读取),然后将它们发送到一个“大”数据报包中。

    【讨论】:

    • 为此我有一个缓冲区没有?如果我将缓冲区大小设置为例如 4K 或更大,那么我的数据报更少但延迟更多。我必须尽量减少延迟。
    • 不要依赖 TargetDataLine 来填充缓冲区,读取“小”数据并发送“大”UDP 数据包。如果您使用大约 200 毫秒(8KB 或 16KB 取决于您的音频设置)的数据包,您将不会注意到延迟。我的网络音频设备正在使用这样的数据包大小。
    • 好的,但同样,你所说的就像有一个特定大小的缓冲区来包含 200 毫秒的音频不是吗?那我还是会遇到同样的问题。
    • 更准确地说:您的最终延迟是:服务器捕获延迟 + 网络延迟 + 客户端处理。捕获 200 毫秒的音频不会以您面临的 1-2 秒延迟结束。我从您的实现中看到的问题(根据我自己的经验)是您的代码正在耦合捕获大小和网络大小。您必须独立调整它们。请注意,您不能随意使用“想要”的缓冲区捕获音频(读取目标数据行)(javadoc:“记录音频的应用程序应该足够快地从目标数据行读取数据,以防止缓冲区溢出”)。
    • 正在耦合捕获大小和网络大小'。你是什​​么意思?我尝试了不同的缓冲区大小,但我仍然得到延迟。我还计算了 tdl 行读取数据并将它们保存在缓冲区中所需的时间,我得到了 0 毫秒。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 2018-01-14
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多