{"slug":"dtmf-handling","title":"DTMF Handling — RFC 2833, SIP INFO, In-band Audio","tags":["dtmf","sip","rfc-2833","telephony","ivr","signaling"],"agent_summary":"DTMF (touch-tone) digits travel three ways: in-band audio in the RTP stream, RFC 2833/4733 named telephone events in RTP, or SIP INFO messages out-of-band. RFC 2833 is the default for modern IP telephony. SIP INFO is fallback when codec/transcoding strips RFC 2833 events. In-band fails on low-bitrate codecs and is deprecated for IP-to-IP calls.","trigger_phrases":["DTMF in band","RFC 2833","SIP INFO DTMF","telephone events","DTMF not working","touch tone digits","RFC 4733"],"runnable":false,"markdown":"\n# DTMF Handling\n\nDTMF (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.\n\n## The three transports\n\n### In-band (audio)\n\nTwo 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.\n\n### RFC 2833 / RFC 4733 (named telephone events in RTP)\n\nThe 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.\n\n- Negotiated in SDP: `a=rtpmap:101 telephone-event/8000` and `a=fmtp:101 0-15`\n- Both endpoints must advertise the same payload type for it to work\n- Survives codec transcoding as long as both legs negotiate `telephone-event`\n- Default on SignalWire, Twilio, and most modern SIP stacks\n\n### SIP INFO (out-of-band)\n\nDTMF 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.\n\n- Fallback when RFC 2833 isn't negotiated or transcoding strips it\n- Mandatory for some legacy PBX integrations\n- Higher latency than RFC 2833 because INFO goes through the SIP proxy chain\n- SignalWire emits SIP INFO when the customer endpoint requested it\n\n## Negotiation in SDP\n\nA SIP INVITE advertises supported DTMF transports in the SDP offer:\n\n```\nm=audio 16384 RTP/AVP 0 8 101\na=rtpmap:0 PCMU/8000\na=rtpmap:8 PCMA/8000\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-15\n```\n\nThe `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.\n\n## How SignalWire reads DTMF in SWML\n\n```yaml\n- prompt:\n    play: say:Press one for sales, two for support\n    max_digits: 1\n    terminators: \"#\"\n    digit_timeout: 5\n```\n\nSignalWire'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.\n\n## How SignalWire emits DTMF (outbound)\n\nUse the `send_digits` SWML verb mid-call:\n\n```yaml\n- send_digits:\n    digits: \"1234#\"\n```\n\nBy default emits RFC 2833. To force SIP INFO on a particular leg, configure the connection endpoint with `dtmf_method: \"info\"`.\n\n## Common failure modes\n\n| Symptom | Likely cause | Fix |\n|---|---|---|\n| IVR responds to first press, then stops | Transcoder strips RFC 2833, second leg only sees in-band | Force SIP INFO on the egress leg |\n| All presses ignored | RFC 2833 negotiated but payload types differ between legs | Align SDP — payload 101 both sides |\n| Some digits duplicated | RFC 2833 retransmissions read as repeat presses | Reduce `dtmf_redundancy` or use SIP INFO |\n| 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 |\n| Test phone works, customer phone doesn't | Customer's softphone advertises in-band only | Update softphone config or force SIP INFO |\n\n## Codec-DTMF compatibility\n\n| Codec | In-band | RFC 2833 | SIP INFO |\n|---|---|---|---|\n| G.711 (PCMU/PCMA) | Works | Works | Works |\n| G.722 | Works | Works | Works |\n| Opus | Mangled | Works | Works |\n| G.729 | Mangled | Works | Works |\n| AMR | Mangled | Works | Works |\n\n## DTMF in BYO SIP trunks (VAPI, LiveKit, Retell, Bland)\n\nMost AI voice platforms expect RFC 2833. If the AI is \"not hearing\" the caller pressing a digit:\n\n1. Check the SDP negotiated on the BYO trunk leg — does it include `telephone-event/8000`?\n2. If not, set the BYO trunk's `dtmf_method` to `rfc2833` in the platform config.\n3. If RFC 2833 is negotiated but still fails, capture RTP and look for payload type 101 events.\n4. As a last resort, switch the BYO trunk to SIP INFO mode.\n\n## References\n\n- RFC 2833 — RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals (deprecated)\n- RFC 4733 — RTP Payload for DTMF Digits, Telephony Tones, and Telephony Signals (active)\n- RFC 6086 — SIP INFO Method and Package Framework\n- RFC 5743 — Definition of the application/dtmf-relay Content-Type\n","html":"<h1>DTMF Handling</h1>\n<p>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.</p>\n<h2>The three transports</h2>\n<h3>In-band (audio)</h3>\n<p>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.</p>\n<h3>RFC 2833 / RFC 4733 (named telephone events in RTP)</h3>\n<p>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.</p>\n<ul>\n<li>Negotiated in SDP: <code>a=rtpmap:101 telephone-event/8000</code> and <code>a=fmtp:101 0-15</code></li>\n<li>Both endpoints must advertise the same payload type for it to work</li>\n<li>Survives codec transcoding as long as both legs negotiate <code>telephone-event</code></li>\n<li>Default on SignalWire, Twilio, and most modern SIP stacks</li>\n</ul>\n<h3>SIP INFO (out-of-band)</h3>\n<p>DTMF digits are sent as SIP INFO messages with a <code>Content-Type: application/dtmf-relay</code> or <code>application/dtmf</code> body. Travels the signaling path, not the media path.</p>\n<ul>\n<li>Fallback when RFC 2833 isn't negotiated or transcoding strips it</li>\n<li>Mandatory for some legacy PBX integrations</li>\n<li>Higher latency than RFC 2833 because INFO goes through the SIP proxy chain</li>\n<li>SignalWire emits SIP INFO when the customer endpoint requested it</li>\n</ul>\n<h2>Negotiation in SDP</h2>\n<p>A SIP INVITE advertises supported DTMF transports in the SDP offer:</p>\n<pre><code>m=audio 16384 RTP/AVP 0 8 101\na=rtpmap:0 PCMU/8000\na=rtpmap:8 PCMA/8000\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-15\n</code></pre>\n<p>The <code>101</code> 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.</p>\n<h2>How SignalWire reads DTMF in SWML</h2>\n<pre><code class=\"language-yaml\">- prompt:\n    play: say:Press one for sales, two for support\n    max_digits: 1\n    terminators: \"#\"\n    digit_timeout: 5\n</code></pre>\n<p>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 <code>prompt_value</code> for downstream branching.</p>\n<h2>How SignalWire emits DTMF (outbound)</h2>\n<p>Use the <code>send_digits</code> SWML verb mid-call:</p>\n<pre><code class=\"language-yaml\">- send_digits:\n    digits: \"1234#\"\n</code></pre>\n<p>By default emits RFC 2833. To force SIP INFO on a particular leg, configure the connection endpoint with <code>dtmf_method: \"info\"</code>.</p>\n<h2>Common failure modes</h2>\n<p>| Symptom | Likely cause | Fix |\n|---|---|---|\n| IVR responds to first press, then stops | Transcoder strips RFC 2833, second leg only sees in-band | Force SIP INFO on the egress leg |\n| All presses ignored | RFC 2833 negotiated but payload types differ between legs | Align SDP — payload 101 both sides |\n| Some digits duplicated | RFC 2833 retransmissions read as repeat presses | Reduce <code>dtmf_redundancy</code> or use SIP INFO |\n| 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 |\n| Test phone works, customer phone doesn't | Customer's softphone advertises in-band only | Update softphone config or force SIP INFO |</p>\n<h2>Codec-DTMF compatibility</h2>\n<p>| Codec | In-band | RFC 2833 | SIP INFO |\n|---|---|---|---|\n| G.711 (PCMU/PCMA) | Works | Works | Works |\n| G.722 | Works | Works | Works |\n| Opus | Mangled | Works | Works |\n| G.729 | Mangled | Works | Works |\n| AMR | Mangled | Works | Works |</p>\n<h2>DTMF in BYO SIP trunks (VAPI, LiveKit, Retell, Bland)</h2>\n<p>Most AI voice platforms expect RFC 2833. If the AI is \"not hearing\" the caller pressing a digit:</p>\n<ol>\n<li>Check the SDP negotiated on the BYO trunk leg — does it include <code>telephone-event/8000</code>?</li>\n<li>If not, set the BYO trunk's <code>dtmf_method</code> to <code>rfc2833</code> in the platform config.</li>\n<li>If RFC 2833 is negotiated but still fails, capture RTP and look for payload type 101 events.</li>\n<li>As a last resort, switch the BYO trunk to SIP INFO mode.</li>\n</ol>\n<h2>References</h2>\n<ul>\n<li>RFC 2833 — RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals (deprecated)</li>\n<li>RFC 4733 — RTP Payload for DTMF Digits, Telephony Tones, and Telephony Signals (active)</li>\n<li>RFC 6086 — SIP INFO Method and Package Framework</li>\n<li>RFC 5743 — Definition of the application/dtmf-relay Content-Type</li>\n</ul>\n"}