1*d9f75844SAndroid Build Coastguard Worker<?% config.freshness.reviewed = '2021-04-12' %?> 2*d9f75844SAndroid Build Coastguard Worker<?% config.freshness.owner = 'sprang' %?> 3*d9f75844SAndroid Build Coastguard Worker 4*d9f75844SAndroid Build Coastguard Worker# Paced Sending 5*d9f75844SAndroid Build Coastguard Worker 6*d9f75844SAndroid Build Coastguard WorkerThe paced sender, often referred to as just the "pacer", is a part of the WebRTC 7*d9f75844SAndroid Build Coastguard WorkerRTP stack used primarily to smooth the flow of packets sent onto the network. 8*d9f75844SAndroid Build Coastguard Worker 9*d9f75844SAndroid Build Coastguard Worker## Background 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard WorkerConsider a video stream at 5Mbps and 30fps. This would in an ideal world result 12*d9f75844SAndroid Build Coastguard Workerin each frame being ~21kB large and packetized into 18 RTP packets. While the 13*d9f75844SAndroid Build Coastguard Workeraverage bitrate over say a one second sliding window would be a correct 5Mbps, 14*d9f75844SAndroid Build Coastguard Workeron a shorter time scale it can be seen as a burst of 167Mbps every 33ms, each 15*d9f75844SAndroid Build Coastguard Workerfollowed by a 32ms silent period. Further, it is quite common that video 16*d9f75844SAndroid Build Coastguard Workerencoders overshoot the target frame size in case of sudden movement especially 17*d9f75844SAndroid Build Coastguard Workerdealing with screensharing. Frames being 10x or even 100x larger than the ideal 18*d9f75844SAndroid Build Coastguard Workersize is an all too real scenario. These packet bursts can cause several issues, 19*d9f75844SAndroid Build Coastguard Workersuch as congesting networks and causing buffer bloat or even packet loss. Most 20*d9f75844SAndroid Build Coastguard Workersessions have more than one media stream, e.g. a video and an audio track. If 21*d9f75844SAndroid Build Coastguard Workeryou put a frame on the wire in one go, and those packets take 100ms to reach the 22*d9f75844SAndroid Build Coastguard Workerother side - that means you have now blocked any audio packets from reaching the 23*d9f75844SAndroid Build Coastguard Workerremote end in time as well. 24*d9f75844SAndroid Build Coastguard Worker 25*d9f75844SAndroid Build Coastguard WorkerThe paced sender solves this by having a buffer in which media is queued, and 26*d9f75844SAndroid Build Coastguard Workerthen using a _leaky bucket_ algorithm to pace them onto the network. The buffer 27*d9f75844SAndroid Build Coastguard Workercontains separate fifo streams for all media tracks so that e.g. audio can be 28*d9f75844SAndroid Build Coastguard Workerprioritized over video - and equal prio streams can be sent in a round-robin 29*d9f75844SAndroid Build Coastguard Workerfashion to avoid any one stream blocking others. 30*d9f75844SAndroid Build Coastguard Worker 31*d9f75844SAndroid Build Coastguard WorkerSince the pacer is in control of the bitrate sent on the wire, it is also used 32*d9f75844SAndroid Build Coastguard Workerto generate padding in cases where a minimum send rate is required - and to 33*d9f75844SAndroid Build Coastguard Workergenerate packet trains if bitrate probing is used. 34*d9f75844SAndroid Build Coastguard Worker 35*d9f75844SAndroid Build Coastguard Worker## Life of a Packet 36*d9f75844SAndroid Build Coastguard Worker 37*d9f75844SAndroid Build Coastguard WorkerThe typical path for media packets when using the paced sender looks something 38*d9f75844SAndroid Build Coastguard Workerlike this: 39*d9f75844SAndroid Build Coastguard Worker 40*d9f75844SAndroid Build Coastguard Worker1. `RTPSenderVideo` or `RTPSenderAudio` packetizes media into RTP packets. 41*d9f75844SAndroid Build Coastguard Worker2. The packets are sent to the [RTPSender] class for transmission. 42*d9f75844SAndroid Build Coastguard Worker3. The pacer is called via [RtpPacketSender] interface to enqueue the packet 43*d9f75844SAndroid Build Coastguard Worker batch. 44*d9f75844SAndroid Build Coastguard Worker4. The packets are put into a queue within the pacer awaiting opportune moments 45*d9f75844SAndroid Build Coastguard Worker to send them. 46*d9f75844SAndroid Build Coastguard Worker5. At a calculated time, the pacer calls the `PacingController::PacketSender()` 47*d9f75844SAndroid Build Coastguard Worker callback method, normally implemented by the [PacketRouter] class. 48*d9f75844SAndroid Build Coastguard Worker6. The router forwards the packet to the correct RTP module based on the 49*d9f75844SAndroid Build Coastguard Worker packet's SSRC, and in which the `RTPSenderEgress` class makes final time 50*d9f75844SAndroid Build Coastguard Worker stamping, potentially records it for retransmissions etc. 51*d9f75844SAndroid Build Coastguard Worker7. The packet is sent to the low-level `Transport` interface, after which it is 52*d9f75844SAndroid Build Coastguard Worker now out of scope. 53*d9f75844SAndroid Build Coastguard Worker 54*d9f75844SAndroid Build Coastguard WorkerAsynchronously to this, the estimated available send bandwidth is determined - 55*d9f75844SAndroid Build Coastguard Workerand the target send rate is set on the `RtpPacketPacer` via the `void 56*d9f75844SAndroid Build Coastguard WorkerSetPacingRates(DataRate pacing_rate, DataRate padding_rate)` method. 57*d9f75844SAndroid Build Coastguard Worker 58*d9f75844SAndroid Build Coastguard Worker## Packet Prioritization 59*d9f75844SAndroid Build Coastguard Worker 60*d9f75844SAndroid Build Coastguard WorkerThe pacer prioritized packets based on two criteria: 61*d9f75844SAndroid Build Coastguard Worker 62*d9f75844SAndroid Build Coastguard Worker* Packet type, with most to least prioritized: 63*d9f75844SAndroid Build Coastguard Worker 1. Audio 64*d9f75844SAndroid Build Coastguard Worker 2. Retransmissions 65*d9f75844SAndroid Build Coastguard Worker 3. Video and FEC 66*d9f75844SAndroid Build Coastguard Worker 4. Padding 67*d9f75844SAndroid Build Coastguard Worker* Enqueue order 68*d9f75844SAndroid Build Coastguard Worker 69*d9f75844SAndroid Build Coastguard WorkerThe enqueue order is enforced on a per stream (SSRC) basis. Given equal 70*d9f75844SAndroid Build Coastguard Workerpriority, the [RoundRobinPacketQueue] alternates between media streams to ensure 71*d9f75844SAndroid Build Coastguard Workerno stream needlessly blocks others. 72*d9f75844SAndroid Build Coastguard Worker 73*d9f75844SAndroid Build Coastguard Worker## Implementations 74*d9f75844SAndroid Build Coastguard Worker 75*d9f75844SAndroid Build Coastguard WorkerThe main class to use is called [TaskQueuePacedSender]. It uses a task queue to 76*d9f75844SAndroid Build Coastguard Workermanage thread safety and schedule delayed tasks, but delegates most of the actual 77*d9f75844SAndroid Build Coastguard Workerwork to the `PacingController` class. 78*d9f75844SAndroid Build Coastguard WorkerThis way, it's possible to develop a custom pacer with different scheduling 79*d9f75844SAndroid Build Coastguard Workermechanism - but ratain the same pacing logic. 80*d9f75844SAndroid Build Coastguard Worker 81*d9f75844SAndroid Build Coastguard Worker## The Packet Router 82*d9f75844SAndroid Build Coastguard Worker 83*d9f75844SAndroid Build Coastguard WorkerAn adjacent component called [PacketRouter] is used to route packets coming out 84*d9f75844SAndroid Build Coastguard Workerof the pacer and into the correct RTP module. It has the following functions: 85*d9f75844SAndroid Build Coastguard Worker 86*d9f75844SAndroid Build Coastguard Worker* The `SendPacket` method looks up an RTP module with an SSRC corresponding to 87*d9f75844SAndroid Build Coastguard Worker the packet for further routing to the network. 88*d9f75844SAndroid Build Coastguard Worker* If send-side bandwidth estimation is used, it populates the transport-wide 89*d9f75844SAndroid Build Coastguard Worker sequence number extension. 90*d9f75844SAndroid Build Coastguard Worker* Generate padding. Modules supporting payload-based padding are prioritized, 91*d9f75844SAndroid Build Coastguard Worker with the last module to have sent media always being the first choice. 92*d9f75844SAndroid Build Coastguard Worker* Returns any generated FEC after having sent media. 93*d9f75844SAndroid Build Coastguard Worker* Forwards REMB and/or TransportFeedback messages to suitable RTP modules. 94*d9f75844SAndroid Build Coastguard Worker 95*d9f75844SAndroid Build Coastguard WorkerAt present the FEC is generated on a per SSRC basis, so is always returned from 96*d9f75844SAndroid Build Coastguard Workeran RTP module after sending media. Hopefully one day we will support covering 97*d9f75844SAndroid Build Coastguard Workermultiple streams with a single FlexFEC stream - and the packet router is the 98*d9f75844SAndroid Build Coastguard Workerlikely place for that FEC generator to live. It may even be used for FEC padding 99*d9f75844SAndroid Build Coastguard Workeras an alternative to RTX. 100*d9f75844SAndroid Build Coastguard Worker 101*d9f75844SAndroid Build Coastguard Worker## The API 102*d9f75844SAndroid Build Coastguard Worker 103*d9f75844SAndroid Build Coastguard WorkerThe section outlines the classes and methods relevant to a few different use 104*d9f75844SAndroid Build Coastguard Workercases of the pacer. 105*d9f75844SAndroid Build Coastguard Worker 106*d9f75844SAndroid Build Coastguard Worker### Packet sending 107*d9f75844SAndroid Build Coastguard Worker 108*d9f75844SAndroid Build Coastguard WorkerFor sending packets, use 109*d9f75844SAndroid Build Coastguard Worker`RtpPacketSender::EnqueuePackets(std::vector<std::unique_ptr<RtpPacketToSend>> 110*d9f75844SAndroid Build Coastguard Workerpackets)` The pacer takes a `PacingController::PacketSender` as constructor 111*d9f75844SAndroid Build Coastguard Workerargument, this callback is used when it's time to actually send packets. 112*d9f75844SAndroid Build Coastguard Worker 113*d9f75844SAndroid Build Coastguard Worker### Send rates 114*d9f75844SAndroid Build Coastguard Worker 115*d9f75844SAndroid Build Coastguard WorkerTo control the send rate, use `void SetPacingRates(DataRate pacing_rate, 116*d9f75844SAndroid Build Coastguard WorkerDataRate padding_rate)` If the packet queue becomes empty and the send rate 117*d9f75844SAndroid Build Coastguard Workerdrops below `padding_rate`, the pacer will request padding packets from the 118*d9f75844SAndroid Build Coastguard Worker`PacketRouter`. 119*d9f75844SAndroid Build Coastguard Worker 120*d9f75844SAndroid Build Coastguard WorkerIn order to completely suspend/resume sending data (e.g. due to network 121*d9f75844SAndroid Build Coastguard Workeravailability), use the `Pause()` and `Resume()` methods. 122*d9f75844SAndroid Build Coastguard Worker 123*d9f75844SAndroid Build Coastguard WorkerThe specified pacing rate may be overriden in some cases, e.g. due to extreme 124*d9f75844SAndroid Build Coastguard Workerencoder overshoot. Use `void SetQueueTimeLimit(TimeDelta limit)` to specify the 125*d9f75844SAndroid Build Coastguard Workerlongest time you want packets to spend waiting in the pacer queue (pausing 126*d9f75844SAndroid Build Coastguard Workerexcluded). The actual send rate may then be increased past the pacing_rate to 127*d9f75844SAndroid Build Coastguard Workertry to make the _average_ queue time less than that requested limit. The 128*d9f75844SAndroid Build Coastguard Workerrationale for this is that if the send queue is say longer than three seconds, 129*d9f75844SAndroid Build Coastguard Workerit's better to risk packet loss and then try to recover using a key-frame rather 130*d9f75844SAndroid Build Coastguard Workerthan cause severe delays. 131*d9f75844SAndroid Build Coastguard Worker 132*d9f75844SAndroid Build Coastguard Worker### Bandwidth estimation 133*d9f75844SAndroid Build Coastguard Worker 134*d9f75844SAndroid Build Coastguard WorkerIf the bandwidth estimator supports bandwidth probing, it may request a cluster 135*d9f75844SAndroid Build Coastguard Workerof packets to be sent at a specified rate in order to gauge if this causes 136*d9f75844SAndroid Build Coastguard Workerincreased delay/loss on the network. Use the `void CreateProbeCluster(...)` 137*d9f75844SAndroid Build Coastguard Workermethod - packets sent via this `PacketRouter` will be marked with the 138*d9f75844SAndroid Build Coastguard Workercorresponding cluster_id in the attached `PacedPacketInfo` struct. 139*d9f75844SAndroid Build Coastguard Worker 140*d9f75844SAndroid Build Coastguard WorkerIf congestion window pushback is used, the state can be updated using 141*d9f75844SAndroid Build Coastguard Worker`SetCongestionWindow()` and `UpdateOutstandingData()`. 142*d9f75844SAndroid Build Coastguard Worker 143*d9f75844SAndroid Build Coastguard WorkerA few more methods control how we pace: * `SetAccountForAudioPackets()` 144*d9f75844SAndroid Build Coastguard Workerdetermines if audio packets count into bandwidth consumed. * 145*d9f75844SAndroid Build Coastguard Worker`SetIncludeOverhead()` determines if the entire RTP packet size counts into 146*d9f75844SAndroid Build Coastguard Workerbandwidth used (otherwise just media payload). * `SetTransportOverhead()` sets 147*d9f75844SAndroid Build Coastguard Workeran additional data size consumed per packet, representing e.g. UDP/IP headers. 148*d9f75844SAndroid Build Coastguard Worker 149*d9f75844SAndroid Build Coastguard Worker### Stats 150*d9f75844SAndroid Build Coastguard Worker 151*d9f75844SAndroid Build Coastguard WorkerSeveral methods are used to gather statistics in pacer state: 152*d9f75844SAndroid Build Coastguard Worker 153*d9f75844SAndroid Build Coastguard Worker* `OldestPacketWaitTime()` time since the oldest packet in the queue was 154*d9f75844SAndroid Build Coastguard Worker added. 155*d9f75844SAndroid Build Coastguard Worker* `QueueSizeData()` total bytes currently in the queue. 156*d9f75844SAndroid Build Coastguard Worker* `FirstSentPacketTime()` absolute time the first packet was sent. 157*d9f75844SAndroid Build Coastguard Worker* `ExpectedQueueTime()` total bytes in the queue divided by the send rate. 158*d9f75844SAndroid Build Coastguard Worker 159*d9f75844SAndroid Build Coastguard Worker[RTPSender]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/rtp_rtcp/source/rtp_sender.h;drc=77ee8542dd35d5143b5788ddf47fb7cdb96eb08e 160*d9f75844SAndroid Build Coastguard Worker[RtpPacketSender]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/rtp_rtcp/include/rtp_packet_sender.h;drc=ea55b0872f14faab23a4e5dbcb6956369c8ed5dc 161*d9f75844SAndroid Build Coastguard Worker[RtpPacketPacer]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/rtp_packet_pacer.h;drc=e7bc3a347760023dd4840cf6ebdd1e6c8592f4d7 162*d9f75844SAndroid Build Coastguard Worker[PacketRouter]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/packet_router.h;drc=3d2210876e31d0bb5c7de88b27fd02ceb1f4e03e 163*d9f75844SAndroid Build Coastguard Worker[TaskQueuePacedSender]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/task_queue_paced_sender.h;drc=5051693ada61bc7b78855c6fb3fa87a0394fa813 164*d9f75844SAndroid Build Coastguard Worker[RoundRobinPacketQueue]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/pacing/round_robin_packet_queue.h;drc=b571ff48f8fe07678da5a854cd6c3f5dde02855f 165