VoNR with ROHC in 5G NR
Why voice needs Robust Header Compression — shrinking the RTP/UDP/IP header on the 5QI=1 voice DRB to boost cell voice capacity.
A VoNR speech frame is tiny — an AMR-WB payload is only about 30–60 bytes every 20 ms — yet the RTP/UDP/IP header stacked on top of it is roughly 40 bytes (IPv4) to 60 bytes (IPv6). The header is as big as the voice it carries, or bigger. Sending that uncompressed over the air would waste scarce radio resources on fields that barely change and would slash how many simultaneous voice users a cell can hold. Robust Header Compression (ROHC) is the fix: it squeezes that header down to as little as 1–3 bytes on the voice bearer. This page is grounded in TS 38.323 (PDCP), TS 26.114 (IMS multimedia telephony) and RFC 5795 (the ROHC framework).
Introduction
Robust Header Compression is a PDCP function (TS 38.323) that runs inside the PDCP entity of a radio bearer, replacing the bulky RTP/UDP/IP header of each packet with a compressed header of a few bytes. It is a transmit-side compressor talking to a receive-side decompressor, both keeping a shared context that remembers the field values so the header need not be re-sent in full every packet.
Where does it sit in the UE/network lifecycle? ROHC is switched on per DRB by RRC, in the PDCP-Config delivered inside RRCReconfiguration, and it comes to life the moment the voice bearer is set up — typically when the IMS session establishes the GBR 5QI=1 voice flow. From then on it runs continuously for the whole call, compressing 50 packets a second, and it must survive handovers, radio loss, and codec-rate changes without corrupting the media.
Why it matters: for VoNR the header is comparable to or larger than the speech it wraps, so uncompressed voice would burn a large fraction of the air interface on near-constant fields. ROHC is what makes VoNR spectrally viable — roughly doubling the useful-payload ratio and multiplying the number of concurrent calls a cell can carry. Because the compression runs as a small state machine per flow, most VoNR "voice quality" or "capacity" investigations end up examining the ROHC state, its context, and how it behaves across mobility.
On this page
Why ROHC is needed
In plain words: imagine mailing a one-line postcard, but wrapping every postcard in a full A4 envelope printed with both addresses, again and again, fifty times a second. The envelope is bigger than the message. ROHC is the agreement between sender and receiver: “we both already know the addresses — from now on just write the message and a tiny same-as-before-plus-one note.” The full envelope goes once; everything after is a postcard.
Concretely, three facts force header compression on the voice bearer. First, the header-to-payload ratio is inverted: unlike bulk data where a 40-byte header rides a 1500-byte payload, a VoNR header of 40–60 bytes wraps a 30–60 byte codec frame. Second, the packet rate is relentless: one frame every 20 ms, 50 per second, for the whole call, per user. Third, the fields are almost entirely predictable: addresses, ports and SSRC are constant, and the RTP sequence number and timestamp move by a fixed step each frame. That combination — huge relative overhead, high rate, near-total predictability — is exactly the case header compression was invented for, and it is why ROHC is universally enabled on the 5QI=1 voice DRB.
The Problem: Header Bigger Than the Voice
VoNR carries voice as media over IMS: the codec frame (typically AMR or AMR-WB) rides inside RTP, which rides inside UDP, which rides inside IP. Each layer adds a fixed header. The trouble is the sheer imbalance between that header and the speech it wraps. For bulk data the header is a rounding error against a 1500-byte payload; for VoNR the header is the packet.
Walk the layers from the outside in. The IP header carries addresses, traffic class, flow label and hop limit — 40 bytes for IPv6 (the VoNR norm), 20 for IPv4. UDP adds 8 bytes (ports, length, checksum), and RTP adds 12 (the V/P/X/CC and marker/payload-type octets, a 16-bit sequence number, a 32-bit timestamp and a 32-bit SSRC). That is 60 bytes of framing before a single sample of speech.
| Layer | Fields | IPv6 size | IPv4 size |
|---|---|---|---|
IP header | Src/dst address, traffic class, flow label, hop limit, next-header | 40 bytes | 20 bytes |
UDP header | Src/dst ports, length, checksum | 8 bytes | 8 bytes |
RTP header | V/P/X/CC, marker, payload type, sequence number, timestamp, SSRC | 12 bytes | 12 bytes |
| Total header | — | ≈ 60 bytes | ≈ 40 bytes |
AMR-WB payload | Codec frame (e.g. 12.65 kbit/s ≈ 32 bytes) | ≈ 30–60 bytes | ≈ 30–60 bytes |
So a single voice packet might be 60 bytes of header wrapped around 32 bytes of speech — the overhead is nearly two-thirds of the packet. A voice call fires one of these every 20 ms, i.e. 50 packets per second per user, for as long as the call lasts. Multiply that overhead by every active voice user in a cell and you are burning a large fraction of the air interface on header fields that are, packet after packet, almost identical. The addresses never change, the ports never change, the SSRC never changes; only the RTP sequence number and timestamp move, and they move by a fixed step each frame.
The core problem: for bulk data the header is a rounding error against a 1500-byte payload; for VoNR the header is the packet. Compressing it is not a nice-to-have — it is what makes VoNR spectrally viable, which is why ROHC is universally deployed on the voice bearer.
What ROHC Does
ROHC exploits a simple observation: across the thousands of packets in one voice call, most header fields never change and the rest change in a completely predictable way. The source/destination IP addresses, the UDP ports and the RTP SSRC are constant for the whole call. The RTP sequence number increments by one each packet, and the timestamp jumps by a fixed sample count every 20 ms. Once both ends agree on those starting values and steps, almost nothing needs to be sent.
A compressor/decompressor pair that replaces the full RTP/UDP/IP header with a few-byte compressed header, while the two ends keep a synchronised context holding the static and dynamic field values, indexed by a CID.
The header is enormous relative to the AMR-WB payload. Collapsing 40–60 bytes to 1–3 bytes roughly doubles the useful payload ratio on the voice bearer, directly increasing VoNR cell capacity and improving cell-edge coverage.
Send the static fields once (the IR state), then send only the unpredictable delta — usually just a few low-order bits of the sequence number. The decompressor rebuilds the full header from its stored context plus that delta, extrapolating the timestamp from the fixed stride.
The deep mechanics — how each profile encodes fields, W-LSB (window-based least-significant-bit) sequence-number encoding, the compressed packet formats (IR, IR-DYN, UO-0, UO-1, UOR-2) and the full state machine — are covered on the general ROHC Header Compression page. This page does not repeat that state machine in full; the focus here is what ROHC buys the voice bearer specifically, how it is switched on, and how it survives the radio channel.
Cross-reference, not duplication: ROHC is a general framework used for many flows. Everything below is the VoNR-specific slice — the voice profile, the voice DRB configuration, and the capacity/coverage payoff. For the protocol internals shared by all flows, follow the link above.
Where ROHC Lives — PDCP on the Voice DRB
ROHC is a PDCP function (TS 38.323). It runs inside the PDCP entity of a specific radio bearer, on the transmit side as the compressor and on the receive side as the decompressor, and it is turned on per DRB by RRC. For VoNR the bearer in question is the GBR voice DRB carrying the 5QI=1 QoS flow — the standardised 5QI for conversational voice, with a 100 ms packet delay budget and a 10-2 error rate target.
RRC configures ROHC through the PDCP-Config of that DRB, sent in RRCReconfiguration. The headerCompression choice is set to rohc (as opposed to notUsed), and that structure carries three things: the set of enabled profiles (each a boolean like profile0x0001), the maximum context identifier maxCID, and the drb-ContinueROHC flag used at handover. For voice, the profile that matters is profile 0x0001 (RTP/UDP/IP) — the RTP-aware profile that understands the sequence-number/timestamp relationship and delivers the biggest saving.
Config field (in PDCP-Config) | Meaning | Voice setting |
|---|---|---|
headerCompression | Choice: notUsed or rohc | rohc |
profiles (booleans) | Which ROHC profiles the UE may use | profile0x0001 = true (RTP/UDP/IP) |
maxCID | Highest CID value — number of parallel contexts the entity may track (0…16383) | Small (often 1–15; one call needs few CIDs) |
drb-ContinueROHC | At PDCP re-establishment, keep the existing ROHC context instead of resetting | Set when the target can preserve context |
Representative 5G SA config snippet (PDCP-Config of the voice DRB) — illustrative, values vary by vendor/build:
| Field | Meaning | Example | Check |
|---|---|---|---|
headerCompression | Whether ROHC is on for this DRB. | rohc | If it decodes as notUsed on the voice DRB, no compression happens — capacity/coverage gain is lost. |
profile0x0001 | RTP/UDP/IP profile enabled flag. | true | Must be true for voice; if only 0x0004/0x0002 are set the RTP timestamp stride is not exploited and headers stay large. |
maxCID | Max number of parallel contexts. | 15 | Must be ≥ the number of concurrent media flows; too small and a new flow cannot get a CID. |
drb-ContinueROHC | Preserve context across PDCP re-establishment. | true | If absent/false, expect an IR burst (full headers) right after every handover. |
mappedQoS-FlowsToAdd | QoS flow(s) mapped onto this DRB via SDAP. | 5QI=1 | Confirm the voice flow really lands on the ROHC-enabled DRB, not a default bulk DRB. |
| Profile | Compresses | Relevance to VoNR |
|---|---|---|
| 0x0001 (RTP/UDP/IP) | Full RTP/UDP/IP stack | The voice profile. RTP-aware, so the steady-state header is near-minimal. |
0x0002 (UDP/IP) | UDP/IP only | Non-RTP UDP flows; not the voice media path. |
0x0003 (ESP/IP) | IPsec ESP/IP | Encrypted tunnels; not the media path. |
0x0004 (IP) | IP only | Generic IP flows with no useful transport regularity. |
0x0000 | Uncompressed (passthrough) | Baseline; no gain. |
ROHC sits at a precise point in the PDCP transmit chain. On transmit the order is: receive the SDU, perform header compression, then ciphering, then add the PDCP header and integrity protection where configured; on receive the order reverses — deciphering first, then decompression. Compression must precede ciphering because ROHC needs to read the plaintext RTP/UDP/IP fields it is compressing; once ciphered they are opaque.
Spec note: TS 38.323 defines how PDCP invokes ROHC and its position in the processing chain (header compression before ciphering on transmit, decompression after deciphering on receive). The profiles themselves come from the IETF ROHC framework (RFC 5795 and the per-profile RFCs, e.g. RFC 3095/3843/4815). The permitted profile set, maxCID and drb-ContinueROHC are signalled to the UE in PDCP-Config.
Why per-DRB matters here: the network enables rohc with profile 0x0001 on the 5QI=1 voice DRB, but typically leaves header compression off on a bulk-data DRB — a 40-byte header against a 1500-byte download is not worth compressing, and the ROHC state machine would add complexity for no benefit.
✅ Debugging steps
- Decode the
RRCReconfigurationand confirmheaderCompressionisrohc(notnotUsed) on the DRB that carries the5QI=1flow — trace the SDAP mapping to be sure the voice flow lands there. - Check that
profile0x0001is enabled; without the RTP-aware profile the timestamp stride cannot be exploited. - Verify both ends agree: the UE only uses profiles the network signalled, and the compressor must not use a CID above
maxCID. - Confirm ROHC runs before ciphering — if a vendor build ciphers first, ROHC sees opaque bytes and cannot compress.
⚠ Common causes of failure
headerCompressionleft asnotUsed, or ROHC applied to the wrong DRB, so voice packets go out with full 60-byte headers.- Profile mismatch: network enables only
0x0004/0x0002, so the RTP timestamp is never extrapolated and the header never reaches the minimal size. maxCIDtoo small for the number of simultaneous media flows — a new flow cannot allocate a context.- SDAP maps the voice QoS flow to a default (bulk) DRB that has ROHC disabled.
Compressor States & Context
The compressor cannot emit tiny headers from the very first packet, because the decompressor has no context yet. So it works through three states, sending less as it gains confidence the far end is in sync. (For the full state machine, transitions and packet formats see the general ROHC page; this is the short version for the voice case.)
| State | Full name | What it sends on the voice flow | Header size |
|---|---|---|---|
IR state | Initialization & Refresh | The full static context (IP addresses, ports, SSRC) so the decompressor can build its context from scratch. Sent at call start and on periodic refresh. | Largest (≈ full header + a few bytes) |
FO state | First Order | Updates to the dynamically changing fields once the static part is known — e.g. establishing the timestamp stride and any irregular field changes. | Medium |
SO state | Second Order | The steady state: the header collapses to essentially just a few sequence-number bits, everything else extrapolated from the context. | ≈ 1–3 bytes |
For a steady voice stream the SO state is where the win lives. A voice call is exactly the kind of long, regular flow ROHC was designed for: after the first handful of packets the compressor settles into SO state and stays there for the rest of the call, sending 1–3 byte headers 50 times a second. In SO state the compressor typically sends a UO-0 format — a single octet carrying a few LSBs of the RTP sequence number plus a CRC — and the decompressor reconstructs the full 60-byte header by adding the known static fields and extrapolating the timestamp from the stride it learned in FO state.
The CID (context identifier) tags which flow a compressed header belongs to, so a PDCP entity can track several contexts at once up to maxCID. A single voice call needs only one context; a device with several simultaneous media streams uses several CIDs on the same entity.
Mental model: the first packet is a full letter with both addresses (IR state). Every later packet is a postcard that says “same as before, plus one” (SO state). Voice sends postcards for minutes on end — which is why ROHC pays off so spectacularly here.
Reading the ROHC state machine in the logs
The single most useful thing to watch is the compressor/decompressor state over time: it should climb IR→FO→SO in the first few packets and then stay in SO. Repeated drops back to IR/FO signal a problem — loss of sync, a handover context reset, or a jittery flow.
Representative PDCP/ROHC log — illustrative, values vary by vendor/build:
| Field | Meaning | Example (from log) | Debugging check |
|---|---|---|---|
profile | ROHC profile in use for this CID. | 0x0001 | Must be 0x0001 for voice; anything else means the RTP-aware compression is not active. |
state | Compressor (IR/FO/SO) or decompressor (NC/SC/FC) state. | SO / FC | Should reach and stay at SO/FC; frequent drops mean loss of sync. |
pktType | Compressed format emitted (IR, IR-DYN, UO-0…). | UO-0 | Steady voice should be almost all UO-0; a stream of IR/IR-DYN means the context keeps re-initialising. |
hdr | Compressed header size for that packet. | 1B | SO-state headers should be 1–3 B; if they stay large the saving is not being realised. |
tsStride | RTP timestamp step learned in FO. | 320 | Must match the codec (+320 for AMR-WB, +160 for AMR); a wrong stride forces repeated FO updates. |
verify | Per-packet CRC over the reconstructed header. | CRC_OK/CRC_FAIL | Bursts of CRC_FAIL = context desync; watch for the recovering STATIC-NACK/IR that follows. |
✅ Debugging steps
- Trace the compressor state per CID — confirm it reaches
SOwithin the first handful of packets and stays there for the call. - Check the emitted
pktTypedistribution: steady voice should be dominated byUO-0; a flood ofIR/IR-DYNmeans the context is not stabilising. - Verify the learned
tsStridematches the codec (+320 AMR-WB / +160 AMR); a mismatch keeps dragging the compressor back toFO state. - On the decompressor side, look for
CRC_FAILbursts and the recovery path (STATIC-NACK → IR refresh) that should follow.
⚠ Common causes of failure
- Compressor never settles in
SO state(irregular flow, DTX churn, or wrong stride), so headers stay medium/large. - Decompressor context lost — too many consecutive packets dropped for W-LSB to resolve the sequence number — producing sustained
CRC_FAILand discarded voice. - No return path in U-mode, so a desync only recovers at the next periodic IR refresh, audible as a brief dropout.
- Context reset at handover (no
drb-ContinueROHC) forcing a fresh IR burst each mobility event.
The AMR / AMR-WB Codec and 20 ms Packetization
To see why the payload is so small — and why the timing is so regular that ROHC can extrapolate it — you have to look at the codec. VoNR uses the 3GPP AMR (narrowband, 8 kHz sampling) and AMR-WB (wideband, 16 kHz sampling) speech codecs, negotiated over IMS SDP per TS 26.114. Both are multi-rate: the encoder can switch its bit rate frame-by-frame in response to a Codec Mode Request (CMR), trading speech quality against bandwidth without renegotiating the session.
The key regularity is timing. Both codecs produce one frame every 20 ms — 50 frames per second. Each 20 ms frame corresponds to a fixed number of audio samples (160 samples at 8 kHz for AMR, 320 at 16 kHz for AMR-WB), which is exactly why the RTP timestamp advances by a constant stride every packet. That fixed stride is the property ROHC profile 0x0001 exploits: once it has seen the stride it never needs to send the timestamp again.
| Parameter | AMR (narrowband) | AMR-WB (wideband) |
|---|---|---|
| Audio bandwidth | 200–3400 Hz | 50–7000 Hz |
| Sampling rate | 8 kHz | 16 kHz |
| Frame duration | 20 ms (160 samples) | 20 ms (320 samples) |
| Frame rate | 50 frames/s | 50 frames/s |
| Codec modes | 8 modes: 4.75, 5.15, 5.90, 6.70, 7.40, 7.95, 10.2, 12.2 kbit/s | 9 modes: 6.60, 8.85, 12.65, 14.25, 15.85, 18.25, 19.85, 23.05, 23.85 kbit/s |
| Payload / 20 ms frame | ≈ 12–31 bytes | ≈ 17–60 bytes (12.65 kbit/s ≈ 32 bytes) |
RTP timestamp stride | +160 per frame | +320 per frame |
Packetization follows RFC 4867 (the AMR/AMR-WB RTP payload format) as profiled by TS 26.114: one 20 ms speech frame per RTP packet in bandwidth-efficient or octet-aligned mode, prefixed by a small payload header (a CMR field and table-of-contents byte). During silence the codec uses Discontinuous Transmission (DTX), sending only occasional Silence Insertion Descriptor (SID) frames for comfort noise. DTX cuts the packet rate further, but the sequence number and timestamp then jump at talk-spurt boundaries — which the compressor absorbs with a brief return to FO state before settling back into SO state.
Codec meets compressor: the codec's fixed 20 ms cadence is what makes the RTP timestamp perfectly predictable, and predictability is exactly what ROHC monetises. A less regular media flow would keep bouncing to FO state and never realise the full SO state saving.
Why It Matters for VoNR Capacity
Put the numbers side by side. Take an AMR-WB frame of 32 bytes at codec mode 12.65 kbit/s over IPv6, and add a small RTP payload header so the on-air voice block is roughly 35 bytes of media:
That saving turns directly into VoNR gains on the 5QI=1 GBR voice DRB:
- Cell voice capacity. Far fewer air-interface bytes per packet means many more simultaneous voice users share the same spectrum — the single biggest reason ROHC is universally deployed for VoNR. Halving the on-air packet roughly doubles the number of calls a fixed resource budget can carry.
- Coverage and robustness. A smaller transport block can be sent at a lower code rate / lower
MCS, or fits in fewer PRBs, so it is more likely to be decoded at the cell edge — better voice coverage where SINR is poor. - Efficiency with SPS / configured grant. Voice already uses semi-persistent scheduling to avoid per-packet signalling; shrinking the packet lets that periodic grant be smaller too, freeing PRBs for other users. Fewer transmitted bits, 50 frames a second over a multi-minute call, also lowers UE transmit energy.
Bottom line: ROHC + a small periodic grant is what lets a 5G cell carry hundreds of concurrent voice calls instead of a handful. The compression is not an optimisation bolted on afterwards — it is designed into the voice bearer's economics.
Modes, Feedback and Radio Robustness
ROHC can run in three modes, which differ in how the decompressor confirms the context to the compressor. The choice trades feedback traffic against resilience:
| Mode | Feedback | Character |
|---|---|---|
| U-mode (Unidirectional) | None | Compressor advances optimistically and refreshes periodically; used when no return path is assumed. |
| O-mode (Bidirectional Optimistic) | Occasional (NACK on error) | Feedback mainly to recover from errors — a common choice on the voice bearer. |
| R-mode (Bidirectional Reliable) | Frequent (ACK/NACK) | Most conservative; every context change is acknowledged. Lowest risk of loss of sync, most feedback traffic. |
The “R” in ROHC — robust — is the point that matters for the radio link. The air interface loses packets; a scheme that broke every time a compressed header went missing would be useless for voice. ROHC tolerates loss two ways. First, it encodes the sequence number with W-LSB (window-based least-significant-bit) encoding, sending only the low-order bits within a sliding window, so a few lost packets do not desynchronise the context — the decompressor can still resolve the true sequence number as long as it stays within the window. Second, the compressor periodically drops back to the IR state to refresh the full context, so a decompressor that lost sync recovers on the next refresh. In the bidirectional modes the decompressor can also send feedback (a NACK or STATIC-NACK) to pull the compressor back to FO state or IR state immediately.
Each compressed packet also carries a small CRC over the reconstructed header, so the decompressor verifies it rebuilt the header correctly before delivering the packet; on a CRC failure the packet is discarded rather than delivered corrupt. Robust does not mean it never loses sync — it means one lost packet cannot poison the whole flow, and recovery is bounded to a few frames (tens of milliseconds), well within what voice can tolerate.
Handover caveat: ROHC context lives in the PDCP entity. On PDCP re-establishment (e.g. handover) the target normally starts with no context, so the compressor must run a fresh IR state phase again — which is why the first voice packets after a mobility event briefly carry full headers. The drb-ContinueROHC flag in PDCP-Config lets the network signal that the existing context is preserved across the re-establishment, avoiding that re-initialisation burst when the target node can carry the context forward.
✅ Debugging steps
- Identify the mode in use (U/O/R). If voice runs U-mode with no feedback, expect longer recovery after loss — check whether the return path could carry ROHC feedback.
- After a mobility event, verify whether the log shows a fresh IR burst; if so, confirm whether
drb-ContinueROHCwas signalled and honoured by both ends. - Correlate audible dropouts with
CRC_FAIL/discard bursts and radio BLER on the DRB — distinguish ROHC desync from ordinary radio loss. - Check the IR refresh period; too long a refresh interval lengthens worst-case recovery after an unrecoverable loss.
⚠ Common causes of failure
- Loss burst longer than the W-LSB window, so the decompressor cannot resolve the sequence number and must wait for an IR refresh.
- U-mode with a long refresh period, turning a brief radio glitch into a noticeable voice gap.
- Handover without context continuation, adding an IR burst (and momentary capacity hit) at every cell change.
- One-directional feedback path broken in O/R mode, so NACKs never reach the compressor and it never accelerates recovery.
LTE ↔ NR: ROHC is essentially the same tool in both. In LTE (VoLTE) it is a PDCP function per TS 36.323, configured in PDCP-Config on the QCI 1 voice bearer; in NR (VoNR) it is TS 38.323 on the 5QI=1 DRB. The profiles, states (IR/FO/SO), W-LSB encoding and the drb-ContinueROHC mechanism carry over unchanged. The main NR differences are contextual, not in ROHC itself: NR voice sits on a QoS-flow/SDAP-mapped DRB (so you must confirm the flow maps to the ROHC DRB), and NR's larger bandwidths and SPS/configured-grant sizing make the per-packet saving compound differently — but the compression machinery is common heritage.
Summary
ROHC is what makes the VoNR voice bearer economical. The chain is short and worth carrying: a VoNR packet is a 30–60 byte codec frame under a 40–60 byte RTP/UDP/IP header sent 50 times a second, so the header dominates. ROHC exploits the fact that the static fields never change and the sequence-number/timestamp move in fixed steps, collapsing the header to 1–3 bytes once the compressor reaches SO state.
When you debug VoNR capacity or voice-quality issues, walk the same path every time: confirm ROHC is actually enabled with profile 0x0001 on the DRB the 5QI=1 flow maps to; confirm the compressor reaches and stays in SO state (mostly UO-0 packets, 1–3 B headers); confirm the learned timestamp stride matches the codec; and watch for CRC_FAIL/IR bursts around radio loss and handovers. The first of those that does not line up is usually your root cause — a config that left compression off, a profile that ignored the RTP stride, a context that keeps resetting, or a mobility event that dropped the context because drb-ContinueROHC was not honoured.
Quick Q&A
Q. Why is ROHC essential for VoNR but not for a big file download?
A. It is about the header-to-payload ratio. A VoNR AMR-WB frame is only ~30–60 bytes but its RTP/UDP/IP header is 40–60 bytes, so the header can exceed the payload and repeats 50 times a second. Compressing it to ~3 bytes roughly doubles the useful payload ratio and multiplies cell voice capacity. A file download has a ~1500-byte payload, so a 40-byte header is negligible — nothing worth compressing, and the network usually leaves ROHC off on that DRB.
Q. Which ROHC profile does voice use, and where is it enabled?
A. Profile 0x0001 (RTP/UDP/IP) — the RTP-aware profile. It is enabled per DRB by RRC in PDCP-Config, via headerCompression set to rohc with the profile list and maxCID, on the 5QI=1 GBR voice bearer. Profiles 0x0002 (UDP/IP) and 0x0004 (IP) exist but are not the voice media profile.
Q. Where in the PDCP chain does ROHC run, and what state gives the big gain?
A. It is a PDCP function (TS 38.323), running as compressor/decompressor inside the PDCP entity, applied before ciphering on transmit (it must read plaintext headers) and after deciphering on receive. The saving comes in the SO state: after the initial IR state and FO state establish the context, the steady voice stream sits in SO state sending 1–3 byte headers.
Q. Why does the AMR/AMR-WB codec make ROHC so effective?
A. Both codecs emit one frame every 20 ms (50/s), so the RTP timestamp advances by a fixed stride (+160 for AMR, +320 for AMR-WB) every packet. That perfect regularity lets profile 0x0001 stop sending the timestamp entirely and extrapolate it — leaving only a few sequence-number bits to transmit.
Q. What makes ROHC “robust” against radio loss, and what happens at handover?
A. W-LSB sequence-number encoding tolerates a few lost packets without desync, a per-packet CRC catches bad reconstructions, and periodic IR state refreshes (plus NACK feedback in O/R modes) bound the recovery time. At PDCP re-establishment the context is normally lost, forcing a fresh IR state burst — unless drb-ContinueROHC is set so the context is carried across the handover.
Where this connects
ROHC on the voice bearer is one piece of the VoNR picture — it sits inside PDCP, feeds the periodically-scheduled voice DRB, and builds on the general header-compression machinery. Follow these to see the layers above and below it.