Repository navigation
feat: add FaxDetector for fax calling-tone detection - #7983
Draft
GSmithApps wants to merge 1 commit into
Draft
GSmithApps wants to merge 1 commit into
GSmithApps wants to merge 1 commit into
Conversation
A fax machine that places a call sends a CNG tone (1100 Hz, 0.5 s on, 3 s off; ITU-T T.30) and no speech. AMD transcribes speech, so a fax times out as `uncertain`, and AMD only runs on outbound calls. Inbound phone agents have had no way to recognize these calls. FaxDetector reads its own AudioStream of the caller's track (before any session noise cancellation) and confirms a fax after two correctly spaced CNG beeps, about 4 s of audio. It only reports; the agent decides whether to tag, hang up, or transfer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Author
|
@chenghao-mou wondering if you could take a peek at this? I know you worked on the AMD 🙏 |
This branch has not been deployed
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.
Summary
Adds
livekit.agents.FaxDetector, which recognizes calls placed by a fax machine.A calling fax sends a CNG tone (1100 Hz, 0.5 s on / 3 s off, ITU-T T.30) and no speech. Today nothing in the stack catches this:
AMDtranscribes speech and classifies it with an LLM, so a fax hitsno_speech_timeoutand settles asuncertain, which the docs say to treat as human. AMD also only runs on outbound calls.livekit/siphas no tone detection or T.38 handling.Inbound phone agents (the common case) receive these calls, play a greeting to a fax machine, and the calls show up as short "early end" calls in users' metrics. A user has asked for this
What it does
FaxDetectoropens its ownrtc.AudioStreamon the caller's track, before any noise cancellation the session applies, and confirms a fax after two CNG beeps of the right length (0.35–0.75 s) at the right spacing (3.0–4.0 s). That takes about 4 s of audio. Requiring the cadence is what keeps a single beep, a steady tone, a busy signal, or speech from triggering it.It only reports (an event and a
wait()result). The agent decides what to do: tag the call, hang up, transfer to a fax line.For SIP participants, listening starts once
sip.callStatus == "active", like AMD.timeout(default 15 s) is wall-clock, counted from when the caller's audio is available.Why a separate helper rather than an AMD category
An AMD
machine-faxcategory for outbound calls (2100 Hz CED answer tone) could still be added later.Open questions (why this is a draft)
livekit/sip, which already decodes the caller audio for every call and could report it inSIPCallInfo? An agent-side helper ships faster and is more flexible; the SIP server would cover every SDK and surface the result in the call record.livekit.agents.FaxDetectorinvoice/fax/.Testing
tests/test_fax_detector.py: 12 unit tests under the virtual-time loop. Synthetic audio is generated at 8 kHz, run through G.711 mu-law, and resampled to 16 kHz. Detects CNG (normal, quiet, after leading silence); ignores a single beep, a steady 1100 Hz tone, a US busy signal, beeps at the wrong spacing, synthetic speech, and silence. Covers event emission, timeout, and a track that sends no frames.livekit-server --dev: a "caller" participant published the synthetic audio as a real track (so it went through Opus). Fax detected after 4.0 s; a speech-only caller ran to timeout with no detection.ruff check,ruff format, andscripts/check_types.py(strict mypy) pass.🤖 Generated with Claude Code