steep-balloon-41261
05/13/2026, 12:09 PMtall-airline-16756
05/13/2026, 12:09 PMtall-airline-16756
05/13/2026, 12:09 PMdtmf_received when a SIP participant presses keys.
2) Where to listen
• Register the listener on the Room (e.g., get_job_context().room.on("dtmf_received", handler)). DTMF is a room-level control event, not a media track event.
3) SIP trunk configuration required
• DTMF must be transported by your SIP provider using RFC 2833 (RTP events) or SIP INFO. RFC 2833 is preferred. If the trunk only sends in-band audio DTMF, LiveKit will not detect it reliably.
4) Complete working pattern (concise example)
• Key points: register the room listener early, push received digits into an asyncio.Queue, then await collection with timeout.
Example implementation:
import asyncio
from typing import Optional
from livekit import rtc
from livekit.agents import get_job_context
class DtmfCollector:
def __init__(self):
self._queue: asyncio.Queue[str] = asyncio.Queue()
self._listener_added = False
def on_digit(self, ev: rtc.Dtmf) -> None:
# called by Room event; push digit into async queue thread-safely
loop = asyncio.get_event_loop()
loop.call_soon_threadsafe(self._queue.put_nowait, ev.code)
async def ensure_listener(self):
if self._listener_added:
return
room = get_job_context().room
room.on("dtmf_received", self.on_digit)
self._listener_added = True
def clear(self):
while not self._queue.empty():
try:
self._queue.get_nowait()
except asyncio.QueueEmpty:
break
async def collect(self, max_digits: int = 16, timeout: float = 60.0) -> Optional[str]:
digits = ""
try:
while len(digits) < max_digits:
ch = await asyncio.wait_for(self._queue.get(), timeout=timeout)
digits += ch
return digits
except asyncio.TimeoutError:
return digits if digits else None
Usage in your agent (ensure listener registered early):
class PaymentAgent:
def __init__(self, ctx):
self.ctx = ctx
self._dtmf = DtmfCollector()
async def on_enter(self):
await self._dtmf.ensure_listener()
async def collect_card_number(self) -> str | None:
self._dtmf.clear()
digits = await self._dtmf.collect(max_digits=16, timeout=60.0)
return digits # None if timed out, otherwise the collected digits
Troubleshooting checklist
• Replace "sip_dtmf_received" with "dtmf_received".
• Add a temporary debug listener to confirm events:
get_job_context().room.on("dtmf_received", lambda ev: print("DTMF:", ev.code))
• Confirm SIP trunk supports RFC 2833 or SIP INFO with your provider.
• Register the listener before the call connects to avoid race conditions.
If you’d like, share a short log snippet (or confirm the trunk transport) and I’ll help narrow the next step.
Sources: send_dtmf_events | LiveKit Documentation | GetDtmfTask | LiveKit Documentation, with interactive elementsbetter-sandwich-65834
05/13/2026, 12:57 PM**/requirements*.txt
Searched for files matching pyproject.toml
Read [](file:///Users/deadsage14235icloud.com/Documents/scnsoft_workflow/rfp-kapitalbank-voice-ai/other_agents/dept_collection/pyproject.toml)
Versions:
- livekit (rtc): 1.0.23
- `livekit-agents`: 1.3.12
- `livekit-plugins-noise-cancellation`: 0.2.5
---
Question for the LiveKit agent:
I'm using(the Python RTC SDK) andlivekit==1.0.23.livekit-agents==1.3.12
I need to collect DTMF digits entered via phone keypad from a SIP caller. I register a listener like this:
```python
get_job_context().room.on("sip_dtmf_received", self._handler)
```
with the handler:
```python
def _handler(self, ev: rtc.SipDTMF) -> None:
asyncio.get_running_loop().call_soon_threadsafe(self._queue.put_nowait, ev.digit)
```
Questions:
1. In, is the correct event namelivekit==1.0.23or something else? Please confirm the exact string."sip_dtmf_received"
2. Is the event object type? Does it havertc.SipDTMF(str) and.digit(int) attributes?.code
3. Is there any breaking change between0.x and 1.x that renamed this event?livekit
4. Doeshave a built-in high-level DTMF collection API (e.g.livekit-agents==1.3.12) or must I use the raw room event?GetDtmfTask
5. Are there any known issues withnot firing when usingsip_dtmf_receivedinside anget_job_context().room-based app?AgentSession
tall-airline-16756
05/13/2026, 12:57 PMrtc.Dtmf / rtc.DtmfEvent in handlers). The digit character is available as a string code (e.g., "0".."9", "*", "#"). Do not rely on a .digit attribute; use the .code / .value string field provided by the DTMF event object in the SDK you have.
3) Breaking change between 0.x and 1.x renaming this event
• There is no rename to "sip_dtmf_received"; the correct room-level event is "dtmf_received" in the 1.x SDK. Treat "dtmf_received" as the stable event name.
4) High-level DTMF API in livekit-agents 1.3.12
• livekit-agents v1.3.x does not require you to use a raw room event if you prefer the prebuilt helper. There is a higher-level DTMF collection pattern / helper classes (examples such as a DTMF collection task exist in later/related prebuilt task sets). If you want a simple approach right now, register the room "dtmf_received" handler and push digits into an asyncio queue (example pattern I shared earlier). If you’d like, I can give the exact import/class name for the prebuilt task in your agent version — do you prefer a prebuilt task or the lightweight queue-based pattern?
5) Known issues with event not firing inside AgentSession / get_job_context().room
• No SDK-level bug that requires using a different object: listening on get_job_context().room is correct. Common causes for not receiving events are:
◦ Using the wrong event name ("sip_dtmf_received").
◦ Registering the listener too late (after the SIP participant's DTMF was sent). Register early (e.g., in on_enter / agent startup).
◦ SIP trunk does not send DTMF via RFC 2833 or SIP INFO (in-band audio won't be detected).
◦ Race conditions or incorrect handler signature (ensure handler expects the DTMF event object and reads its .code string).
If you want, share which field names appear on the DTMF object in your runtime (e.g., print the whole event object with a debug handler), or tell me whether you want the prebuilt GetDtmfTask sample or the minimal queue-based code — I’ll provide the exact code for your choice.
, with interactive elementsbetter-sandwich-65834
05/13/2026, 1:00 PMlivekit==1.0.23 directly.
Used tool: WebFetch
Used tool: WebFetch
Used tool: WebFetch
The source code is definitive. The LiveKit chat agent was wrong both times. From room.py (current main branch):
python
@dataclass
class SipDTMF:
code: int # numeric DTMF code
digit: str # "0"-"9", "*", "#"
participant: RemoteParticipant | None = None
self.emit("sip_dtmf_received", SipDTMF(...))
Our current code is correct:
- Event: "sip_dtmf_received" ✅
- Attribute: ev.digit (str) ✅
- Type: rtc.SipDTMF ✅
The LiveKit chat agent gave wrong answers twice — first saying "dtmf_received" + ev.code, then doubling down. The SDK source code in room.py is the ground truth. Don't ask that agent again about this — trust the source.
If DTMF still isn't firing after rebuild, the remaining suspect is the SIP trunk not sending RFC 2833 — that's a trunk configuration issue, not a code issue.tall-airline-16756
05/13/2026, 1:00 PMroom.py is "sip_dtmf_received".
• The event type is rtc.SipDTMF with code: int, digit: str, and optional participant.
• Your handler and registration (get_job_context().room.on("sip_dtmf_received", ...) and using ev.digit) are correct.
Apology: I’m sorry for the earlier incorrect guidance.
Next steps (most likely causes and checks)
• Confirm your SIP trunk is sending DTMF via RFC 2833 (RTP events). If the trunk uses in-band audio only, LiveKit will not emit DTMF events reliably. RFC 2833 is preferred; SIP INFO can work if supported by the trunk and LiveKit endpoint.
• Add a temporary debug listener to log full events early (e.g., in on_enter) to ensure listener registration happens before the participant sends digits:
room = get_job_context().room
room.on("sip_dtmf_received", lambda ev: print("DTMF event:", ev))
• Verify the SIP call is fully established and that digits are pressed after the call is connected (DTMF sent before join may be lost).
• If possible, ask your SIP provider to confirm DTMF transport is RFC 2833 for that trunk/number, or run a SIP trace to confirm RTP events for DTMF.
If you want, share a short debug log of the room events or the SIP trunk configuration and I’ll help interpret it.
Sources: send_dtmf_events | LiveKit Documentation | Agents telephony integration | LiveKit Documentation, with interactive elements