xref: /aosp_15_r20/external/webrtc/modules/pacing/g3doc/index.md (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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