Call forwarding, UCMA, and "derived conversations"

If you have a UCMA application that communicates with users via both IM and audio in the same conversation, you may one day be caught off guard by the following exception:

Microsoft.Rtc.Signaling.OperationFailureException: Application must register 
for ConversationChanged event when a call is moved to a derived conversation.

Specifically, this exception occurs if you try to add audio to a conversation that currently only has instant messaging and/or application sharing, and the remote party redirects the audio call to a PSTN phone; maybe because they don't have headphones plugged in, or because they are on a wireless network which has been causing poor audio quality, or even because they are logged in on a client that doesn't support audio.

What's happening here is that the audio call that is part of the conversation is being routed to a PSTN phone, through the Mediation Server, instead of the original destination user. Because of this, the call is split off from the original Conversation object and is moved to a new, "derived" conversation, with a new conversation ID. If you look at the original Conversation object (the one that the IM call belonged to), you won't see an AudioVideoCall,nor will you see the PSTN phone as a remote participant. At this point,you have no way to control the new audio call with the PSTN phone. Basically, UCMA tries to save you from yourself by insisting that you hook up an event handler to get the details of the new, derived Conversation. The event you need is Call.ConversationChanged.

To be notified when a derived conversation like this is created, subscribe to the ConversationChanged event on the new AudioVideoCall, like so:

[csharp] avCall.ConversationChanged += new EventHandler<ConversationChangedEventArgs>(OnAvCallConversationChanged); [/csharp]

In this event handler, you can do something useful with the new Conversation object, hopefully something more useful than just dumping the details to the console, as I'm doing here:

[csharp] void OnAvCallConversationChanged(object sender, ConversationChangedEventArgs e) { Console.WriteLine("Call moved to derived conversation! Old ID: {0}. New ID: {1}. Reason: {2}.", e.PreviousConversation.Id, e.NewConversation.Id, e.Reason); } [/csharp]

This eliminates the exception and allows you to keep control of the audio call after it is redirected.