Skip to content

feat(sip_client): add auth_username (3CX Auth-ID) and accept SIP INFO / marker-less RFC 2833 DTMF - #319

Merged
eigger merged 1 commit into
masterfrom
feat/sip-auth-username-dtmf-rx
Aug 31, 2026
Merged

feat(sip_client): add auth_username (3CX Auth-ID) and accept SIP INFO / marker-less RFC 2833 DTMF#319
eigger merged 1 commit into
masterfrom
feat/sip-auth-username-dtmf-rx

Conversation

@eigger

@eigger eigger commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Closes #318.

1. auth_username — Digest auth ID separate from the extension

3CX v20 (and other PBXs) issue an Authentication ID that differs from the
extension number. Digest username= always carried the extension, so REGISTER
failed with 403 Credentials don't match.

sip_client:
  username: "100"             # extension: From / To / Contact
  auth_username: "<auth-id>"  # optional: Digest username only
  password: "<password>"

Applied to both the REGISTER and the INVITE challenge. Omitting the option
keeps the current behaviour exactly (username is used for Digest).

2. DTMF receive: marker-less RFC 2833 + SIP INFO

on_dtmf only fired on telephone-event packets that carried the RTP marker
bit, so Yealink DECT handsets (W70B/W73H) and the 3CX Android app never
triggered a door relay.

  • The telephone-event decoder now reports a digit once per (event, RTP
    timestamp)
    and ignores the marker bit entirely. Since every packet of one
    event repeats its timestamp, this also swallows the retransmitted end
    packets — firing on the end bit instead would have fired ~3x per keypress.
    State is reset on session start/stop, so an identical packet in the next call
    is not mistaken for a duplicate.
  • SIP INFO with application/dtmf-relay (Signal=1) or application/dtmf
    now fires the trigger, answered with 200 OK as before. The body is parsed
    through Signal=, so Duration=250 is not misread as digit D; * / #
    are accepted literally and as event codes 10 / 11. INFO outside an
    established call is answered but does not fire the trigger.

In-band audio tones remain undecoded.

Existing on_dtmf automations are unchanged.

Tests

Digit decoding, the receive de-duplication and the INFO body parser live in
dtmf.h / dtmf.cpp with no ESPHome dependency, and are covered by 10 new
cases in tests/native/sip_sdp/test_dtmf.cpp (wired into run.sh and the
suite README).

  • tests/native/sip_sdp/ — all pass
  • esphome compile tests/components/sip_client/test.esp32-idf.yaml — succeeds
    (the test YAML now also sets auth_username, so CI covers the new option)

On-device verification against 3CX v20, a Yealink desk phone, Yealink DECT and
the 3CX Android app is still pending — @AlexW85 offered to test in #318.

🤖 Generated with Claude Code

… DTMF

Two fixes for 3CX and DECT deployments (#318).

auth_username: PBXs that separate the Digest authentication user from the
extension (3CX v20 "Authentication ID") rejected REGISTER with "credentials
don't match", because Digest username= always carried the extension. The new
optional auth_username feeds REGISTER and INVITE Digest only; From / To /
Contact keep using username, so the device still presents its extension.
Omitted = today's behaviour.

DTMF receive: on_dtmf only fired on RFC 2833 packets carrying the RTP marker
bit, so Yealink DECT handsets and the 3CX Android app (marker-less, or SIP
INFO) never opened a door relay. The telephone-event decoder now reports a
digit once per (event, RTP timestamp) regardless of the marker, which also
covers the retransmitted end packets, and SIP INFO with
application/dtmf-relay or application/dtmf fires the trigger too. The INFO
body is parsed via Signal=, so "Duration=250" is no longer read as digit D,
and * / # are accepted both literally and as event codes 10 / 11.

Digit decoding and the receive de-duplication live in dtmf.h/.cpp and are
covered by the native test suite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@eigger
eigger merged commit ece4e2d into master Aug 31, 2026
10 checks passed
@eigger
eigger deleted the feat/sip-auth-username-dtmf-rx branch August 31, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add auth_username (3CX Auth-ID) and accept SIP INFO / marker-less RFC2833 DTMF

1 participant