Bridge Communications

Saturday, April 4, 2015

A Practical UCMA DTMF library for Lync/Skype4B

One of the truly great things about Microsoft Lync/Skype for Business is something the user will never see with their own eyes.  In typical Microsoft fashion, the client and server and loaded with fully functional SDKs that let programmers like me do almost everything the software can do programmatically.  Listening and responding to DTMF is no exception.  What is DTMF?  Put simply it's the process of interpreting if the caller pressed a button or buttons on the phone.

So what is the best way to handle this in UCMA and Lync/Skype4B?  My approach was to create a separate class called ToneSomething.  This won't muck up my call handling handling code and allows this separate thread to be off and running on it's own.  So what do I store in my class?  I determined really there are 2 things I want to know.

1.  What keys have I heard?
2.  When was the last time they pressed a key?

What this gives me is the ability to for the caller to press multiple keys so I don't handle 1 and 11 the same.  It also lets me have them timeout if you will, ie if you haven't pressed a key in 3 seconds I will assume you are done, and ask you a confirmation question.

Here is what the top part of my class looks like.

internal class ToneSomething
    {
        public string _whatIHeard = "";
        AudioVideoCall _call;
        ILogger _logger = new ConsoleLogger();
        ToneController _TC = new ToneController();
        public DateTime _lastHeard = DateTime.Now;

_whatIHeard would be the string of keys that the caller has pressed since I started the controller.

_lastHeard is the DateTime of the last key press event.

There are 3 functions I have created in the class, Start, Stop, and Clear.  Clear lets me re-use the object without having to detach from it, in the event I need to ask a second question or the user needs to start over.

 internal void Start(AudioVideoCall _call)
        {
            _TC = new ToneController();
            _TC.ToneReceived += _TC_ToneReceived;
            _TC.AttachFlow(_call.Flow);
        }

internal void Stop()
        {
            _logger.Log("Detaching Tone Controller from Call");
            _TC.DetachFlow();
        }

        internal void Clear()
        {
            _whatIHeard = "";
            _lastHeard = DateTime.Now;
        }

In addition to the 3 functions I have 1 event handled as you see in the start called _TC_ToneReceived.  It looks like this and has the responsibility of setting the 2 properties I can use to check on the status of what has been pressed and when the last key press happened.

        void _TC_ToneReceived(object sender, ToneControllerEventArgs e)
        {
            try
            {
                _logger.Log("Tone Heard: " + e.Tone.ToString());

                if (e.Tone == 1)
                {
                    _whatIHeard += "1";
                }
                else if (e.Tone == 2)
                {
                    _whatIHeard += "2";
                }
                else if (e.Tone == 3)
                {
                    _whatIHeard += "3";
                }
                else if (e.Tone == 4)
                {
                    _whatIHeard += "4";
                }
                else if (e.Tone == 5)
                {
                    _whatIHeard += "5";
                }
                else if (e.Tone == 6)
                {
                    _whatIHeard += "6";
                }
                else if (e.Tone == 7)
                {
                    _whatIHeard += "7";
                }
                else if (e.Tone == 8)
                {
                    _whatIHeard += "8";
                }
                else if (e.Tone == 9)
                {
                    _whatIHeard += "9";
                }
                else if (e.Tone == 0)
                {
                    _whatIHeard += "0";
                }
                else if (e.Tone == (int)ToneId.Pound)
                {
                    _whatIHeard += "#";
                }
                else if (e.Tone == (int)ToneId.Star)
                {
                    _whatIHeard += "*";
                }

                _logger.Log("Total value : " + _whatIHeard);
            }
            catch { }
        }

That's it, the class is pretty simple but the beauty is when you go to use it.  You can do something like this.  Where you ask the user to end their key pressing with #.

 ToneSomething ts = new ToneSomething();
                                ts.Start(_call);


SaySomething says = new SaySomething(_call, "Hi, thank you for calling.  Dial 44 pound to enter the back to back conference.");
                                says.Start();

                                while (_call.State != CallState.Terminating)
                                {
                                    if (ts._whatIHeard.EndsWith("#"))
                                    {

                                        if (ts._whatIHeard == "44#")
                                        {
                                            ts.Clear();

                                            #region Pound

                                            //say something
SaySomething says5 = new SaySomething(_call, "Ouch! don't press the damn pound key so hard, I'll transfer you.");
                                            says5.Start();


As you can probably guess I wrote a class called SaySomething that speaks a string or an audio file to an existing call, making it again simpler easing the clutter in the call handling routines.

This will conclude the simple example of using DTMF with UCMA in Lync or Skype for Business.

Doug Routledge, C# Lync, Skype for Business, SQL, Exchange, UC Developer  BridgeOC
Twitter - @droutledge @ndbridge



Lync/Skype4B Response Group Monitor is coming soon.



No comments:

Post a Comment

Any spam comments will be deleted and your user account will be disabled.