Creating Call Center Applications with Unified Communications SDKs: Bot Application (Part 2 of 4)

Summary:   Learn how to use Unified Communications SDKs to implement speech synthesis, speech recognition, and call control technologies to create a simple call center application.

Applies to:   Microsoft Unified Communications Managed API (UCMA) 3.0 Core SDK or Microsoft Unified Communications Managed API 4.0 SDK | Microsoft Lync 2010 SDK | Microsoft Speech Platform SDK version (x64) 10.2

Published:   April 2012 | Provided by:   John Clarkson and Mark Parker, Microsoft | About the Author


Download code   Download code

Watch video   See video

This is the second in a series of four articles about how to create a call center application.

  • Microsoft Speech Platform SDK version (x64) 10.2.

  • Microsoft Server Speech Text to Speech Voice (en-US, Helen).

  • Microsoft Server Speech Recognition Language - TELE(en-US).

  • Microsoft Unified Communications Managed API (UCMA) 3.0 Core SDK.

  • On each computer that is running the bot application, sign in to the Microsoft Lync 2010 client.

  1. Create and establish a UserEndpoint instance.

    _userEndpoint = _helper.CreateEstablishedUserEndpoint("Forwarding User" /*endpointFriendlyName*/);
  2. Register a delegate to be invoked when a call arrives.


The AudioVideoCall_Received method is called when the incoming customer call is received. This method is used to control the dialog flow.

Figure 1. Call flow

Call flow
  1. After the call arrives, accept it. Before transferring the call, it must be in the Established state.

    _inboundAVCall.BeginAccept(BeginAcceptCB, _inboundAVCall);
  2. Query the caller for department and name. We'll discuss this later in this article.

  3. Begin call transfer. We'll discuss this later in this article.

    result = _inboundAVCall.BeginTransfer(_outboundAVCall, basicTransferOptions, BeginTransferCB, _inboundAVCall);
  4. Send contextual data. We'll discuss this later in this article.


  1. After the customer's call is accepted, create a speech synthesis connector and attach the AudioVideoFlow instance to it.

    _speechSynthesisConnector = new SpeechSynthesisConnector();
  2. Create a speech synthesizer and set the output of the speech synthesizer to the speech synthesis connector.

    //Create a SpeechSynthesizer object.
    _speechSynthesizer = new SpeechSynthesizer();
    //Set speech format options.
    SpeechAudioFormatInfo audioformat = new SpeechAudioFormatInfo(16000, AudioBitsPerSample.Sixteen, Microsoft.Speech.AudioFormat.AudioChannel.Mono);
    //Connect the synthesizer object to the audio stream.
    _speechSynthesizer.SetOutputToAudioStream(_speechSynthesisConnector, audioformat);
  3. Register for notification of the SpeakCompleted and SpeakStarted events on the speech synthesizer.

    _speechSynthesizer.SpeakStarted += new EventHandler<SpeakStartedEventArgs>
    _speechSynthesizer.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>
    Start the speech synthesis connector and speak the text in a string.
    _speechSynthesizer.Speak("Hello, can I connect you to billing or sales");

  1. Create a speech recognition connector and attach it to an AudioVideoFlow object.

    _speechRecognitionConnector = new SpeechRecognitionConnector();
  2. Start the speech recognition connector.

    SpeechRecognitionStream stream = _speechRecognitionConnector.Start();
  3. Create a SpeechRecognitionEngine object and then register to receive notifications for the SpeechRecognized and SpeechRecognitionRejected events.

    _speechRecognitionEngine = new SpeechRecognitionEngine();
    _speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(speechRecognitionEngine_SpeechRecognized);
    _speechRecognitionEngine.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(_speechRecognitionEngine_SpeechRecognitionRejected);
  4. Create a recognition grammar and attach it to the SpeechRecognitionEngine object. The following code example shows the grammar to recognize the answer to “Hello, can I connect you to billing or sales.” There is also a second grammar to recognize the answer to “And who shall I say is calling.”

    Note Note

    You should consider using a grammar that is more scalable, for example an SRGS XML grammar, or a GrammarBuilder grammar. For more information, see Creating Speech Recognition Calculators in UCMA 3.0: Grammar Creation.

    string[] departmentString = { "Sales", "Billing" };
    Choices departmentGrammar = new Choices(departmentString);
    _speechRecognitionEngine.LoadGrammar(new Grammar(new GrammarBuilder(departmentGrammar)));
    _speechRecognitionEngine.Grammars[0].Name = "department";
  5. Use the event handler for the SpeechRecognized event to get data from the caller's answers.

    RecognitionResult result = e.Result;
    if (result != null)
      //Grammar name indicates which question the caller is answering.
      if (result.Grammar.Name == "department")
        _department = result.Text;
        //The name of the grammar used to recognize 
        //the caller's speech indicates the caller is answering "which department?"
        //This tells us we should now ask for the caller's name.
      else if (result.Grammar.Name == "name")
        _name = result.Text;
        Console.WriteLine("Speech not name or dept: " + result.Text);

The incoming call replaces a new outbound call represented by an AudioVideoCall object.

  1. Get the Conversation object.

    _conversation = new Conversation(_userEndpoint);
  2. Create an AudioVideoCall object.

    _outboundAVCall = new AudioVideoCall(_conversation);
  3. Establish a new outbound call. Before transferring the inbound call, the outbound call must be in the Established state.

    _outboundAVCall.BeginEstablish(_transferUserURI, null, BeginEstablishCB, _outboundAVCall);
  4. Begin the transfer to the agent.

    result = _inboundAVCall.BeginTransfer(_outboundAVCall, basicTransferOptions, BeginTransferCB, 

Call Transfer Method Parameters

BeginEstablish method parameters that are used in this application are described in the following table.




String. The transfer destination.


Optional, CallEstablishOptions object.


Callback method.


Optional object.

BeginTransfer method parameters that are used in this application are described in the following table.




Call object, the call to replace.


Optional, CallEstablishOptions object.


Callback method.


Optional object.

Contextual data is supported by both the UCMA 3.0 Core SDK and the Lync SDK. Contextual data supports improved end-to-end communication by integrating external data sources, such as Customer Relationship Management (CRM), Enterprise Resource Planning (ERP), and web cookies, into a two-way contextual conversation. In this case we are displaying information about the customer on the agent's console at the time that the agent answers the transferred call.

You can provide any kind of data that you want - is this a good or bad customer, are they the owner's second cousin, what was their last order, how long have they been on hold? In our case, we performed some magical hand-waving and sent the agent a customer ID, account balance, and customer name. You should send information that gives the agent a better chance of meeting the organization's goals: increased sales, happy customers, quick turnaround, or all of the above.

Sending contextual data between a UCMA 3.0 middle-tier application and a Lync SDK client application requires the following setup.

  • The client application (in this case the agent application) must be registered.

  • The middle-tier application (in this case the bot application) must reference the GUID used in the client application’s registry entry.

The GUID identifies the conversation which carries the contextual data. For more information see part 3 in this series, and Application Registration for Lync 2010 Contextual Applications.

Figure 2. Contextual data displayed for the agent

Contextual data

To send contextual data

  1. Get the current conversation.

    Conversation conversation = call.Conversation;
  2. Get the remote endpoint.

    ParticipantEndpoint endpoint = call.RemoteEndpoint;
  3. Set the application GUID.

    Guid AppId = new Guid("client application GUID");
  4. Create a ConversationContextChannel object.

    _channel = new ConversationContextChannel(conversation, endpoint);
  5. Create a ConversationContextChannelEstablishOptions object.

    ConversationContextChannelEstablishOptions options = new ConversationContextChannelEstablishOptions();
  6. Get the contextual data and add it to the ConversationContextChannelEstablishOptions object.

    options.ContextualData = SetCallerInfo();
  7. Send the contextual data to the agent.

    _channel.BeginEstablish(AppId, options, BeginContextEstablishCB, null);

    The bot sends the contextual data to the agent's endpoint, and the data displays in a Silverlight application on the agent's console.

Mark Parker is a programming writer at Microsoft Corporation. His principal responsibility is the UCMA SDK documentation.

John Clarkson is also a programming writer on the Microsoft Lync feature team.