最大限度地减少丢失数据包对通过 TCP 发送的实时媒体流的影响的最佳方法是什么?

发布于 2024-10-03 23:20:20 字数 961 浏览 4 评论 0原文

我们已经在 Silverlight 之上实现了一个音频-视频协作应用程序,并正在尝试对其进行调整。我们遇到的问题之一是,每当数据包丢失时,流延迟就会增加:我们必须等待检测到、请求数据包丢失,然后重新发送丢失的数据包。当然,这会影响我们音频流的一致性。 (如果可以的话,我们会切换到 UDP,但是 Silverlight 不支持浏览器内的那种。我们还禁用了 Nagle 算法,所以一般来说,一旦我们提交要传输的 byte[] 数组,它被传输,并且在单个数据包中。我知道 TCP 数据包大小! = 提交的数据量,但在禁用 Nagle 算法的情况下,它很接近,并且我们有一个自适应抖动缓冲区,因此我们可以 处理丢失的数据包,但是 TCP/IP 上的丢失数据包会大量增加我们需要缓冲的音频量,从而增加延迟。)

因此,我们正在尝试优化发送数据包的方式,看看是否有任何方法以减少丢包的影响。目前,我们正在考虑实施几个相互竞争的解决方案:

(1) 我们可以尝试使数据包变得更大。目前,我们通过同一 TCP 流混合发送大型(约 1024 字节视频)数据包和小型(约 70 字节音频)数据包。但是我们可以将音频和视频数据复用在一起,即只要有空间就将一些视频数据附加到音频数据包中。这将使各个数据包稍大一些,但会减少数据包的总数。

(2) 我们可以将音频和视频分成两个单独的 TCP 流。这意味着,如果视频流由于丢失数据包而停止,音频流不会停止,反之亦然。当然,这会稍微增加开销,并且不会减少发送的数据包总数。

(3) 我们可以将音频反向复用为多个单独的 TCP 流,然后在远端重新组合它们。这将有效地允许我们“伪造”单一 UDP 风格的数据包传输。如果我们有 8 个音频流,其中一个由于丢失数据包而停止,其他流仍然能够按时传送数据,而我们所要做的就是处理 1/8 的音频数据包在停滞的流恢复之前不可用。当然,这并不理想,但与整个流停顿以及在重新传输丢失的数据包之前无法播放任何数据包相比,它可能会带来更好的体验。

对这些可能性有什么想法吗?还有其他建议吗?或者我们只需要编写所有三个代码,然后测试它们?

We've implemented an audio-video collaboration application on top of Silverlight, and are trying to tune it. One of the issues we're experiencing is an increase in stream latency whenever a packet is dropped: we have to wait for the packet loss to be detected, requested, and then for the lost packet to be resent. Of course, this plays hell with the consistency of our audio stream. (We'd switch over to UDP if we could, but Silverlight doesn't support that in-browser. We've also disabled the Nagle algorithm, so in general, as soon as we submit a byte[] array to be transmitted, it's transmitted, and in a single packet. I'm aware that TCP packet size != amount of data submitted, but with the Nagle algorithm disabled, it's close. And we have an adaptive jitter buffer, so we can deal with lost packets, but a lost packet over TCP/IP massively increases the amount of audio we need to buffer, and hence latency.)

So we're trying to optimize how we send our packets, to see if there's any way to reduce the impact of dropped packets. We currently have several competing solutions that we're thinking about implementing:

(1) We could try to make our packets larger. Currently, we send a mix of large (~1024 byte video) packets and small (~70 byte audio) packets over the same TCP stream. But we could multiplex the audio and video data together, i.e., by attaching some of our video data to our audio packets whenever there's room. This would make the individual packets somewhat larger, but would cut down on the total number of packets.

(2) We could split the audio and video into two separate TCP streams. This means that if the video stream stalled because of a lost packet, the audio stream wouldn't stall, and vice versa. Of course, it would slightly increase the overhead, and wouldn't cut down on the overall number of packets sent.

(3) We could inverse multiplex the audio into multiple separate TCP streams, and then reassemble them on the far side. This would effectively allow us to "fake" a single UDP style of packet delivery. If we had 8 audio streams, and one of them stalled because of a lost packet, the other streams would still be able to deliver their data on time, and all we'd have to do is deal with 1/8 of the audio packets being unavailable until the stalled stream caught back up. That's not ideal, of course, but it might result in a better experience than to have the entire stream stall, and not being able to play any packets until the lost packet is retransmitted.

Any thoughts on any of these possibilities? Any other suggestions? Or do we just need to code up all three, and then test them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蛮可爱 2024-10-10 23:20:20

如果您重新启用 Nagle 算法,您将 (i) 让 TCP 根据路径 MTU 而不是您自己的决定发送最大大小的缓冲区; (ii) 完成您的建议 (1) 搭载音频和视频数据包; (iii) 减少数据包总数。使用和不使用 Nagle 算法的饱和 TCP 连接的稳态性能是相同的,因此除了初始窗口填充期间之外,您不会丢失任何内容。

您还应该运行您可以承受的最大套接字发送缓冲区:至少 128k,或者如果可能的话,是该缓冲区的两倍或四倍;并且您还应该使用尽可能大的套接字接收缓冲区,尽管套接字接收缓冲区>在连接套接字之前必须设置 64k,以便在 TCP 握手期间可以告知另一端有关窗口缩放的信息。

If you re-enabled the Nagle algorithm you would (i) let TCP send out maximally-sized buffers according to the path MTU rather than your own determination; (ii) accomplish your suggestion (1) of piggybacking audio and video packets; and (iii) reduce the total number of packets. The steady-state performance of a saturated TCP connection with and without the Nagle algorithm is the same so you don't lose anything except during initial window filling.

You should also run the largest socket send buffer you can possibly afford: at least 128k, or double or quadruple that if possible; and you should also use as large a socket receive buffer as possible, although a socket receive buffer > 64k has to be set before connecting the socket so the other end can be told about window scaling during the TCP handshake.

少钕鈤記 2024-10-10 23:20:20

该应用程序可以通过互联网使用吗?丢包的原因是网络质量问题吗?如果是这样,除了开发尽可能具有容错能力的应用程序之外,您可能还想确保互联网电路的质量可以接受。如今,良好的互联网线路的丢包率不应超过 0.1%。您可以使用我们的数据包丢失工具测试互联网电路和 ISP。它是免费使用的,所以请自行使用。

Is this application to be used over the Internet? Is the reason for the lost packets due to Internet quality? If so, beyond developing the application to be as fault tolerant as possible, you may also want to make sure the Internet circuits are of acceptable quality. Good Internet circuits today should not have any more than 0.1% packet loss. You can test Internet circuits and ISPs using our Packet Loss tool. It's free to use so help yourself.

但可醉心 2024-10-10 23:20:20

您如何确定是数据包丢失导致了停顿?

我认为分离流不会有太大帮助,在尝试保持音频/视频同步时您只会遇到更多问题。

无论哪种方式,无论您使用什么调整,您都会受到 TCP/IP 的限制,要求重新传输数据包。我想我要研究的最重要的事情是服务器和客户端上的 TCP 堆栈是否启用了一些更高级的选项。我特别指的是选择性确认和快速重传(任何现代操作系统都应该默认具有这些)。快速重传将使客户端在检测到丢失的数据包时非常快速地请求丢失的数据包,而选择性确认将使服务器仅重传流中丢失的部分。

但最终,如果您无法容忍单个数据包丢失,那么听起来好像您没有使用足够大的抖动缓冲区。也有可能您的应用程序在将数据发送到 tcp 堆栈的时间上并不那么一致。我会捕获一些数据包,并尝试了解网络中发生的情况,并看看您可以从那里做什么。

How have you determined that it is packet loss that is causing the stalls?

I don't think separating the streams will help much, you'll just have more problems trying to keep the audio / video in sync.

Either way, no matter what tweaks you use, you will be limited by TCP/IP requiring the packet to be retransmitted. I guess the biggest thing I would look into is whether the TCP stacks on you're server and clients have some of the more advanced options enabled. I'm specifically referring to Selective Acknowledgements and Fast retransmissions (any modern OS should have these by default). Fast retransmissions will have the client ask for a missing packet very quickly when it's detected missing, and the selective acknowledgements will have the server only retransmit the missing portions of the stream.

Ultimately though, it sounds as if you're not using a large enough jitter buffer, if you're unable to tolerate a single packet lost. It's also possible you're application isn't all that consistent in the timing used to send data to the tcp stack. I'd get some packet captures and try and get a good idea what's going on in the network, and see what you can do from there.

遇见了你 2024-10-10 23:20:20

我在缓冲区上支持@Kevin Nisbet(不幸的是)。如果您使用 TCP 而不是 UDP,则缓冲区需要足够大,以便服务器收到有关丢失字节的通知并让它们到达客户端。

由于 TCP 将数据作为有序流传递给应用程序,因此当数据包丢失时,堆栈无法向应用程序传递任何额外的字节,直到报告丢失字节的 ack 发送到服务器、进行处理并且字节到达客户端为止。
同时,保持应用程序运行的唯一因素是缓冲区。您知道往返需要多长时间,包括处理吗?

如果没有选择性确认,在丢失字节之后收到的任何内容都是无用的,需要重新传输。客户端将确认收到的最后一个字节,服务器需要重新传输从该点开始的所有内容。

使用选择性确认,至少服务器只需要发送丢失的块,但堆栈仍然需要等待块到达。它无法将迄今为止收到的数据提供给应用程序,然后填写缺失的部分。这就是 UDP 的作用:)
也许你应该写信给微软……

来自网络方面,我对发送相同内容的多个副本感到(有点)畏缩。您的应用程序的带宽充足吗?也许某种冗余(FEC 或类似的)比复制内容更好。
此外,如果可能发生数据包丢失,我认为在网络上增加更多流量并不明智。您的计算机是否运行半双工? :-D

I second @Kevin Nisbet on the buffer (unfortunately). If you're using TCP instead of UDP, the buffer needs to be as large as it takes for the server get notified about the missing bytes and for them to reach the client.

Since TCP delivers data to the application as an ordered stream, when a packet gets lost, the stack cannot deliver any additional byte to the app until the ack reporting the missing bytes is sent to the server, processed and the bytes arrive on the client.
Meanwhile, the only thing keeping your app running is the buffer. Do you know how long does it take for the round-trip, including processing?

Without Selective Ack, anything received after that lost byte is useless and needs to be retransmitted. The client will ack the last byte received and the server needs to re-retransmit everything from that point on.

With Selective Ack at least the server only needs to send the missing chunk, but the stack needs to wait for the chunk to arrive nonetheless. It can't give the data it has received so far to the app and then fill in the missing parts. That's what UDP does :)
Maybe you should write to MS...

Coming from the network side, I cringe (a bit) about sending multiple copies of the same content. Is bandwidth plentiful in your application? Maybe some sort of redundancy (FEC or similar) is better than duplicating your content.
Besides, if packet loss could be happening I don't think it would be wise to shove more traffic on the network. Is your computer running half-duplex? :-D

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文