| <!-- go/cmark --> | |
| <!--* freshness: {owner: 'jakobi' reviewed: '2021-04-13'} *--> | |
| # NetEq | |
| NetEq is the audio jitter buffer and packet loss concealer. The jitter buffer is | |
| an adaptive jitter buffer, meaning that the buffering delay is continuously | |
| optimized based on the network conditions. Its main goal is to ensure a smooth | |
| playout of incoming audio packets from the network with a low amount of audio | |
| artifacts (alterations to the original content of the packets) while at the same | |
| time keep the delay as low as possible. | |
| ## API | |
| At a high level, the NetEq API has two main functions: | |
| [`InsertPacket`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=198;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72) | |
| and | |
| [`GetAudio`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=219;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72). | |
| ### InsertPacket | |
| [`InsertPacket`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=198;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72) | |
| delivers an RTP packet from the network to NetEq where the following happens: | |
| 1. The packet is discarded if it is too late for playout (for example if it was | |
| reordered). Otherwize it is put into the packet buffer where it is stored | |
| until it is time for playout. If the buffer is full, discard all the | |
| existing packets (this should be rare). | |
| 2. The interarrival time between packets is analyzed and statistics is updated | |
| which is used to derive a new target playout delay. The interarrival time is | |
| measured in the number of GetAudio ‘ticks’ and thus clock drift between the | |
| sender and receiver can be accounted for. | |
| ### GetAudio | |
| [`GetAudio`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=219;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72) | |
| pulls 10 ms of audio from NetEq for playout. A much simplified decision logic is | |
| as follows: | |
| 1. If there is 10 ms audio in the sync buffer then return that. | |
| 2. If the next packet is available (based on RTP timestamp) in the packet | |
| buffer then decode it and append the result to the sync buffer. | |
| 1. Compare the current delay estimate (filtered buffer level) with the | |
| target delay and time stretch (accelerate or decelerate) the contents of | |
| the sync buffer if the buffer level is too high or too low. | |
| 2. Return 10 ms of audio from the sync buffer. | |
| 3. If the last decoded packet was a discontinuous transmission (DTX) packet | |
| then generate comfort noise. | |
| 4. If there is no available packet for decoding due to the next packet having | |
| not arrived or been lost then generate packet loss concealment by | |
| extrapolating the remaining audio in the sync buffer or by asking the | |
| decoder to produce it. | |
| In summary, the output is the result one of the following operations: | |
| * Normal: audio decoded from a packet. | |
| * Acceleration: accelerated playout of a decoded packet. | |
| * Preemptive expand: decelerated playout of a decoded packet. | |
| * Expand: packet loss concealment generated by NetEq or the decoder. | |
| * Merge: audio stitched together from packet loss concealment to decoded data | |
| in case of a loss. | |
| * Comfort noise (CNG): comfort noise generated by NetEq or the decoder between | |
| talk spurts due to discontinuous transmission of packets (DTX). | |
| ## Statistics | |
| There are a number of functions that can be used to query the internal state of | |
| NetEq, statistics about the type of audio output and latency metrics such as how | |
| long time packets have waited in the buffer. | |
| * [`NetworkStatistics`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=273;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72): | |
| instantaneous values or stats averaged over the duration since last call to | |
| this function. | |
| * [`GetLifetimeStatistics`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=280;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72): | |
| cumulative stats that persist over the lifetime of the class. | |
| * [`GetOperationsAndState`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=284;drc=4461f059d180fe8c2886d422ebd1cb55b5c83e72): | |
| information about the internal state of NetEq (is only inteded to be used | |
| for testing and debugging). | |
| ## Tests and tools | |
| * [`neteq_rtpplay`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc;drc=cee751abff598fc19506f77de08bea7c61b9dcca): | |
| Simulate NetEq behavior based on either an RTP dump, a PCAP file or an RTC | |
| event log. A replacement audio file can also be used instead of the original | |
| payload. Outputs aggregated statistics and optionally an audio file to | |
| listen to. | |
| * [`neteq_speed_test`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/test/neteq_speed_test.cc;drc=2ab97f6f8e27b47c0d9beeb8b6ca5387bda9f55c): | |
| Measure performance of NetEq, used on perf bots. | |
| * Unit tests including bit exactness tests where RTP file is used as an input | |
| to NetEq, the output is concatenated and a checksum is calculated and | |
| compared against a reference. | |
| ## Other responsibilities | |
| * Dual-tone multi-frequency signaling (DTMF): receive telephone events and | |
| produce dual tone waveforms. | |
| * Forward error correction (RED or codec inband FEC): split inserted packets | |
| and prioritize the payloads. | |
| * NACK (negative acknowledgement): keep track of lost packets and generate a | |
| list of packets to NACK. | |
| * Audio/video sync: NetEq can be instructed to increase the latency in order | |
| to keep audio and video in sync. |