Send and Receive DTMF

Overview

Dual Tone Multi Frequency (DTMF), is a form of signalling used by phone systems to transmit the digits 0-9 and the * and # characters. Typically a caller presses these buttons on their telephone keypad and the phone then generates a tone made up of two frequencies played simultaneously (hence Dual Tone).

DTMF is used both for dialing a destination on a landline telephone and also for signalling to the remote end once a call is answered. Typically this is used to implement an Interactive Voice Response (IVR) system, or to enter information like a PIN number or conference call pin.

With the Client SDKs you can both collect a DTMF input from your app user, and listen to DTMF input that was sent from another member.

Before you begin, make sure you added the SDK to your app and you are able to make or receive calls.

Send DTMF

In order to send DTMF tones from your application to the backend, use this method:

Copy to Clipboard
call.conversation.media.sendDTMF('3212333,222,399,3212333,32232,1')
Copy to Clipboard
val callListener = object : NexmoRequestListener<NexmoCall> {
    override fun onSuccess(nexmoCall: NexmoCall?) {
        Log.d("TAG", "Call started: " + nexmoCall.toString())

        nexmoCall.sendDTMF("123456")
    }

    override fun onError(apiError: NexmoApiError) {
        Log.d("TAG", "Error: Unable to start a call ${apiError.message}")
    }
}

nexmoClient.call("123456", NexmoCallHandler.SERVER, callListener)
Copy to Clipboard
NexmoRequestListener<NexmoCall> callListener = new NexmoRequestListener<NexmoCall>() {
    @Override
    public void onSuccess(@Nullable NexmoCall nexmoCall) {
        Log.d("TAG", "Call started: " + nexmoCall.toString());

        nexmoCall.sendDTMF("123456");
    }

    @Override
    public void onError(@NonNull NexmoApiError apiError) {
        Log.d("TAG", "Error: Unable to start a call " + apiError.getMessage());
    }
};

nexmoClient.call("123456", NexmoCallHandler.SERVER, callListener);
Copy to Clipboard
nexmoCall.sendDTMF("3212333,222,399,3212333,32232,1")
Copy to Clipboard
[ongoingCall sendDTMF:@"3212333,222,399,3212333,32232,1"];

During an ongoing call, where your backend implemented an NCCO with an Input action, sending a DTMF will trigger the defined "eventUrl".

Receive DTMF

Whenever a member in a Conversation or a Call sends a DTMF, all of the other members are notified about that event.

Copy to Clipboard
call.conversation.on("audio:dtmf",(from, event)=>{
  event.digit // the dtmf digit(s) received
  event.from //id of the user who sent the dtmf
  event.timestamp //timestamp of the event
  event.cid // conversation id the event was sent to
  event.body // additional context about the dtmf
});

The DTMF events will be received in your implementation of NexmoCallEventListener.onDTMF() method, on the NexmoCallEventListener that is attached to the NexmoCall.

Copy to Clipboard
val callListener = object : NexmoRequestListener<NexmoCall> {
    override fun onSuccess(nexmoCall: NexmoCall?) {
        Log.d("TAG", "Call started: " + nexmoCall.toString())

        nexmoCall?.addCallEventListener(callEventListener)
    }

    override fun onError(apiError: NexmoApiError) {
        Log.d("TAG", "Error: Unable to start a call ${apiError.message}")
    }
}

val callEventListener = object : NexmoCallEventListener {
    override fun onDTMF(digit: String?, callMember: NexmoCallMember?) {
        Log.d("TAG", "v: digit: $digit, callMember: $callMember")
    }

    override fun onMemberStatusUpdated(memberStatus: NexmoCallMemberStatus?, callMember: NexmoCallMember?) {
        Log.d("TAG", "onMemberStatusUpdated: status: $memberStatus, callMember: $callMember")
    }

    override fun onMuteChanged(muteState: NexmoMediaActionState?, callMember: NexmoCallMember?) {
        Log.d("TAG", "onMuteChanged: muteState: $muteState, callMember: $callMember")
    }

    override fun onEarmuffChanged(earmuffState: NexmoMediaActionState?, callMember: NexmoCallMember?) {
        Log.d("TAG", "onEarmuffChanged: earmuffState: $earmuffState, callMember: $callMember")
    }
}


nexmoClient.call("123456", NexmoCallHandler.SERVER, callListener)
Copy to Clipboard
NexmoRequestListener<NexmoCall> callListener = new NexmoRequestListener<NexmoCall>() {
    @Override
    public void onSuccess(@Nullable NexmoCall nexmoCall) {
        Log.d("TAG", "Call started: " + nexmoCall.toString());

        nexmoCall.addCallEventListener(callEventListener);
    }

    @Override
    public void onError(@NonNull NexmoApiError apiError) {
        Log.d("TAG", "Error: Unable to start a call " + apiError.getMessage());
    }
};

NexmoCallEventListener callEventListener = new NexmoCallEventListener() {

    @Override
    public void onMemberStatusUpdated(NexmoCallMemberStatus $memberStatus, NexmoCallMember callMember) {}

    @Override
    public void onMuteChanged(NexmoMediaActionState muteState, NexmoCallMember callMember) {}

    @Override
    public void onEarmuffChanged(NexmoMediaActionState earmuffState, NexmoCallMember callMember) {}

    @Override
    public void onDTMF(String digit, NexmoCallMember callMember) {
        Log.d("TAG", "onDTMF(): digit:" + digit + ", callMember: " + callMember);
    }
};

nexmoClient.call("123456", NexmoCallHandler.SERVER, callListener);

The DTMF events will be received in the implementation of the dtmfReceived(_, callMember) optional method for your NXMCallDelegate:

Copy to Clipboard
func dtmfReceived(_ dtmf: String, callMember: NXMCallMember) {
  print("DTMF received:`\(dtmf)` from `\(String(describing: callMember.user.name))`")
}

The DTMF events will be received in the implementation of the DTMFReceived:callMember: optional method for your NXMCallDelegate:

Copy to Clipboard
- (void)DTMFReceived:(nonnull NSString *)dtmf callMember:(nonnull NXMCallMember *)callMember {
    NSLog(@"DTMF received: `%@` from `%@`", dtmf, callMember.user.name);
}