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:

call.conversation.media.sendDTMF('3212333,222,399,3212333,32232,1')
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)
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);
nexmoCall.sendDTMF("3212333,222,399,3212333,32232,1")
[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.

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.

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)
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:

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:

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