Communicating Between Workflow and VXML

When working with the VoiceXML Interpreter Activity the simple act of passing data between your Workflow and your VXML applications can be tricky to figure out. Hopefully this post will save someone the time I spent scratching my head the first time around.

Passing Data In

Lets say I want to pass “The dog is brown” to my VXML application so that is can in turn relay this very vital information to the caller.

Prior to VXML activity I’ll drop a Code activity with the following in its ExecuteCode method:


VXML.ApplicationData.Add("PassedInVar", "The dog is brown");

To access this data from within my VXML application I’ll need to reference both my variable name and the ApplicationData collection itself. For example:


<block>
  <prompt>
    <value expr="ApplicationData['PassedInVar']" />                
  </prompt>            
</block>

Passing Data Out

VoiceXML has a standard method of passing data out of an application using the <exit> tag (<exit namelist="SomeVar"/>).  Variables passed back via the “namelist” are stored as a Dictionary object in the ApplicationData collection.

Inside my VoiceXML application I’ll declare a Var and return it in my <exit> tag.


<block> 
    <prompt> 
        <value expr="ApplicationData['PassedInVar']" />                
    </prompt> 
    <var name="ReturnedVar" expr="'The cat is black'" />        
    <exit namelist="ReturnedVar"/> 
</block>

Once back in the Workflow I’ll extract the data from the ApplicationData collection’s $_exit_ element. I’ll drop a Code activity after the VXML activity with following in its ExecuteCode method:

UCMA 2.0 Tip: Communications Sequence Activity

I’ve been playing around with the UCMA 2.0 SDK for the last few weeks, mainly in preparation for the upcoming v.next release of Communication Server. For those interested in what comes after Speech Server it is a worthy endeavor to dig into the UCMA. Going forward the UCMA will be the tool we use. 

When I first started playing I made one simple mistake that left me scratching my head for longer that I’d like to admit. In an effort to help others avoid my mistake (and to remind me should I forget again):

With the UCMA, all of your activities must live within a Communications Sequence Activity.

With Speech Server the tools automatically provide you with a “parent sequence” in which all your activities live. With the UCMA this isn’t the case; you need to include it in your workflow. When you create a new project it provides this for you, just don’t be like me and think its ok to just delete it….

FTR, the exception I received was:

System.InvalidOperationException: ‘Workflow1’ does not have a value for Call property. Please specify a name that corresponds to a call in the CommunicationsWorkflowRuntime service

KB974571 Breaks OCS 2007 R2

I came back from vacation to find that I was unable to login to OCS. Turns out that an update installed on 10/14 broke the front-end services for OCS. The event log shows the following error:

The evaluation period for Microsoft Office Communications Server 2007 R2  has expired. Please upgrade from the evaluation version to the full released version of the product.

Uninstalling the KB974581 update corrected the problem.

Big thanks to Dietmar Kraume’s blog post at http://tinyurl.com/yjefeg9 for pointing to the solution.

Avoiding Call Throttling on Outbound Calls

imageOne of the most common ways of queuing outbound calls with Speech Server is by using the built in MSMQ support. For the most part, using a message queue is extremely straightforward and easy to implement. But there is one gotcha – call throttling.

When an outbound call fails to connect, Speech Server will start throttling down the number of messages it pulls from the queue. The assumption is that failures are the result of your system having insufficient capacity to handle the load. The more failures your have, the more it will throttle the load. This would be acceptable if it were not for two issues:

  • Almost any failure, even acceptable ones,  can result in throttling
  • It will happy throttle you all the way down to 0, effectively shutting down your application

Disabling call throttling needs to be done on a per-call bases by binding to the TelephonySession.OpenCompleted event prior to the MakeCall Activity. Typically I do this in a Code Activity at the very top of my workflow.

Inside my initWorkflow Activity I bind to the OpenCompleted like so:

 TelephonySession.OpenCompleted += new EventHandler<Microsoft.SpeechServer.AsyncCompletedEventArgs>(TelephonySession_OpenCompleted);

Then I use the following to disable throttling on any failure:

void TelephonySession_OpenCompleted(object sender, Microsoft.SpeechServer.AsyncCompletedEventArgs e)
{
    if (e.Error != null && e.Error is SipPeerException)
    {
        SipPeerException sipEx = e.Error as SipPeerException;
        sipEx.ShouldThrottleMsmqCalls = false;
    }
}

Handling SIP Errors on Outbound Calls

 

imageWhen placing outbound calls there are a number of scenarios that you will want to apply business logic too. When your application reaches a BUSY number for example, you will need to make an appropriate decision as to how to process this result (should you redial, wait some amount of time and then redial, stop calling, etc).

In order to handle these events you will first need to catch them using the Fault Handler page. From here you define the workflows for processing each fault type.

The default project template for speech workflows includes two fault handlers. The first handles call disconnections (normally this happens when a caller hangs up) and a general fault handler for catching everything else.

We’re going to add another one for trapping SIP results. This will fire off a code block where we will make decisions on how to handle the results we care about. 

  1. From the toolbox, drag a new FaultHandler object into the fault handler’s list.
  2. On the Properties tab for the FaultHandler, open the details dialog for the FaultType property.
  3. In the Type Name text box enter “Microsoft.SpeechServer.SipPeerException” and click ok.
  4. Drop a Code activity into the workflow area of the new FaultHandler instance
  5. Double-click the new Code activity to open the code view for the ExectuteCode event.

Now you can process the SipPeerException based on the ResponseCode you’ve received. For example:

if (sipPeerFaultHandler.Fault is Microsoft.SpeechServer.SipPeerException)
 {
     Microsoft.SpeechServer.SipPeerException ex = (Microsoft.SpeechServer.SipPeerException)sipPeerFaultHandler.Fault;
     switch (sipException.ResponseCode)
     {
         case 486: // Decline with Busy Here
         case 600: // Decline with Busy everywhere
             /*
              * 
              *  Handle your busy case here
              * 
              */
             break;
 
         case 480: // Temporarily unavailable
         case 503: // Service Unavailable
         case 603: // Decline
         case 408: // Request Timeout
         case 504: // Gateway Timeout
         case 404: // Not Found
         case 484: // Address Incomplete                 
         case 604: // Does Not Exist Anywhere
         case 485: // Ambiguous
         case 410: // Gone
         default:
             break;
     }
 }