Working with Dual-tone Multi-frequency (DTMF) Signalling

IceLink 3.2.0 added support for dual-tone multi-frequency signalling (DTMF).

Sending DTMF Tones

Here we demonstrate how simple it is to send a DTMF tone.

audioStream.InsertDtmfTones(FM.IceLink.Dtmf.Tone.FromToneString("..."));
audioStream.insertDtmfTones(fm.icelink.dtmf.Tone.fromToneString("..."));
[audioStream insertDtmfTones:[FMIceLinkDtmfTone fromToneString:@"..."]];
audioStream?.insertDtmfTones(FMIceLinkDtmfTone.fromToneString("..."));
audioStream.insertDtmfTones(fm.icelink.dtmf.Tone.fromToneString("..."));

DTMF Tone String

A tone string is made of up characters from the set "123456789*0#ABCD,". The special character "," indicates a pause.


Also, you can hook into an event that is raised when the sending tone changes.

audioStream.OnSendDtmfToneChange += (tone) =>
{
    Log.Info("Sender's DTMF tone is changing: " + tone.ToString());
};
audioStream.addOnSendDtmfToneChange(new fm.icelink.IAction1<fm.icelink.dtmf.Tone>() {
    @Override
    public void invoke(fm.icelink.dtmf.Tone tone) {
        Log.info("Sender's DTMF tone is changing: " + tone.toString());
    }
});
audioStream.addOnSendDtmfToneChangeWithBlock(^(FMIceLinkDtmfTone *tone) {
	[FMIceLinkLog infoWithMessage:[NSString stringWithFormat:@"Sender's DTMF tone is changing: %@", [tone description]]];
});
audioStream?.addOnSendDtmfToneChange({ (t: Any!) in
	let tone = t as! FMIceLinkDtmfTone
	FMIceLinkLog.info(withMessage: "Sender's DTMF tone is changing: " + tone.description())
})
audioStream.addOnSendDtmfToneChange((tone: fm.icelink.dtmf.Tone) => {
	fm.icelink.Log.info("Sender's DTMF tone is changing: " + tone.toString());
});

The empty string “” indicates that the tone has stopped.

For browsers, that's all there is to it. Per Mozilla:

The primary purpose for WebRTC's DTMF support is to allow WebRTC-based communication clients to be connected to a public-switched telephone network (PSTN) or other legacy telephone service, including extant voice over IP (VoIP) services. For that reason, DTMF can't be used between two WebRTC-based devices, because there is no mechanism provided by WebRTC for receiving DTMF codes.

Additional DTMF Tone Features for Native Platforms 

We've taken it a few steps further on all other platforms (native desktop/mobile), where additional sending and receiving events are available.

When the receiving tone changes, an event is raised:

audioStream.OnReceiveDtmfToneChange += (tone) =>
{
    Log.Info("Receiver's DTMF tone is changing: " + tone.ToString());
};
audioStream.addOnReceiveDtmfToneChange(new fm.icelink.IAction1<fm.icelink.dtmf.Tone>() {
    @Override
    public void invoke(fm.icelink.dtmf.Tone tone) {
        Log.info("Receiver's DTMF tone is changing: " + tone.toString());
    }
});
audioStream.addOnReceiveDtmfToneChangeWithBlock(^(FMIceLinkDtmfTone *tone) {
	[FMIceLinkLog infoWithMessage:[NSString stringWithFormat:@"Receiver's DTMF tone is changing: %@", [tone description]]];
});
audioStream?.addOnReceiveDtmfToneChange({ (t: Any!) in
	let tone = t as! FMIceLinkDtmfTone
	FMIceLinkLog.info(withMessage: "Receiver's DTMF tone is changing: " + tone.description())
})
audioStream.addOnReceiveDtmfToneChange((tone: fm.icelink.dtmf.Tone) => {
	fm.icelink.Log.info("Receiver's DTMF tone is changing: " + tone.toString());
});

The empty string “” indicates that the tone has stopped.

If you want to go lower-level, it's possible to handle the actual packet-level send/receive events which are tied to the clock-rate of the selected audio stream codec (Opus, PCMU, PCMA, etc.).

audioStream.OnSendDtmfTone += (tone) =>
{
    Log.Info("Sending DTMF tone: " + tone.ToString());
};
audioStream.OnReceiveDtmfTone += (tone) =>
{
    Log.Info("Received DTMF tone: " + tone.ToString());
};
audioStream.addOnSendDtmfTone(new fm.icelink.IAction1<fm.icelink.dtmf.Tone>() {
    @Override
    public void invoke(fm.icelink.dtmf.Tone tone) {
        Log.info("Sending DTMF tone: " + tone.toString());
    }
});
audioStream.addOnReceiveDtmfTone(new fm.icelink.IAction1<fm.icelink.dtmf.Tone>() {
    @Override
    public void invoke(fm.icelink.dtmf.Tone tone) {
        Log.info("Received DTMF tone: " + tone.toString());
    }
});
audioStream.addOnSendDtmfToneWithBlock(^(FMIceLinkDtmfTone *tone) {
	[FMIceLinkLog infoWithMessage:[NSString stringWithFormat:@"Sending DTMF tone: %@", [tone description]]];
});
audioStream.addOnReceiveDtmfToneWithBlock(^(FMIceLinkDtmfTone *tone) {
	[FMIceLinkLog infoWithMessage:[NSString stringWithFormat:@"Receiving DTMF tone: %@", [tone description]]];
});
audioStream?.addOnSendDtmfTone({ (t: Any!) in
	let tone = t as! FMIceLinkDtmfTone
	FMIceLinkLog.info(withMessage: "Sending DTMF tone: " + tone.description())
})
audioStream?.addOnReceiveDtmfTone({ (t: Any!) in
	let tone = t as! FMIceLinkDtmfTone
	FMIceLinkLog.info(withMessage: "Receiving DTMF tone: " + tone.description())
})
audioStream.addOnSendDtmfTone((tone: fm.icelink.dtmf.Tone) => {
	fm.icelink.Log.info("Sending DTMF tone: " + tone.toString());
});
audioStream.addOnReceiveDtmfTone((tone: fm.icelink.dtmf.Tone) => {
	fm.icelink.Log.info("Receiving DTMF tone: " + tone.toString());
});