From time to time, someone asks me whether there is a way to move a call from one Lync conference to another using UCMA. In other words, they want their UCMA application to be able to take someone who is connected to Conference A, and cause that person to suddenly be connected to Conference B.

Now, whenever I’m explaining a concept and I start having to talk about Thing A, Thing B, Thing C, and so forth, I begin to feel that a diagram is in order. So here’s the idea in simple pictures with little blue people. Say Frank is on a conference, Conference A. There’s another conference, Conference B, which Frank is not connected to. Both of these conferences are owned by a UCMA application,which is also participating in both of them.

We want the application to somehow transfer Frank from Conference A to Conference B. Frank shouldn’t have to click anything or answer a new incoming call. Lync should simply take the call between Frank and Conference A,and turn it into a call between Frank and Conference B:

This might seem like a bizarre thing to do, so let me take a bit of a break and mention a few examples of scenarios where this would be useful.

Example Scenarios

For one, Frank might be a contact center agent who has been talking to a customer and has just finished the call. Instead of letting Frank go on break right away, we want to connect him to a supervisor who has been monitoring the call so the supervisor can give him feedback. Or maybe we just want to keep him connected to an empty conference; some contact centers like to keep agents “off hook” as long as they are logged in.

Another possibility is that one of the conferences might be serving as a “holding zone” for callers who are waiting to be connected to someone or to some other part of the application, sort of like a more advanced version of the Lync conference lobby.

So, the next question is: how do we do it?

The Trouble With Transfers

The difficulty that always comes up in situations like these is that an application can’t control calls that belong to remote conference participants. Let me illustrate with another beautiful diagram.

The UCMA application here has created a conference and invited two other participants, Rodney and Philip. I’m simplifying a bit in this diagram, because the conference focus is involved as well, but the principle is the same regardless. Now, you might think, because the UCMA application has started a conference using the ConferenceSession class, that the conference is hosted by the UCMA application, and that Rodney and Philip are calling into the application in order to join the conference. If so, you have been deceived. What’s actually happening is that the UCMA application has a call with the audio/video MCU, and Rodney and Philip also have their own calls with the MCU.

Because the UCMA application is the conference owner, it can tell the MCU to do things by sending commands to it (and if the application has joined as a trusted participant, it can send even more commands), but the UCMA application itself has no direct access to the call between Rodney and the conference MCU, nor the call between Philip and the conference MCU. There is no way for the application to get a handle to those calls in the form of a Call object.

The solution is simple. There is a class, new to UCMA 3.0, which allows your application to greedily keep control of other people’s calls.

Making Calls “Moveable” With the BackToBackCall Class

By connecting each remote participant to the conference using a BackToBackCall, the application can maintain control of SIP signaling for the call. There’s plenty of information out there on the BackToBackCall class and its shenanigans, but to sum it up briefly, with a BackToBackCall, the application acts as a proxy for all SIP signaling between two remote participants (in this case, a user and a conference), while the media flows directly between the two points.

Here’s an incoming audio call event handler that creates a new ad hoc conference and connects the caller to the conference using a BackToBackCall:

private void OnAudioVideoCallReceived(object sender, CallReceivedEventArgs args)
{
_logger.Log("Incoming call.");
// Create a conversation to use to join the ad hoc conference.
Conversation conferenceConversation = new Conversation(_endpoint);
// Join the conference.
conferenceConversation.ConferenceSession.BeginJoin(
null as ConferenceJoinOptions,
ar =&gt;
{
// Create a call into the conference. This will be call leg 2.
_conferenceCallLeg =
new AudioVideoCall(conferenceConversation);
// The incoming call will be call leg 1.
_incomingCallLeg = args.Call;
// Create the settings for the back to back call.
BackToBackCallSettings settings1 =
new BackToBackCallSettings(_incomingCallLeg);
BackToBackCallSettings settings2 =
new BackToBackCallSettings(_conferenceCallLeg, _destinationSipUri);
// Create and establish the back to back call.
BackToBackCall b2bCall = new BackToBackCall(settings1, settings2);
try
{
_logger.Log("Establishing back to back call...");
// Establish the back to back call.
b2bCall.BeginEstablish(
ar2 =&gt;
{
try
{
b2bCall.EndEstablish(ar2);
_logger.Log("Established back to back call.");
// Wait for 5 seconds.
Thread.Sleep(5000);
_logger.Log("Transferring the call into a new conference...");
TransferIntoNewConference();
}
catch (RealTimeException ex)
{
_logger.Log("Failed establishing a back to back call.", ex);
}
},
null);
}
catch (InvalidOperationException ioex)
{
_logger.Log("Failed initiating a back to back call.", ioex);
}
},
null);
}

In the first method, the application creates a second ad hoc conference and joins it as a participant. Next, in the EstablishAudioCallInNewConference method, it transfers the original incoming call into the new conference. The caller gets pulled out of Conference A and transferred straight into Conference B, without having to do anything in the Lync client.

Now, keep in mind that this process is not repeatable. When you transfer the call using AudioVideoMcuSession.BeginTransfer, you are pulling it out of the back-to-back arrangement, and your application will no longer have a handle to the call. The Call object you have will go into the Terminated state and the caller will once again become a remote participant, completely out of your grasp.

There is a way to retain control of the call after doing a transfer like this, using a strange technique known as the self-transfer. But I’ll have to leave that to a future post.

I’m curious if there is a way (with UCMA 4 or 5 now) to be able to have an application that monitors the health of application endpoints, take a conference owned by a now dead application and move it to a healthy application?