TEL-6986: Generate silence toward A-leg from hold path - #574
Closed
minhtuan1407-telnyx wants to merge 1 commit into
Closed
TEL-6986: Generate silence toward A-leg from hold path#574minhtuan1407-telnyx wants to merge 1 commit into
minhtuan1407-telnyx wants to merge 1 commit into
Conversation
minhtuan1407-telnyx
force-pushed
the
jira-tel-6986
branch
3 times, most recently
from
April 30, 2026 15:16
f0123b1 to
7f9ba95
Compare
minhtuan1407-telnyx
force-pushed
the
jira-tel-6986
branch
from
April 30, 2026 15:18
7f9ba95 to
3c76dca
Compare
Author
|
Superseded by Option A in #576. The new PR fixes TEL-6986 by preventing B-leg — 🪽 Hermes War Room |
Author
|
Closing as superseded by #576 per Option A direction. — 🪽 Hermes War Room |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes TEL-6986 using the existing bridge variable:
When
bridge_generate_comfort_noiseis enabled and the bridge source leg is held, FreeSWITCH now generates silence RTP toward the non-held target leg. It still sends zero RTP toward the held/inactive leg.This keeps the PR minimal by reusing FreeSWITCH's existing bridge-generated-comfort-noise knob instead of adding a new channel variable.
Existing variable reused
FreeSWITCH already has bridge-level generated silence/comfort-noise support:
bridge_generate_comfort_noiseExisting source behavior in
src/switch_ivr_bridge.c:bridge_generate_comfort_noisefromchan_a,trueas default generated silence divisor1400,Existing
docs/ChangeLogdescribes it as:TEL-6986 is the same class of problem, but the no-audio condition comes from SIP protocol hold /
a=inactiverather than a normal CNG frame.Problem
During B-leg protocol hold, FreeSWITCH correctly suppresses media toward the held/inactive B-leg. However, the bridge path can also stop sending RTP toward the non-held A-leg.
Failure mode before this fix:
Prior log-based attempts using hold music / broadcast /
silence_stream://-1were insufficient because playback could execute while the PCAP still showed no sustained FS -> A RTP.Final implementation
1. Reuse existing generated-silence frame setup
The PR keeps the existing
bridge_generate_comfort_noisesetup path and only tracks codec ownership with:silence_codec_initializedCleanup now destroys the codec only if it was actually initialized.
2. Add a small helper for forced hold-generated silence writes
write_hold_generated_silence(...)This helper:
switch_generate_sln_silence(), andSWITCH_IO_FLAG_FORCE.3. Use directional hold predicates
Each bridge loop computes:
This is required because SIP/SDP protocol hold can set
CF_LEG_HOLDINGwithout using only the local/APICF_HOLDpath.4. Generate only from held source to non-held target
Generated silence is written only when:
That means:
The same guard is present in both the suspend/hold path and the normal post-read bridge path, because hold can enter the suspended branch before the normal write branch.
5. Do not use normal writes while either side is held
The normal bridge write path is guarded by:
This avoids forwarding normal media into held endpoints. Hold-generated media is handled by the explicit generated-silence path above.
6. Force only the guarded generated-silence write through the media-flow gate
The retest showed the target A-leg can have target audio flow set to inactive while B is on hold (
SWITCH_MEDIA_FLOW_INACTIVE, enum value3).switch_core_media_write_frame()normally returns success without sending RTP when target audio flow is notSENDRECVorSENDONLY.To avoid generated silence being silently dropped, the hold-generated-silence helper writes with:
SWITCH_IO_FLAG_FORCEand the audio media-flow gate now preserves normal behavior except when FORCE is explicitly set:
Normal writes still respect media-flow direction. Only the guarded generated-silence write can bypass this gate.
Why not
send_silence_when_idle?HWR checked the existing variables thoroughly.
send_silence_when_idleis an IVR/session idle-loop variable used by sleep, park, digit collection, and SRTP idle-gap handling. It writes silence to the current idle session and does not implement bridge-direction hold behavior.TEL-6986 requires bridge-specific asymmetric behavior:
So
send_silence_when_idleis not the right knob.Safety / scope
bridge_generate_comfort_noise; no new channel variable.Validation evidence
The TEL-6986 behavior was validated on the prior patch iteration with the same bridge hold write mechanics using an explicit temporary opt-in variable. HWR then re-reviewed the source and switched the opt-in to the existing
bridge_generate_comfort_noisevariable to minimize the PR surface.The exact current head should be retested with:
Expected behavior is unchanged because the current source uses the same prepared generated-silence frame and the same guarded forced write path:
Latest validation artifacts from prior equivalent patch iteration
TEL-6986.pcap24a0c79225916f62ea1f11a0ee721ef26ebe258a0748c49d06f35df6f281672a290018.283666sTEL-6986.log15758cf0336c742cc9e3eb462c3e3c4a30db110a14f211f25326ef2406b00e15SIP / SDP window:
1015,t=7.156475, SDPa=inactive.1051,t=7.423097, SDPa=inactive.1817,t=12.533111, SDPa=sendrecv.1846,t=12.801459, SDPa=sendrecv.Strict confirmed-hold window:
RTP counts from that prior equivalent patch iteration:
FS -> A continuity:
50.114.144.37:29014 -> 171.240.253.53:4022252packets.1053,t=7.443045, seq5424, RTP timestamp43040.1814,t=12.519906, seq5675, RTP timestamp83680.20.076ms / 20.227ms / 40.183ms.0.Result
The implementation keeps the required TEL-6986 behavior while using FreeSWITCH's existing bridge-generated comfort-noise variable: