我已经编写了一个小型Java程序(pc)和android应用,旨在将音频从pc传输到手机。我正在通过UDP发送音频数据,无法确定发生延迟的原因。从客户端到服务器,在处理数据包之前大约需要1.5-2秒。
我的程序缓存512个字节以发送给客户端,该字节在接收到后立即播放。
我测试了一些不同的配置,任何(基本上)高于此值的配置,延迟只会增加。值较低时,在延迟方面没有明显改善,但是质量损失明显。
根据窗口,设备之间的ping时间仅为3毫秒,因此我认为网络连接不是问题,尽管我不是很肯定。
我的客户(PC)的代码如下所示。
byte[] buffer = new byte[512];
while (true) {
try {
audioInput.read(buffer, 0, buffer.length);
DatagramPacket data = new DatagramPacket(buffer, buffer.length, address, port);
dout.send(data);
System.out.println("Sent Packet #" + i++);
} catch (IOException e) {
e.printStackTrace();
}
}
服务器(电话)的代码如下。
byte[] buffer = new byte[512];
DatagramPacket incomingPacket = new DatagramPacket(buffer, buffer.length);
while (true) {
try {
dgs.receive(incomingPacket);
buffer = incomingPacket.getData();
audioOutput.write(buffer, 0, buffer.length);
} catch (IOException e) {
e.printStackTrace();
}
}
我期望数据包以接近5ms的网络延迟的速度到达,但实际上只有在1500ms之后才接收到它们。
我希望你们中的一些人可能对这种问题有经验。我知道诸如Discord和Skype之类的应用以更高的比特率流播,具有更高的延迟,但是延迟却低得多,所以我希望可能会错过一些东西。
答案 0 :(得分:0)
您正在尝试进行实时流式传输。让我们看看整个过程中的延迟预算。
首先,您使用的是512字节缓冲区-假设采样为float
,采样率为44.1k
,则每次处理128
个采样,则缓冲区的周期为~2.9ms
。
在此缓冲区大小下,最好的方法是~7.5ms
。
控制流:
1:音频输入硬件生成样本并将其存储在缓冲区中。在预定数量的样本之后,操作系统将中断以提供音频。该缓冲时间可能明显长于128个样本。这是T1
2:操作系统计划音频守护进程运行。它在运行之前等待S1
3:音频守护程序运行,处理音频,将其写入缓冲区,并向操作系统发出信号,指出可以读取样本。这段时间短得可以忽略不计。
4:操作系统通过取消阻止对audioInput.read(buffer, 0, buffer.length);
的调用来安排您的输入过程运行。它会在计划之前等待S2
。
5:您致电System.out.println()
。这可能会阻塞-尤其是在您每秒写入约350次时-可能直到安排了另一个不相关的进程为止。 S3
6:将UDP写入网络套接字。操作系统可能会将其排队等待发送-稍后发生的时间很短可以忽略不计
7:通过网络传输。 T2
接收方与上述情况完全相反。
因此总延迟为
2 * (T1 + S1 + S2 + S3 + T2)
我想您的大部分延迟是发送和接收-T1
的硬件缓冲时间。如果您得到的金额远低于10ms
,那么S1,S2,S3
将会变得越来越重要。
注意:
S1
,S2
是运行调度延迟,并且取决于系统负载和调度程序策略。音频渲染处理程序通常以实时威胁优先级运行。 S3
。此延迟特别不可预测。 真正降低延迟的方法是: