SIP Trunk DTMF Not Working: Diagnose and Fix on Asterisk
When SIP trunk DTMF is not working, the cause is almost always a mode or payload type mismatch. Set the trunk to RFC 4733 (dtmf_mode=rfc4733), confirm telephone-event is in the SDP of both the INVITE and 200 OK, then verify with a capture.
- Use RFC 4733 (telephone-event) by default; it is codec independent and supported by nearly all carriers.
- Read the SDP in the INVITE and 200 OK: both sides must list a=rtpmap:101 telephone-event/8000 with the same payload type that appears in the RTP packets.
- Inband DTMF fails on G.729 and other low-bitrate codecs because compression distorts the dual tone; G.711 usually passes it.
- First decide which direction fails (caller to PBX or PBX to far end), then change one setting at a time and retest.
- Isolate the trunk from the dialplan with a simple Read() test call before editing IVR logic.
What are the three DTMF methods and how do they differ?
DTMF digits can travel three ways, and both ends of a call leg must agree on one. A mismatch is the root of most cases where SIP trunk DTMF is not working, because each side then listens in a place where the other is not sending.
RFC 4733 (formerly RFC 2833) sends digits as RTP telephone-event packets. They are in the RTP session but are not audio, so the codec does not matter. SIP INFO sends each digit as a signaling message, usually with Content-Type application/dtmf-relay. Inband encodes real dual tones in the audio, so the codec and any transcoding directly affect it.
| Method | Where digits travel | Codec dependent | Typical use | Main risk |
|---|---|---|---|---|
| RFC 4733 (rfc2833) | RTP telephone-event packets, dynamic payload type (usually 101) | No | Default for nearly all carriers | Payload type mismatch, SDP stripped by SBC |
| SIP INFO | SIP signaling (application/dtmf-relay or application/dtmf) | No | Some legacy or specific providers | Not universally supported, timing differs from audio |
| Inband | Audible tones in the audio stream | Yes: fine on G.711, poor on G.729/low-bitrate | Last resort | Missed or distorted digits, doubling if combined with RFC 4733 |
Why is RFC 4733 the recommended default?
RFC 4733 is reliable because the digit is an explicit event with a start, duration and end, not a tone the receiver must detect in noisy audio. It survives any codec, including G.729 and Opus, and the vast majority of carriers support it.
Because the event carries its own duration, the receiver does not need to guess when a key was released. That is why a held key on a mobile phone still produces one clean digit in an IVR, where inband detection might report two.
Use inband only when the provider cannot do RFC 4733 or INFO. Treat it as a last resort, and then keep the call on G.711 end to end.
SIP trunk DTMF not working: how do I find which leg and direction is failing?
Work in this order so you stop guessing. The symptom usually tells you where to look first.
| Symptom | Likely cause | First check |
|---|---|---|
| No digits at all from caller | Mode mismatch, or telephone-event stripped from SDP | SDP in INVITE and 200 OK |
| Digits work on internal extensions, not on trunk | Trunk config differs from extension config | Trunk dtmf_mode versus extension dtmf_mode |
| Doubled digits | Inband and RFC 4733 both detected (for example dtmf_mode=auto with an inband-leaking path) | Set one explicit mode |
| Missing or intermittent digits | Events too short (under about 40 to 50 ms) or jittery RTP | Capture event durations; check jitter |
| Works on G.711, fails on G.729 | Inband in use over a compressed codec | Core show channel for codec; switch to rfc4733 |
| Caller keys fail, but PBX-to-far-end digits work (or the reverse) | One direction's payload type or SDP is wrong | Compare payload type per direction in the capture |
| Fails after provider change or migration | Different payload type, SBC or NAT device rewriting SDP | Compare SDP against the old working one |
- Decide the direction: does the PBX fail to hear the caller (IVR, voicemail PIN, ConfBridge) or does the far end fail to hear digits the PBX sends (for example dialing out through an auto-attendant)?
- Read the SDP in both the INVITE and the 200 OK.
- Capture RTP while pressing a key and confirm telephone-event packets appear.
- Change one setting, retest, and only then move on.
What should the SDP look like, and what does a payload type mismatch look like?
Telephone-event uses a dynamic payload type (96 to 127). It is usually 101, but some carriers use 100 or another number. Asterisk normally mirrors the type the other side offers, so trouble appears mainly with misconfigured SBCs or B2BUAs that advertise one number and send another.
A healthy offer lists the codec and the event line, and the answer agrees:
INVITE (offer)
m=audio 12345 RTP/AVP 0 8 101
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
200 OK (answer)
m=audio 20000 RTP/AVP 0 101
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
BROKEN: answer has no telephone-event line, or says
a=rtpmap:100 telephone-event/8000
but the RTP packets actually carry payload type 101.How do I set the DTMF mode in PJSIP and FreePBX?
In PJSIP the setting is dtmf_mode on the endpoint. Values are rfc4733, inband, info and auto. Auto prefers rfc4733 and falls back to inband if the peer did not negotiate telephone-event. For inband on PJSIP, the endpoint must use a codec that carries tones, in practice ulaw or alaw.
The snippet below belongs in pjsip.conf only. If you are still on Asterisk 20 or earlier with the legacy chan_sip driver, the equivalent is a separate setting, dtmfmode=rfc2833, placed in the peer's stanza in sip.conf (not pjsip.conf). chan_sip was removed in Asterisk 21, so on current releases use PJSIP and skip that option.
In FreePBX, open the trunk, go to the pjsip Advanced tab (or the chan_sip settings on older systems) and set DTMF Mode. Also check each extension's own DTMF Mode, because internal and trunk legs are configured separately. Then click Submit and Apply Config.
Changing a trunk on a live system reloads PJSIP configuration and can briefly disrupt registrations. Do it outside peak hours.
; File: /etc/asterisk/pjsip.conf (Asterisk 12+ with res_pjsip)
; On FreePBX, set these through the trunk's GUI fields instead.
[mytrunk]
type=endpoint
dtmf_mode=rfc4733
allow=!all,ulaw,alaw
; If the provider only supports INFO, use instead:
; dtmf_mode=infoHow do I verify with the Asterisk CLI?
Start with signaling, then RTP, then the channel. Run the Asterisk CLI commands inside the console during a live test call, and run the shell commands from a normal terminal.
- Attach to the console, then at the asterisk prompt run pjsip set logger on and look for telephone-event in the SDP of the INVITE and 200 OK.
- At the same prompt run rtp set debug on and press a key; you should see DTMF events logged.
- Run core show channels, then core show channel PJSIP/mytrunk-00000001 (use your real channel name) and check NativeFormats, ReadFormat and WriteFormat to see whether the call is being transcoded.
- When finished, run rtp set debug off and pjsip set logger off, since both are verbose and add load.
# Shell commands only (run in a terminal on the PBX)
# Attach to the Asterisk console, then type the CLI commands from the steps there
asterisk -rvvvv
# Interactive SIP flow view in a second terminal
sngrep -d any port 5060
# Capture signaling and RTP to a file for Wireshark
tcpdump -i any -n -s0 -w /tmp/dtmf.pcap udp port 5060 or udp portrange 10000-20000 How do I confirm with Wireshark or sngrep, and isolate the dialplan?
In Wireshark, filter rtp.p_type == 101 (or your negotiated number) and press a key during the call. You should see a short burst of packets with the event field and an end bit. Telephony > RTP > RTP Streams lists payload types per stream, so a stream carrying type 100 when the SDP said 101 is your mismatch. For SIP INFO, filter sip.Method == "INFO" and look for Content-Type application/dtmf-relay with Signal=5 and Duration lines.
Other causes to rule out are NAT or an SBC rewriting SDP and stripping telephone-event, both sides set to different modes, and transcoding or media-path changes (direct_media toggling) that move the stream through a device that breaks the events. IVR, voicemail and ConfBridge PIN prompts all use the same detection on the incoming channel, and Read(), WaitExten() and Background() only see what the channel driver hands them.
To separate the trunk from the dialplan, route a test DID to a minimal context. If Read works from an internal extension but not from the trunk, the problem is the trunk leg.
; extensions_custom.conf
[dtmf-test]
exten => s,1,Answer()
same => n,Read(DIGITS,beep,4,,1,10)
same => n,Verbose(1,Got digits: ${DIGITS})
same => n,SayDigits(${DIGITS})
same => n,Hangup() Common questions
Why does DTMF fail only with G.729?
G.729 compresses audio with a model tuned for speech, which distorts the pure dual tones that inband detection needs. Switch to RFC 4733 so digits travel as RTP events, or use G.711 on that leg if inband is mandatory.
Why do I get duplicated digits in my IVR?
Usually the same key is seen twice: once as a telephone-event and once as inband tone leaking through the audio. Set an explicit dtmf_mode=rfc4733 instead of auto and avoid paths that also pass the tone.
Does Asterisk need payload type 101 specifically?
No. Asterisk mirrors the dynamic type the peer offers, so 100 or 96 to 127 work if SDP and RTP agree. Failures occur when a device advertises one number in SDP but sends another.
What is the minimum DTMF duration that gets recognized?
Detectors commonly need roughly 40 to 50 ms of event duration, so very short or jittery events can be dropped. Check durations in the capture and look at jitter or packet loss on the path.
Can I use SIP INFO if my provider does not support RFC 4733?
Yes, set dtmf_mode=info on the trunk endpoint, provided the provider confirms it supports INFO. Confirm in a capture that INFO messages carry the correct Signal and Duration values.