Posted by: rcosic | 02/11/2011

Starting with Lync Client’s API

Note: this post is part of Lync Client development series. You can find the following topics here:

Hi everyone!

Today I will concentrate on explaining some of the most usual development tasks when using Microsoft Lync Client API.

For events and actions available from Lync related classes, I’m using a wrapper class that will serve me as an intermediate layer between my worflow (or view model) and the model itself. Inside this class I usually put all the code to communicate with the Lync Client through the API. Some additional classes and structures may appear if you want to further enhance some of the functionality (e.g. LyncConversation, LyncContact classes, and so on).

So, what to put in this wrapper class? First of all, I mark it IDisposable, as it will be easier to put all the cleanup code in one place and leave the CLR to handle it respectively. Next, I’ll sure have some instance of the LyncClient object itself, but beware – you should handle its life cycle and be cautious in case of disconnecting and some actions not available (i.e. plan your exception handling well).

I publish some general events, such as OnLyncConnected and OnLyncDisconnected, together with some public properties representing state (Connected, etc.). Since Lync can handle more than one active conversation at a time, it would be helful to keep track on active conversation(s), as well as the state of the conversations. This also applies to the contacts, since the way we can reach published contacts is farly inadequate. For list of conversations I use dictionary with hashcode as a key and conversation object as a value, but you can use some other way to store it (ObservableCollection, Tuple, and so on). For the contacts, you should have to subscribe to contact’s changes as presented in the following method definition:
///

/// Subscribe to the changes of Lync contacts availability through contact manager’s subscription mechanism.
/// Once subscribed, the caller will start receiving events whenever any of the Lync contacts changes its state.
///

internal void SubscribeToContactChanges()
{
// get the contacts if the Microsoft Lync Client is fully available
if (Connected && m_lyncClient.State == ClientState.SignedIn)
{
// create new contact subscription for tracking the active contacts on the GUI
if (m_contactSubscription == null)
{
m_contactSubscription = m_lyncClient.ContactManager.CreateSubscription();
}

// get all custom groups (“Other contacts” and so on…)
IEnumerable customGroups = m_lyncClient.ContactManager.Groups.Where(p => p.Type == GroupType.CustomGroup);

if (customGroups != null)
{
foreach (Group customGroup in customGroups)
{
// group events are raised when the state of a group is changed by updating the group membership or changing the name of the group.
customGroup.ContactAdded += new EventHandler(ContactGroup_ContactAdded);
customGroup.ContactRemoved += new EventHandler(ContactGroup_ContactRemoved);

// There are three kinds of state change events that are raised on an individual contact.
// These events can only be raised when the contact has been added to a ContactSubscription and your application has registered for events on a Contact.
// In the case where a given contact appears in the Lync 2010 contact list,
// you do not need to add the contact to a contact subscription because Lync 2010 itself maintains a subscription.
// In contrast, a contact that you obtain using the search feature of the API must be added to a contact subscription that your application maintains.

foreach (Contact contact in customGroup)
{
// add the Contact instance to the subscription if a contact is not already in the ContactSubscription instance
if (m_contactSubscription != null && !m_contactSubscription.Contacts.Contains(contact))
{
// add contact to contact subscription
m_contactSubscription.AddContact(contact);
}

// get presence item values of interest from each contact
// Trigger update of the user interface to reflect the contact list change.

}
}

// include also “Self” in the contact list
m_contactSubscription.AddContact(m_lyncClient.Self.Contact);

//Specify contact presence items to subscribe for
ContactInformationType[] contactInformationTypes = { ContactInformationType.Availability, ContactInformationType.ActivityId };

// The Subscribe method creates a request on Lync Server 2010 that asks for continuous updates of the presence information from each contact added to the subscription.
m_contactSubscription.Subscribe(ContactSubscriptionRefreshRate.Low, contactInformationTypes);
}
}
}

There are several keypoints to this:

You should use a ContactManager object and its CreateSubscription method to effectively create a subscription to your contacts. You will normally get “other groups”, but you can search by other group names and distribution groups. You should subscribe to events triggered when some contact is added or removed to the group, and add the contacts initially into the subscription. Note: not into the list, but rather into the subscription instance!

One of the scenarios you might have is to include also yourself as a contact to the list (since you are not in your contact list). You can add yourself to the list by using LyncClient’s Self object, and its corresponding Contact property.

To actually subscribe to contacts changes, you should specify by which rate the changes will be monitored, and what properties will be monitored. For presence status, for example, you should denote Availability and ActivityId.

Next, try to grab as many useful events as you can. For example, on the most general level (LyncClient instance) you can respond to: StateChanged, SignInDelayed, CredentialRequested, ClientDisconnected, CapabilitiesChanged, DelegatorClientAdded and DelegatorClientRemoved. Of course, the sign-in process should also be a part of this class. For details, see my previous posts..

Since Self object (and all others in the object’s structure) will be available only when a user signs in, you should take care to proper subscribe and unsubscribe from these events. For example, when a user is successfully signed in, subscribe to its Self events. Others can come in the constructor or some other place (like the ones concerning ContactManager or ConversationManager).

To handle conversations you can subscribe to ConversationManager object’s ConversationAdded and ConversationRemoved events. ConversationAdded event occurs when a new conversation is taking place and you can use it to store the conversation into the list, subscribe to its related events, such as ParticipantAdded, StateChanged, ActionAvailabilityChanged, and PropertyChanged. Also, this is an ideal place to check modalities , that is, whether it is an audio, video call, or IM conversation. And also to start keeping track on their events accordingly – the most important of them is ModalityStateChanged. Also, ActionAvailabilityChanged and ModalityPropertyChanged (for A/V call) and InstantMessageReceived and IsTypingChanged (for IM) may prove useful.

The last point I want to implicate is Availability. This is something that you should get to know by start. There is no “state” of the Lync Client, but rather more “states” you should track if you want to know in which state your client is. For example, you may be busy, but this state can also be triggered manually by yourself. And getting your state(s) is done, as most of the tasks in Lync, asynchronously. And, once again, Self object should be used for that purpose:
Contact self = m_lyncClient.Self.Contact;

//get actual contactModel availability (Will be int value within OCOM availaiblity ranges)
return (ContactAvailability)self.GetContactInformation(ContactInformationType.Availability);

This piece of code gets the contact object from within Self object, and gets information about your availability. Notice that you would need to examine if you are supposed to do some action (whether you have rights or action is currently unavailable).  The similar code will be in handling Self’s ContactInformationChanged event (if you are subscribed to it).

To set yourself on a different state you can do the following:
Dictionary publishData = new Dictionary();
publishData.Add(PublishableContactInformationType.Availability, newState);

if (!string.IsNullOrEmpty(activityId))
{
publishData.Add(PublishableContactInformationType.ActivityId, activityId);
}

object[] asyncState = { m_lyncClient.Self };

m_lyncClient.Self.BeginPublishContactInformation(publishData, null, asyncState);

Notice that you fill in a dictionary with some PublishableContactInformationType objects (you can set Availability, ActivityId, CustomActivityId, LocationName, PersonalNote, DisplayPhoto, and PhotoUrl). Then you push this information by calling asynchronously PublishContactInformation method, passing its data, callback and object state.


Responses

  1. Thanks a lot! Great article!

  2. I wanted to thank you for this great read!! I
    certainly loved every bit of it. I have you bookmarked to check out new things you post…


Leave a comment

Categories