Reducing media traffic from UCMA using call hold

For complex UCMA applications that handle things like quality monitoring, call recording, or call flow management, the effect of the UCMA application on network traffic can become a concern. For a UCMA application to act as a participant in an audio, video, or application sharing call, there must be a media stream flowing from the application to the remote party on the call, and another media stream flowing from the remote party back to the application, as in the diagram below. Each of these streams will take up bandwidth on whatever network the media must traverse to flow between the endpoints, or on the connection to the public Internet if the remote endpoint is an individual user logged into Lync remotely.

This effect can be multiplied in cases where a UCMA application maintains multiple audio/video calls with a conference, in order to provide separate services such as DTMF menus, recording,or hold music. Each of these individual calls requires a separate pair of media streams between the audio/video MCU and the UCMA application,as the following diagram illustrates.

Multiply this by hundreds or thousands of calls, and you can have some significant effects on network usage.

Often these audio/video calls between the UCMA application and an MCU or other Lync endpoint are there primarily to keep the SIP signaling session active, and not for sending or receiving media. In other cases, the application needs to deal with media, but only for brief periods or under certain conditions (e.g., if hold music is activated). This means that there is media traffic flowing to and from the UCMA application for no purpose, using up network bandwidth needlessly.

One way to help reduce this extraneous traffic is to put these calls on hold, using the AudioVideoFlow.BeginHold method in UCMA. Here is an example of the code you might use:

[csharp] try { _avCall.Flow.BeginHold(HoldType.BothEndpoints, ar => { try { _avCall.Flow.EndHold(ar);

Console.WriteLine("Call has been placed on hold."); } catch (RealTimeException ex) { Console.WriteLine(ex); } }, null);

} catch (InvalidOperationException ex) { Console.WriteLine(ex); } [/csharp]

This will cause UCMA to send a new SIP INVITE message (a "re-INVITE" because it is not the initial INVITE that set up the call). This re-INVITE, like the initial INVITE, has a message body consisting of Session Description Protocol, but with a single line added:

[xml]a=inactive[/xml]

This line indicates to the remote endpoint that audio media is temporarily inactive. If you try this out on a call from a UCMA application to an audio/video MCU, you''ll see that the network traffic decreases after the call is put on hold.

If your application is a trusted participant in a conference, there won''t even be a visual indication of the call hold; no one else in the conference will have any idea that something has changed. If the application is not a trusted participant, or is on a two-party call, the Lync UI will show that the application''s call is now on hold.

If your application needs to do something with media again (like recording the call or playing a message) you can take the call off hold just as easily:

[csharp] try { _avCall.Flow.BeginRetrieve(ar => { try { _avCall.Flow.EndRetrieve(ar);

Console.WriteLine("Call has been taken off hold."); } catch (RealTimeException ex) { Console.WriteLine(ex); } }, null);

} catch (InvalidOperationException ex) { Console.WriteLine(ex); } [/csharp]

UCMA will send another re-INVITE and media will become active again.

If you put calls on hold immediately after they''re established, you may run into some situations where the AudioVideoFlow object for the call doesn''t exist yet. To get around this, you can create an event handler for the AudioVideoCall.AudioVideoFlowConfigurationRequested event, like this one:

[csharp] _avCall.AudioVideoFlowConfigurationRequested += OnFlowConfigRequested; [/csharp]

Then, in this event, you can subscribe to state changes on the AudioVideoFlow object:

[csharp] void OnFlowConfigRequested(object sender, AudioVideoFlowConfigurationRequestedEventArgs e) { e.Flow.StateChanged += OnFlowStateChanged; } [/csharp]

Finally, in the StateChanged event handler, you can watch for the flow to become active, and put it on hold at that point.

[csharp] void OnFlowStateChanged(object sender, MediaFlowStateChangedEventArgs e) { Console.WriteLine("Flow changed from {0} to {1}", e.PreviousState, e.State);

AudioVideoFlow flow = sender as AudioVideoFlow;

if (e.State == MediaFlowState.Active) { // Call a method we''ve already created // to put the call on hold. PutOnHold(flow); } } [/csharp]

I''m planning to cover more ways to deal with the media traffic created by UCMA applications in future posts, so please let me know if there are specific topics you''d like to read about!