info@voip-sip-sdk.com Tel.: 00 36 52 532 731

How to use DTMF signaling (sending and receiving DTMF)?

Download: DTMF.zip

This article introduces you the basic knowledge about DTMF signaling and how to use it in your Ozeki VoIP SIP SDK supported softphone application. To use this example, you need to have Ozeki VoIP SIP SDK installed, and a reference to ozeki voipsipsdk.dll should be added to your visual studio project. It's also recommended to visit the How to make a Voice Call and How to accept incoming call articles before you begin to study how to perform sending and receiving DTMF signals.


Figure 1 - Sending DTMF signals works as sending RTP events to the other party

What is a DTMF Signal? When is it needed?

All leading companies in the world know that communication with the customers is an essential part of their success. It is a fact that there are always more customers having problems at a time than free service desk agents to solve those problems. So, companies need to use some kind of solution that decreases the number of customers who need to talk to a real person to solve their problems.

Let's categorize the problems by difficulty and the number of occurrence, and you will see that there are some common problems that occur more than once every day, and there is a simple default solution for them. Wasn't it good if these problems wouldn't bother your already engaged customer service agents, but automatically given to your customers?

Dual-tone multi-frequency signaling (DTMF) is a telecommunication tool that is based on sending and receiving signals of different frequencies via telephone lines. This technique is very useful, when you want for example build an automatic menu system for a customer service.

If you have a hotline for customer service, you can have some prerecorded automatic answers for the most usual customer problems. These answers can be played by using a phone line menu that can be controlled by pressing some numeric buttons on the caller's telephone or softphone keypad. This is the most common usage of a DTMF signal nowadays.

If a customer calls the hotline, they will get an automatic answer with the instruction to press some keys to get answer for their problem. You can also define a key press for reaching a real customer service agent is case that they didn't find answer for their problem. You can create as deep and wide menu system as you want so you can solve one or even one hundred types of problem automatically with default answers.

If you read more about DTMF, you can check the following page: DTMF navigation

How to use DTMF signaling in C#?

DTMF signals originally use the numeric keypad extended with the *, #, A, B, C and D buttons. The alphabetical buttons are usually not found on the most recent telephones and softphone applications, and their frequencies are used for basic settings of the connection.

DTMF defines 8 frequencies that are used in pairs for the 16 button press options. These frequencies are selected so as not to collide with each other even when they are combined. The frequencies used in DTMF signaling are shown in Table 1.

DTMF is called multi-frequency as for every key press two of the predefined frequencies are sent. The receiver needs to have a decoder system to be able to identify which key was pressed.

1209 Hz1366 Hz1477 Hz1633 Hz
697 Hz123A
770 Hz456B
852 Hz789C
941 Hz*0#D

Table 1 - Frequency information for DTMF signaling

Fortunately, if you use Ozeki VoIP SIP SDK, you will not need to worry about coding or decoding DTMF signals as the support is provided by the SDK classes and methods. You will only need to call some methods and determine what to do when a DTMF signal has been received.


You start a DTMF signal with pressing a numeric button during a call

Ozeki VoIP SIP SDK class IPhoneCall has the methods for noticing, starting and ending DTMF signals, you will only have to call these methods in the right place and order. A DTMF signal is sent when there is an established call line that means that the call state is InCall.

You have to specify the sender button for the DTMF so as the SDK could notice what frequency it shall send.

You can start sending a DTMF signal by calling the StartDTMFSignal method of the call object.

The DTMF signal is being sent from the time of the button press till the time of its release. There can be some situations when the length of the DTMF signal is significant so you need to write the start and the end method too. The softphone will stop sending the signal when you release the button.

For stopping the DTMF signal, you only have to release the keypad button you pressed. Ozeki VoIP SIP SDK covers the topic of stopping DTMF signals too, so you only have to call the StopDTMFSignal method in your program.

The preconditions of stopping a DTMF signal are similar to the ones of starting one. There has to be an established phone line and you have to identify the sender button.

DTMF example using C#

This simple example automatically sends a DTMF signal. Automatically means that you do not have to push any buttons or click your mouse, the DTMF signal will be sent by the example. Yet, it is essential to note that it has not been implemented that as a result of the sent DTMF signal, anything should take place.

using System;
using System.Threading;
using System.Threading.Tasks;
using Ozeki.Network.Nat;
using Ozeki.VoIP;
using Ozeki.VoIP.SDK;

namespace DTMF
{
    class Program
    {
        private static ISoftPhone mySoftphone; // softphone object    
        private static IPhoneLine phoneLine; // phoneline object          
        private static IPhoneCall call;
        private static string numberToDial;

        private static void Main(string[] args)
        {
            //Create a softphone object with RTP port range 5000-10000, and SIP port 5060    
            mySoftphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000, 5060);

            // SIP account registration data, (supplied by your VoIP service provider)    
            var registrationRequired = true;  
            var userName = "sipusername";
            var displayName = "sipdisplayname";
            var authenticationId = "authenticationid";
            var registerPassword = "password";
            var domainHost = "pbxip.voipprovider.com";
            var domainPort = 5060;
            numberToDial = "1001";

            // Send SIP regitration request    
            mySoftphone_Register(mySoftphone, registrationRequired, displayName, userName, authenticationId, registerPassword,
                             domainHost, domainPort);

            // prevents the termination of the application    
            while (true) Thread.Sleep(10);
        }

        static void mySoftphone_Register(ISoftPhone softphone, bool registrationRequired, string displayName, string userName,
        string authenticationId, string registerPassword, string domainHost, int domainPort)
        {
            try
            {
                var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost, domainPort);
                var natConfiguration = new NatConfiguration(NatTraversalMethod.None);
                phoneLine = softphone.CreatePhoneLine(account, natConfiguration);
                phoneLine.PhoneLineStateChanged += mySoftphone_PhoneLineStateChanged;
                softphone.RegisterPhoneLine(phoneLine);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error during SIP registration: " + ex.ToString());
            }
        }

        static void mySoftphone_PhoneLineStateChanged(object sender, VoIPEventArgs<PhoneLineState> e)
        {
            Console.WriteLine(e.Item);
            if (e.Item == PhoneLineState.RegistrationSucceeded || e.Item == PhoneLineState.NoRegNeeded)
                CreateCall();
        }

        static void CreateCall()
        {
            call = mySoftphone.CreateCallObject(phoneLine, numberToDial);
            call.CallStateChanged += call_CallStateChanged;
            call.CallErrorOccured += call_CallErrorOccured;
            call.Start();
        }

        static void call_CallStateChanged(object sender, VoIPEventArgs<CallState> e)
        {
            Console.WriteLine("\nCall state: {0}.", e.Item);

            if (e.Item == CallState.Answered)
                Task.Factory.StartNew(SendDTMFSingnal);
        }

        static void call_CallErrorOccured(object sender, VoIPEventArgs<CallError> e)
        {
            Console.WriteLine("Error occured during the call: {0}.", e.Item);
        }

        private static void SendDTMFSingnal()
        {
            Thread.Sleep(1000);
            call.StartDTMFSignal(DtmfNamedEvents.Dtmf0);
            Thread.Sleep(500);
            call.StopDTMFSignal(DtmfNamedEvents.Dtmf0);
        }
    }
}

Training guides, simple examples

If you would like to visit the detailed developer documentations, you can learn much more from the Ozeki VoIP SIP SDK Training chapter.

Communication through the network

After the call has been established, the softphone is ready to send DTMF signals as RTP events:

[Stream setup by SDP (frame 46)]
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
1... .... = Marker: True
Payload type: telephone-event (101)
Sequence number: 11828
[Extended sequence number: 77364]
Timestamp: 28960
Synchronization Source identifier: 0x272bf0c7 (657191111)

RFC 2833 RTP Event
Event ID: DTMF Zero 0 (0)
0... .... = End of Event: False
.0.. .... = Reserved: False
..00 1010 = Volume: 10
Event Duration: 160

If you have any questions or need assistance, please contact us at info@voip-sip-sdk.com

Related Pages