feat(sip_client): accept DTMF from ATAs on unnegotiated PTs and looser INFO bodies - #320
Merged
Conversation
…r INFO bodies Ported from the hass-sip Python client, which grew both after field reports from ATA / VoIP-adapter users. Some adapters send RFC 2833 without ever offering telephone-event in their SDP, or on a different dynamic payload type than the one negotiated, so the keypress was dropped. A 4-byte payload on a dynamic PT (96-127) that is not the negotiated audio PT is the telephone-event shape and is now decoded as one, logged once per session. Sessions that negotiated no telephone-event at all now say so, since inbound DTMF then depends on this fallback or SIP INFO. The INFO parser also accepts what gateways actually send: the `d=` and `dtmf=` keys besides `Signal=`, the `audio/telephone-event` content type, and a body with no Content-Type at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Follow-up to #319. Both changes are ports of the hass-sip Python client, which
grew them after field reports from ATA / VoIP-adapter users; the ESPHome
component did not have them.
1. RFC 2833 on an unnegotiated payload type
Some adapters send telephone-event without ever offering it in their SDP, or on
a different dynamic PT than the one negotiated. The receive path only accepted
the negotiated PT, so those keypresses were dropped entirely.
A 4-byte payload on a dynamic PT (96-127) that is not the negotiated audio PT
is the RFC 4733 shape — event, E|R|volume, duration — and never an audio frame,
so it is now decoded as a telephone-event. The acceptance is logged once per
session, and a session that negotiated no telephone-event at all now warns that
inbound DTMF depends on this fallback or SIP INFO.
2. Looser SIP INFO bodies
The parser now takes what gateways actually send:
d=anddtmf=besidesSignal=audio/telephone-eventbesidesapplication/dtmf-relayandapplication/dtmfContent-Typeheader at allDuration=250is still not read as digitD, and a non-DTMF content type isstill rejected.
Tests
Two new cases in
tests/native/sip_sdp/test_dtmf.cpp(
info_alternate_keys_and_types,unnegotiated_telephone_event_pt), thepayload-type decision extracted as
is_unnegotiated_telephone_event()indtmf.hso it is testable on the host.tests/native/sip_sdp/— all passesphome compile tests/components/sip_client/test.esp32-idf.yaml— succeedsNot merged yet on purpose: this widens the DTMF receive path beyond what #318
asked for, so it is worth holding until the on-device results from #318 land.
🤖 Generated with Claude Code