DTMF Handling
DTMF (Dual-Tone Multi-Frequency) is the touch-tone signal generated when a caller presses a phone keypad digit. In IP telephony there are three distinct transports for the same digit. Choosing the right one — or mishandling a transcoded leg — is the single most common cause of "the IVR doesn't hear my presses" bugs.
The three transports
In-band (audio)
Two sinusoidal tones mixed into the RTP audio stream. Works perfectly on G.711 (uncompressed) because the tones survive. Fails on G.729, Opus, and other low-bitrate codecs because lossy compression mangles the tone purity. Avoid for IP-to-IP. Acceptable only when both legs are G.711 and no transcoder sits between them.
RFC 2833 / RFC 4733 (named telephone events in RTP)
The IP-native standard. DTMF digits are sent as named events in their own RTP payload type (typically 101), with explicit start/stop markers and the digit name ("1", "*", etc.). RFC 2833 was superseded by RFC 4733 in 2006 but the original name persists.
- Negotiated in SDP:
a=rtpmap:101 telephone-event/8000anda=fmtp:101 0-15 - Both endpoints must advertise the same payload type for it to work
- Survives codec transcoding as long as both legs negotiate
telephone-event - Default on SignalWire, Twilio, and most modern SIP stacks
SIP INFO (out-of-band)
DTMF digits are sent as SIP INFO messages with a Content-Type: application/dtmf-relay or application/dtmf body. Travels the signaling path, not the media path.
- Fallback when RFC 2833 isn't negotiated or transcoding strips it
- Mandatory for some legacy PBX integrations
- Higher latency than RFC 2833 because INFO goes through the SIP proxy chain
- SignalWire emits SIP INFO when the customer endpoint requested it
Negotiation in SDP
A SIP INVITE advertises supported DTMF transports in the SDP offer:
m=audio 16384 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-15
The 101 line is RFC 2833. If absent, the other party falls back to SIP INFO or in-band. Most production stacks fail safely back to SIP INFO when RFC 2833 negotiation is missing.
How SignalWire reads DTMF in SWML
- prompt:
play: say:Press one for sales, two for support
max_digits: 1
terminators: "#"
digit_timeout: 5
SignalWire's prompt verb accepts DTMF from any of the three transports. The script never has to specify which — the platform handles negotiation. The captured digit lands in prompt_value for downstream branching.
How SignalWire emits DTMF (outbound)
Use the send_digits SWML verb mid-call:
- send_digits:
digits: "1234#"
By default emits RFC 2833. To force SIP INFO on a particular leg, configure the connection endpoint with dtmf_method: "info".
Common failure modes
| Symptom | Likely cause | Fix |
|---|---|---|
| IVR responds to first press, then stops | Transcoder strips RFC 2833, second leg only sees in-band | Force SIP INFO on the egress leg |
| All presses ignored | RFC 2833 negotiated but payload types differ between legs | Align SDP — payload 101 both sides |
| Some digits duplicated | RFC 2833 retransmissions read as repeat presses | Reduce dtmf_redundancy or use SIP INFO |
| Digits work on cellular but not on WiFi | Codec changes between G.711 (cell) and Opus (WiFi), in-band tones survive only on G.711 | Use RFC 2833 or SIP INFO end-to-end |
| Test phone works, customer phone doesn't | Customer's softphone advertises in-band only | Update softphone config or force SIP INFO |
Codec-DTMF compatibility
| Codec | In-band | RFC 2833 | SIP INFO | |---|---|---|---| | G.711 (PCMU/PCMA) | Works | Works | Works | | G.722 | Works | Works | Works | | Opus | Mangled | Works | Works | | G.729 | Mangled | Works | Works | | AMR | Mangled | Works | Works |
DTMF in BYO SIP trunks (VAPI, LiveKit, Retell, Bland)
Most AI voice platforms expect RFC 2833. If the AI is "not hearing" the caller pressing a digit:
- Check the SDP negotiated on the BYO trunk leg — does it include
telephone-event/8000? - If not, set the BYO trunk's
dtmf_methodtorfc2833in the platform config. - If RFC 2833 is negotiated but still fails, capture RTP and look for payload type 101 events.
- As a last resort, switch the BYO trunk to SIP INFO mode.
References
- RFC 2833 — RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals (deprecated)
- RFC 4733 — RTP Payload for DTMF Digits, Telephony Tones, and Telephony Signals (active)
- RFC 6086 — SIP INFO Method and Package Framework
- RFC 5743 — Definition of the application/dtmf-relay Content-Type