LiveKit's Telephony stack fully supports DTMF tones, enabling integration with legacy IVR systems. It also enables agents to receive DTMF tones from telephone users.
Sending DTMF
To send DTMF tones, use the publishDtmf
API on the localParticipant
.
This API transmits DTMF tones to the room; tones can be sent by any participant in the room.
SIP participants in the room receive the tones and relay them to the telephone user.
// publishes 123# in DTMFawait localParticipant.publishDtmf(1, '1');await localParticipant.publishDtmf(2, '2');await localParticipant.publishDtmf(3, '3');await localParticipant.publishDtmf(11, '#');
# publishes 123# in DTMFawait local_participant.publish_dtmf(code=1, digit='1')await local_participant.publish_dtmf(code=2, digit='2')await local_participant.publish_dtmf(code=3, digit='3')await local_participant.publish_dtmf(code=11, digit='#')
import ("github.com/livekit/protocol/livekit")// publishes 123# in DTMFlocalParticipant.PublishDataPacket(&livekit.SipDTMF{Code: 1,Digit: "1",})localParticipant.PublishDataPacket(&livekit.SipDTMF{Code: 2,Digit: "2",})localParticipant.PublishDataPacket(&livekit.SipDTMF{Code: 3,Digit: "3",})localParticipant.PublishDataPacket(&livekit.SipDTMF{Code: 11,Digit: "#",})
Sending DTMF tones requires both a numeric code and a string representation to ensure compatibility with various SIP implementations.
Special characters like *
and #
are mapped to their respective numeric codes. See RFC 4733 for details.
Receiving DTMF
When SIP receives DTMF tones, they are relayed to the room as events that participants can listen for.
room.on(RoomEvent.DtmfReceived, (code, digit, participant) => {console.log('DTMF received from participant', participant.identity, code, digit);});
@room.on("sip_dtmf_received")def dtmf_received(dtmf: rtc.SipDTMF):logging.info(f"DTMF received from {dtmf.participant.identity}: {dtmf.code} / {dtmf.digit}")
import ("fmt""github.com/livekit/protocol/livekit"lksdk "github.com/livekit/server-sdk-go/v2")func DTMFCallbackExample() {// Create a new callback handlercb := lksdk.NewRoomCallback()// Handle data packets received from other participantscb.OnDataPacket = func(data lksdk.DataPacket, params lksdk.DataReceiveParams) {// handle DTMFswitch val := data.(type) {case *livekit.SipDTMF:fmt.Printf("Received DTMF from %s: %s (%d)\n", params.SenderIdentity, val.Digit, val.Code)}}room := lksdk.NewRoom(cb)...}