SIP Monitoring with Wireshark

SIP Monitoring with Wireshark

This topic comes up pretty often and while this article was originally written for Wireshark v1.05 in 2009, it still applies today. All of the instructions are accurate for Wireshark v1.6.1.

Wireshark is a free tool for capturing network traffic. It is an invaluable resource for troubleshooting problems with VOIP calls. It is available for download from www.wireshark.org (current version for Windows as of this post is 1.05).

I’m going to walk through the steps required for setting up a basic trace with Wireshark. This will give you a view of the underlying SIP traffic between your speech platform and your SIP gateway.  Please note that this information isn’t specific to Lync or UCMA so if you’re using something else simply replace these references with your platform.

1) Download and install Wireshark from www.wireshark.org on the machine where Speech Server is installed.

Wireshark- Capture Interfaces 2) Now launch Wireshark and open up the “Capture” menu. Select “Interfaces” (the first item in the menu). This will open a window listing each of your network adapters, their current IP address and the number of packets currently travailing down the wire.

3) Click the “Start” button for the interface that UCMA is using (sometimes it helps to run a call and see which interface has traffic).

Wireshark- Raw Capture Data 4) Now you should be seeing a flood of traffic in the Wireshark window. This is a real-time view of the data traveling up and down you’re network connection (it is a bit scary how much traffic you see on a typical network). Of course as it stands right now there is far too much information being shown to parse through. To narrow our focus we’ll apply a “Filter” for the traffic we want.

Wireshark - SIP Capture Data 5) In the Wireshark filter’s box enter the value “sip” (all lowercase) and hit enter. This will filter out everything that isn’t SIP traffic. In this screenshot you can see the traffic for a single call.

Wireshark - SIP INVITE6) The top section shows a summary of each packet including the time, source and destination. The lower section shows the contents of the selected packet from above. It is this lower area where you can see the actual SIP traffic details. By expanding the “Session Initial Protocol” section for the first packet we can see the INVITE header that was sent to the gateway.

This is just a starting point. There are a lot of valuable functionality in Wireshark such as decoding the audio from the call, viewing ladder diagrams of the conversation, complex filtering rules… There is a lot in there. But every one of them starts with this simple collection process.

There is quite a bit of information in a typical SIP conversation and often times troubleshooting involves figuring out obscure differences between the server and the gateway SIP implementation. As an example, I once found a problem between the Nuance Voice Platform and an Acme Packet SBC involving the format of the ALLOW property of the SIP INVITE (turns out Nuance wants them all delimited on one line and Acme Packet put them out as separate elements). Without Wireshark I would have been trying to diagnose this blind.

The only downside is that you can only monitor conversations between two endpoints. For developers this means you can’t easily view the conversations using the Visual Studio debugging tools. You need a gateway or remote SIP phone in order to see what information is being transmitted.

Implementing InstanceDependencyProperty

Implementing InstanceDependencyProperty

If you were looking to the UCMA 3.0 documentation for information on how to use InstanceDependencyProperty, don’t. Its incomplete and what is there is incorrect.

In an effort to implement my custom activities in the same way as Microsoft, I wanted to ensure that property values didn’t get destroyed when you moved on to the next activity in your workflow. This is vital if you plan on returning values from a Workflow Activity for another Activity to make use of. For example, you likely want the Recognition Result from the question you asked them so you can act on it.

The InstanceDependencyProperty allows you to keep property changes you made within an Activity. Without it, the second the instance of that Activity is finished executing, the property changes are discarded. If you checked them from another activity, all you’d get are the default values. Not very useful if you ask me.

So here is an stripped down example of an Activity that implements InstanceDependencyProperties properly:

[csharp]
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Serialization;
using Microsoft.Rtc.Workflow.Activities;

namespace AudioRecordingActivity
{
public partial class Activity1 : Activity, IInstanceDependencyContainer
{
private static System.Collections.Generic.Dictionary _instanceDependencyProperties;

public Activity1()
{
_instanceDependencyProperties = new System.Collections.Generic.Dictionary();
}

public System.Collections.Generic.Dictionary InstanceDependencyProperties
{
get { return _instanceDependencyProperties; }
}

public readonly static InstanceDependencyProperty MyStringProperty = InstanceDependencyProperty.Register("MyString", typeof(string), typeof(Activity1), "Empty");
public string MyString
{
get
{
if (base.DesignMode) return InstanceDependencyHelper.GetValue(this, MyStringProperty).ToString();
else return InstanceDependencyHelper.GetValue(this, this.WorkflowInstanceId, this.MyStringProperty).ToString();
}

set
{
if (base.DesignMode) InstanceDependencyHelper.SetValue(this, MyStringProperty, value);
else return InstanceDependencyHelper.SetValue(this, this.WorkflowInstanceId, MyStringProperty, value);
}
}

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
MyString = "Test String";
return base.Execute(executionContext);
}
}
}
[/csharp]

Here the key things to know:

  1. Your Activity needs to implement the IInstanceDependencyContainer interface
  2. When you impement the interface, the private _instanceDependencyProperties dictionary must be static
  3. Your properties must implement both prototypes of GetValue/SetValue. One is used for design-time, the other for run-time.

One other important note. In the documentation example they use a property with a TimeStamp type. You need to decorate this property with [TypeConverter(typeof(TimeSpanConverter))] or it will give you a very vague error at compile time.

UPDATE: I had initially thought I had this fully working until I attempted to drop more than one of my custom activities on my workflow. I quickly found an issue with the static _instanceDependencyProperties however. Because it was static, changes to properties on Activity1 were reflected on Activity2. After some time with Reflector, looking at how Microsoft’s activities were built, I noticed they used two different versions of InstanceDependencyHelper, one for design time and one for run time. Low and behold, if you implement both versions and remove the static statement you get the correct behavior. Its very unfortunate that the documentation doesn’t explain this.

Building a New Record Audio Activity

Building a New Record Audio Activity

One of the key activities missing from UCMA that we used in Speech Sever 2007 is the Record Audio Activity. This was one of my “go to” tools in the Speech Server arsenal, so I’ve been hurting without. So to eliminate my pain, and hopefully some other’s, I’ve started building a replacement.  While what I’ve built so far isn’t nearly feature-complete, it will hopefully provide a suitable starting point for those looking to simply record some audio. Trust me, starting from scratch wasn’t much fun. It may seem simple (and it really is) but it was extremely unclear when I started. A special thanks to Marshall Harrison who helped me put this together.

What’s Included

  • InitialSilenceTimeout – How long should we record silence before we decide the calling isn’t going to start talking
  • EndingSilenceTimeout – How long should we record silence before we decided the caller has stopped talking
  • FilePath – Full path where we should save the file (this is new, it wasn’t definable in Speech Server)
  • AudioEncoding – Format to encode the saved file as (Wma16Kbps,Wma48Kbps, Pcm16Khz or Pcm8Khz)
  • RecordedLength – The length of the recorded made

What’s Not Included

  • LeadingSilenceTrimmedLength – We’re just saving the raw audio, there is no post-processing of the file
  • TrailingSilenceTrimmedLength – See above
  • PlayBeep – This object simply records audio, it doesn’t play any prompts or tones
  • Prompts  – See above
  • TerminationDigits  – The only method used for stopping recording at this point is silence from the caller
  • CanBargeIn – Given the lack of prompts, there was nothing to “barge in” on

I’ve included the full project (and the compiled Debug and Release versions) here:  AudioRecordingActivity1.2

UPDATE: I’ve fixed a few issues and updated the download to v1.1.

Update: We’re now at v1.2. This version solves some problems with Properties when multiple copies of the activity are in the same workflow