Noise on TX RTP stream at the moment a re-offer (with both RTP/AVP and RTP/SAVP m-lines) is applied to an established plain-RTP call

43 views
Skip to first unread message

Fbyself Shin

unread,
Sep 8, 2026, 5:21:34 AMSep 8
to Sipwise rtpengine
Hi all,
I'm seeing a brief burst of noise on the outgoing (TX) RTP stream at the exact moment rtpengine processes a re-offer, and I'd appreciate help understanding whether this is expected behavior or a misuse of the offer options on my side.
Setup
• rtpengine acts as a media relay (B2BUA controlled by our signaling server) between a WebRTC leg (A) and a SIP/PBX leg (B).
• The call is established as plain RTP end-to-end. B answered with RTP/AVP only (it does not support SRTP), so media flows unencrypted.
• We use OSRTP / legacy offer so the initial offer toward B contains two m-lines sharing the same port and SSRC: one RTP/SAVP (with a=crypto) and one RTP/AVP (no crypto). B picks RTP/AVP.

What triggers the issue :

When A puts the call on hold, our server sends a re-offer to rtpengine. 
The offer request uses these options (rtpengine ng protocol):

transport protocol: RTP/SAVP
OSRTP: offer-legacy
flags: SDES-only-AES_CM_128_HMAC_SHA1_80, codec-strip-all,
       codec-offer-PCMA, codec-offer-PCMU, codec-offer-H264,
       port latching
DTLS: off
ICE: remove
rtcp-mux: demux
ptime: 20
direction: (hold, a=sendonly on the WebRTC side)

The resulting SDP that rtpengine produces toward B again contains both an RTP/SAVP m-line (with a=crypto) and an RTP/AVP m-line, same port/SSRC:

m=audio 55342 RTP/SAVP 8 0
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:+sLivjldL6zDn83KL0URaTemu8qOmp2BkUPrsAis
...
m=audio 55342 RTP/AVP 8 0
...

The problem
At the moment this re-offer is applied by rtpengine — and before B sends its 200 OK (i.e. before the answer is processed) — a short burst of noise appears on the RTP stream that rtpengine sends toward B. Capturing/playing the TX packets confirms the noise is in the media rtpengine emits.
If the exact same call is set up without the SRTP m-line (plain RTP/AVP only, no crypto in any offer/re-offer), the noise does not occur on hold.

My questions
1. When a re-offer contains both RTP/SAVP (with crypto) and RTP/AVP m-lines for the same stream/port/SSRC, how does rtpengine treat the outgoing media at the offer stage, before the answer selects a profile? Since the peer hasn't chosen yet, I'd expect the TX side to stay unchanged until the answer — is that correct?
2. Could applying such a dual-profile re-offer cause rtpengine to re-initialize or re-key the SRTP/crypto context (or otherwise rebuild the media flow) in a way that briefly corrupts the TX stream, even though the active call is plain RTP?
3.Is OSRTP: offer-legacy + transport protocol: RTP/SAVP the correct way to re-offer on a call that was originally negotiated down to plain RTP/AVP? Or should we detect that the established call is plain RTP and re-offer with RTP/AVP only (no crypto) to avoid touching the crypto context?
4. Does port latching combined with a protocol change (RTP/AVP active → RTP/SAVP re-offered on the same port) play any role here?

Environment
• rtpengine version: 13.4
• OS / kernel : Ubuntu 5.15.0-143-generic,  Forwarding: Kernel module

Any guidance on whether this is expected and how to re-offer correctly on a plain-RTP call would be very helpful. I can share full offer/answer ng payloads and a pcap if useful.

Thanks!

Richard Fuchs

unread,
Sep 10, 2026, 7:32:22 AMSep 10
to rtpe...@googlegroups.com
It's been a while since I played with OSRTP so my memory on the particulars of the code is a little hazy, but what's probably happening is that an offer made with SRTP + OSRTP is still primarily an SRTP offer, so until the answer selects the RTP media, media is probably sent as SRTP. Which with SDES is possible since the advertised keys are for egress SRTP. The entire protocol really isn't very good.

You can confirm this by looking at the captured RTP. SRTP packets are a bit larger than their plaintext RTP counterparts.

If you have the option, I would suggest omitting the transport-protocol related flags from the re-invite offer. Without them, rtpengine would leave the negotiated protocol alone and would not switch back to maybe-SRTP. The generated output SDP may or may not be to the client's liking. There is no standard for this, so the expected behaviour is always a bit of guesswork.

In general I would suggest avoiding this mode of OSRTP operation altogether.

Cheers
--
You received this message because you are subscribed to the Google Groups "Sipwise rtpengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtpengine+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/rtpengine/1891659e-4087-4887-9da4-89e507f0d3abn%40googlegroups.com.

Fbyself Shin

unread,
Sep 13, 2026, 10:50:09 PM (13 days ago) Sep 13
to Sipwise rtpengine
Thank you for the detailed explanation — it matches exactly what we observed.

Confirming your hypothesis via packet capture
As you suggested, I checked the captured RTP stream. In the noisy segment I see a run of consecutive 220-byte packets followed by a final 230-byte packet. 
The larger (230-byte) packet is consistent with SRTP encryption (the extra bytes being the SRTP auth tag), while the surrounding 220-byte packets are plain RTP.
This confirms your point: with an SRTP + OSRTP offer, the stream is still treated as primarily SRTP, so a packet is sent as SRTP before the answer selects plain RTP media. 
That mismatch — an SRTP packet arriving while the peer still expects plaintext RTP — is what produces the noise on our side.
Fix applied
Following your recommendation, I removed the SAVP protocol from the re-INVITE (hold/resume) offer, 
so that rtpengine leaves the already-negotiated protocol alone instead of switching back to maybe-SRTP. 
With this change, an RTP call stays RTP on hold/resume and no crypto (SAVP) is offered again.

Thanks again for your feedback — it was very helpful.

2026년 9월 10일 목요일 오후 8시 32분 22초 UTC+9에 rfuchs님이 작성:
Reply all
Reply to author
Forward
0 new messages