Howwise RSS
VoIP & Phone Systems7 min read

SIP Trunk DTMF Not Working: Diagnose and Fix on Asterisk

Short answer

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.

Key takeaways
  • 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.

MethodWhere digits travelCodec dependentTypical useMain risk
RFC 4733 (rfc2833)RTP telephone-event packets, dynamic payload type (usually 101)NoDefault for nearly all carriersPayload type mismatch, SDP stripped by SBC
SIP INFOSIP signaling (application/dtmf-relay or application/dtmf)NoSome legacy or specific providersNot universally supported, timing differs from audio
InbandAudible tones in the audio streamYes: fine on G.711, poor on G.729/low-bitrateLast resortMissed 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.

SymptomLikely causeFirst check
No digits at all from callerMode mismatch, or telephone-event stripped from SDPSDP in INVITE and 200 OK
Digits work on internal extensions, not on trunkTrunk config differs from extension configTrunk dtmf_mode versus extension dtmf_mode
Doubled digitsInband and RFC 4733 both detected (for example dtmf_mode=auto with an inband-leaking path)Set one explicit mode
Missing or intermittent digitsEvents too short (under about 40 to 50 ms) or jittery RTPCapture event durations; check jitter
Works on G.711, fails on G.729Inband in use over a compressed codecCore 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 wrongCompare payload type per direction in the capture
Fails after provider change or migrationDifferent payload type, SBC or NAT device rewriting SDPCompare SDP against the old working one
  1. 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)?
  2. Read the SDP in both the INVITE and the 200 OK.
  3. Capture RTP while pressing a key and confirm telephone-event packets appear.
  4. 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.
Tip: If the answer lacks telephone-event entirely, the far end or an SBC in the path removed it. Asterisk will then fall back to inband under dtmf_mode=auto, which fails on compressed codecs.

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=info
Warning: FreePBX regenerates pjsip.conf from the GUI. Put manual overrides in the custom files or the GUI fields, or they will be overwritten on the next apply.

How 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.

  1. 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.
  2. At the same prompt run rtp set debug on and press a key; you should see DTMF events logged.
  3. 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.
  4. 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.

Related topics:asteriskfreepbxdtmfsip trunkpjsip