Walkthrough: Park and Re-activate an Audio Conversation (Lync 2010 SDK)
Microsoft Lync 2010 API provides a call hold and call park feature. With call park, a user simultaneously places a call on hold and sends the call to a network call-park service where another user can retrieve the call.
Warning
The call park feature is not available when Microsoft Lync Server 2010 is in branch-datacenter resiliency mode.
With the call park feature, you do not need to know what user will pick the call up from the network call-park service. While the call is parked on the network, you can broadcast the call park Orbit URI of the parked call to multiple potential users. One of these users can retrieve the call from the network call-park service using the Orbit of the parked call. Broadcasting the Orbit gives unintended users access to the parked call. If this is a concern, you should identify a target user and directly transfer the call instead of parking it.
With call park, local client resources and network bandwidth resources are not dedicated to maintaining the state of the conversation. The only state object that a local client application should maintain is the string object representing the parked call Orbit.
A network call-park service typically maintains a limited number of orbits that you can park a call on. If an orbit is not available, a park request fails. To avoid using an orbit unnecessarily, you should transfer a call if you have determined a specific transfer target.
While a call participant is on hold in the network call-park service, an audio stream configured by an administrator is streamed to the participant. This feature is configured using Lync Server Control Panel.
Tip
You can park an audio/video call, however only the audio portion of the call is parked. The video channel is disconnected. You must re-connect the video channel when the call is picked up from a call park orbit.
In the following walkthrough, a local client application places a conversation on a network call-park service. The walkthrough concludes by showing how a different user retrieves the parked call represented by the broadcasted Orbit. The walkthrough creates a new conversation and adds the parked call as a participant.
To park a call, you use the BeginPark method of the conversation. When a call is parked, you retrieve the call using the CallParkOrbit property of the conversation.
Parking an Audio Conversation
The following figure illustrates the classes, methods, and events used in the process of parking an audio conversation.
Park an Audio Conversation
Declare an instance of CallParkOrbit as a private class field.
Add an audio conversation. For more information, see Walkthrough: Start an Audio Conversation (Lync 2010 SDK).
Tip
You can park any active audio or audio/video conversation regardless of the origin. When parking an audio/video conversation, the video channel of the conversation is disconnected. If you want to display video, you must re-connect the video channel when picking up a park conversation.
Call the CanInvoke method. If true is returned, go to the next step. Otherwise, you should verify the conversation is connected and not on hold.
Call the BeginPark method on the conversation with an asynchronous callback method conforming to the signature of System.AsyncCallback as the first argument.
In the callback method, get the CallParkOrbit where the call was parked. Read the Properties property collection and get the call park orbit property using the ConversationProperty.CallParkOrbit enumerator. You get the Orbit of the parked call by reading the FriendlyOrbit property. If you want to give other users a reference to the parked call, you must provide the string value of FriendlyOrbit to all potential users. An example of a mechanism you can use is the IM conversation you can create with a participant list that includes users who may retrieve the parked call. You can send the FriendlyOrbit string to each participant as message text.
Tip
Do not broadcast the SafeRetrieveUri to the users who you intend to give access to the parked call. SafeRetrieveUri should be reserved for the following scenario.
Use the SafeRetrieveUri property if you intend for the local user to retrieve his or her parked call. In the following scenario, the SafeRetrieveUri property should be used. Suppose Mary calls Bob. Bob wants Mary to speak to another team member and parks her on Orbit "123". Mary decides not to wait until Bob picks up the call again and hangs up. Now Orbit "123" is available. Michael and Steven are having a conversation at the same time. Michael parks Steven on the now free Orbit "123". Bob tries to retrieve Mary using the FriendlyOrbit property and obtains the call at Orbit "123". Bob is surprised to discover he is talking to Steven instead of Mary.
If Bob had used the SafeRetrieveUri property, the network call-park service would not have connected Bob to Steven because Bob did not park Steven.
As an alternative to using the callback method in the previous step, you can handle the ActionAvailabilityChanged event raised by the parked Conversation. Read the Action property. If the event is raised because the conversation was parked, the action is ConversationAction.Park. If the action is Park, then you get the CallParkOrbit from the conversation as described in the previous step.
Retrieving a Parked Conversation
This walkthrough assumes that a user has obtained the parked call Orbit broadcast by the user who parked the call originally. The walkthrough creates a new audio conversation and adds the parked call as the remote user. For information about starting an audio conversation, see Walkthrough: Start an Audio Conversation (Lync 2010 SDK).
Register for ConversationAdded.
Call into AddConversation to create a new conversation specifying the audio/video modality.
Register for ParticipantAdded on the new conversation returned in the ConversationAdded event handler.
Verify that a participant can be added to the new conversation by calling into CanInvoke, passing ConversationAction.AddParticipant. If true is returned, proceed to the next step of the walkthrough.
Create a new Contact by passing either a safe retrieve Uri or friendly orbit Uri into GetContactByUri(string) and add the returned Contact to a new Conversation by calling into AddParticipant.
Call the BeginConnect(AsyncCallback, Object) method on the audio/video modality returned by Modalities[ModalityTypes.AudioVideo] to allow both the local and remote endpoints to accept the conversation. You must call EndConnect after calling BeginConnect. You can call EndConnect on your UI thread or you can call it within a System.AsyncCallback method you pass into BeginConnect.
Examples
The following example parks a conversation named myConversation and designates the ConversationCallback method as the callback for the BeginPark method.
/// <summary>
/// Parks a conversation.
/// </summary>
private void ParkConversation()
{
_ParkOrbit = null;
try
{
if (_Conversation.CanInvoke(ConversationAction.Park))
{
_Conversation.BeginPark(CallParkCallback, _Conversation);
}
}
catch (NotReadyException e)
{
MessageBox.Show("Conversation park: Lync Exception: " + e.Message);
}
}
The following example handles the ActionAvailabilityChanged event raised by the Conversation instance when the call is parked or activated.
void Conversation_ActionAvailabilityChanged(Conversation source, ConversationActionAvailabilityEventArgs data)
{
// Is this event the result of a Park operation?
if (data.Action == ConversationAction.ParkAction)
{
if (source.State == ConversationState.Parked)
{
MessageBox.Show("Conversation Parked");
}
else if (source.State == ConversationState.Active)
{
MessageBox.Show("Conversation Activated");
}
}
}
The next example is the callback method for the call to the BeginPark method. This method retrieves and stores locally the value of the CallParkOrbit property in the ConversationProperty enumeration of the conversation that was parked. The example reads the AsyncState property that allows it to associate its invocation with the call park operation that initiated the callback.
Tip
It is not necessary to provide a callback method to the call into Park if you handle the ActionAvailabilityChanged event. You can obtain the CallParkOrbit instance from the Conversation instance in the ActionAvailabilityChanged event handler if you do not provide an asynchronous callback method to be invoked by the conversation when it is parked.
If a network call-park service is not available, the operation completes its run but will not succeed.
/// <summary>
/// Called on the LyncClient worker thread when asynchronous call park operation completes.
/// </summary>
/// <param name="ar">IAsyncResult. The state of the asynchronous operation.</param>
private void CallParkCallback(IAsyncResult ar)
{
if (ar.IsCompleted == true)
{
object orbitProperty = ((Conversation)ar.AsyncState).Properties[ConversationProperty.CallParkOrbit];
((Conversation)ar.AsyncState).EndPark(ar);
_ParkOrbit = orbitProperty as CallParkOrbit;
((Conversation)ar.AsyncState).End();
_Conversation = null;
}
}
For an example of starting an audio conversation in order to pick up a parked call, see Walkthrough: Start an Audio Conversation (Lync 2010 SDK). Use the friendly orbit Uri or safe retrieve orbit Uri string to get a Contact to be added to the new audio conversation.