I decided to combine the Lync client SDK with the speech synthesizer SDK and not only get myself a persistent popup notification, but have the new notification read to me, assuming my Lync status was not DND or Busy.
Step 1
Add these classes to your project.
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Conversation;
using System.Diagnostics;
using System.Speech;
using System.Speech.Synthesis;
Step 2
Declare some variables
LyncClient lyncClient;
List<ConversationHandler> conversations = new List<ConversationHandler>();
SpeechSynthesizer synth = new SpeechSynthesizer();
From here you need to assign some values and add some handlers somewhere like the window loaded event.
lyncClient = LyncClient.GetClient();
lyncClient.ConversationManager.ConversationAdded += ConversationManager_ConversationAdded;
lyncClient.ConversationManager.ConversationRemoved += ConversationManager_ConversationRemoved;
Now as a conversation gets added you can create a conversation handler for each one, that can then notify you when you receive a new message in that conversation
var conversationHandler = new ConversationHandler(conversation);
conversationHandler.MessageError += new MessageError(conversationService_MessageError);
conversationHandler.MessageRecived += new MessageReceived(conversationService_MessageRecived);
conversations.Add(conversationHandler);
//starts listening to Lync events
conversationHandler.Start();
The conversation handler cs code is attached here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Conversation;
namespace LyncNotifier
{
/// <summary>
/// Called when a message is received from Lync.
/// </summary>
public delegate void MessageReceived(string message, string participantName, string nuri);
/// <summary>
/// Called when there was an issue with the conversation.
/// </summary>
/// <summary>
/// Called when there was an issue with the conversation.
/// </summary>
public delegate void MessageError(Exception ex);
/// <summary>
/// Registers for conversation and participants events and responds to those by
/// notifying the UI through the events. This is the main point for interactions
/// with the Lync SDK.
/// </summary>
public class ConversationHandler
{
//the conversation the translator is associated with
private Conversation conversation;
/// <summary>
/// Registers for conversation and participants events and responds to those by
/// notifying the UI through the events. This is the main point for interactions
/// with the Lync SDK.
/// </summary>
public class ConversationHandler
{
//the conversation the translator is associated with
private Conversation conversation;
public Conversation Conversation
{
get { return conversation; }
set { conversation = value; }
}
//Self participant's IM modality for sending messages
private InstantMessageModality myImModality;
/// <summary>
/// Occurs when a message is received from Lync.
/// </summary>
public event MessageReceived MessageRecived;
/// <summary>
/// Occurs when there was an issue with the conversation.
/// </summary>
public event MessageError MessageError;
/// <summary>
/// Receives the conversation, callback to UI and the OC root object
/// </summary>
public ConversationHandler(Conversation conversation)
{
//stores the conversation object
this.conversation = conversation;
//gets the IM modality from the self participant in the conversation
this.myImModality = (InstantMessageModality)conversation.SelfParticipant.Modalities[ModalityTypes.InstantMessage];
}
/// <summary>
/// Hooks into the conversation events so incoming messages are translated.
/// </summary>
{
get { return conversation; }
set { conversation = value; }
}
//Self participant's IM modality for sending messages
private InstantMessageModality myImModality;
/// <summary>
/// Occurs when a message is received from Lync.
/// </summary>
public event MessageReceived MessageRecived;
/// <summary>
/// Occurs when there was an issue with the conversation.
/// </summary>
public event MessageError MessageError;
/// <summary>
/// Receives the conversation, callback to UI and the OC root object
/// </summary>
public ConversationHandler(Conversation conversation)
{
//stores the conversation object
this.conversation = conversation;
//gets the IM modality from the self participant in the conversation
this.myImModality = (InstantMessageModality)conversation.SelfParticipant.Modalities[ModalityTypes.InstantMessage];
}
/// <summary>
/// Hooks into the conversation events so incoming messages are translated.
/// </summary>
public void Start()
{
//subscribes to new participants (in more people joins the conversation
conversation.ParticipantAdded += new EventHandler<ParticipantCollectionChangedEventArgs>(conversation_ParticipantAdded);
//registers for all existing remote participants messages
foreach (Participant participant in conversation.Participants)
{
//skips the self participant (only remote messages are translated)
//Note: Self participant also fires InstantMessageReceived
//In this case, we're not interested in watching messages
//sent by the self participant (actually reported as InstantMessageReceived)
if (participant.IsSelf == false)
{
SubcribeToParticipantMessages(participant);
}
}
}
/// <summary>
/// Called by the Lync SDK when a new participant is added to the conversation.
/// </summary>
private void conversation_ParticipantAdded(object sender, ParticipantCollectionChangedEventArgs args)
{
//subscribes to messages sent only by a remote participant.
if (args.Participant.IsSelf == false)
{
SubcribeToParticipantMessages(args.Participant);
}
}
/// <summary>
/// Register for InstantMessageReceived events for the specified participant.
/// </summary>
/// <param name="participant"></param>
private void SubcribeToParticipantMessages(Participant participant)
{
//registers for IM received messages
InstantMessageModality remoteImModality = (InstantMessageModality)participant.Modalities[ModalityTypes.InstantMessage];
remoteImModality.InstantMessageReceived += new EventHandler<MessageSentEventArgs>(remoteImModality_InstantMessageReceived);
}
// <summary>
/// Called by the Lync SDK when a new message is received.
/// </summary>
private void remoteImModality_InstantMessageReceived(object sender, MessageSentEventArgs args)
{
try
{
//casts the modality
InstantMessageModality modality = (InstantMessageModality)sender;
//gets the participant name
string name = (string)modality.Participant.Contact.GetContactInformation(ContactInformationType.DisplayName);
//reads the message in its plain text format (automatically converted)
string message = args.Text;
//List<string> mods = (List<string>)modality.Participant.Contact.GetContactInformation(ContactInformationType.InstantMessageAddresses);
string nuri = modality.Endpoint.Uri.ToString();
//string nuri = mods[0];
//notifies the UI about the new message
MessageRecived(message, name, nuri);
}
catch (Exception ex)
{
MessageError(ex);
}
}
// <summary>
/// Sends a notification about the composing state.
/// </summary>
public void SendComposingNotification(bool isComposing)
{
//send the event 'as-is' without checking the success
try
{
myImModality.BeginSetComposing(isComposing, null, null);
}
catch (LyncClientException e)
{
var eventHandler = MessageError;
if (eventHandler != null)
{
eventHandler(e);
}
}
catch (SystemException e)
{
//if (LyncModelExceptionHelper.IsLyncException(e))
//{
// // Handle the exception thrown by the Lync Model API.
// var eventHandler = MessageError;
// if (eventHandler != null)
// {
// eventHandler(e);
// }
//}
//else
//{
// Rethrow the SystemException which did not come from the Lync Model API.
throw;
//}
}
}
}
}
The final result will be a notification to your procedure conversationService_MessageReceived that will contain the message, participant name, and participant uri.
At this point you can do anything you want, I chose to speak the message if not busy;
synth.SpeakAsync(youmessage);
and then display a visual notification right about the task bar clock.
Sorry I can't give you more, but this is part of a commercial product, hopefully it's enough to get you started.
Doug Routledge, C# Lync, SQL, Exchange, UC Developer
{
//subscribes to new participants (in more people joins the conversation
conversation.ParticipantAdded += new EventHandler<ParticipantCollectionChangedEventArgs>(conversation_ParticipantAdded);
//registers for all existing remote participants messages
foreach (Participant participant in conversation.Participants)
{
//skips the self participant (only remote messages are translated)
//Note: Self participant also fires InstantMessageReceived
//In this case, we're not interested in watching messages
//sent by the self participant (actually reported as InstantMessageReceived)
if (participant.IsSelf == false)
{
SubcribeToParticipantMessages(participant);
}
}
}
/// <summary>
/// Called by the Lync SDK when a new participant is added to the conversation.
/// </summary>
private void conversation_ParticipantAdded(object sender, ParticipantCollectionChangedEventArgs args)
{
//subscribes to messages sent only by a remote participant.
if (args.Participant.IsSelf == false)
{
SubcribeToParticipantMessages(args.Participant);
}
}
/// <summary>
/// Register for InstantMessageReceived events for the specified participant.
/// </summary>
/// <param name="participant"></param>
private void SubcribeToParticipantMessages(Participant participant)
{
//registers for IM received messages
InstantMessageModality remoteImModality = (InstantMessageModality)participant.Modalities[ModalityTypes.InstantMessage];
remoteImModality.InstantMessageReceived += new EventHandler<MessageSentEventArgs>(remoteImModality_InstantMessageReceived);
}
// <summary>
/// Called by the Lync SDK when a new message is received.
/// </summary>
private void remoteImModality_InstantMessageReceived(object sender, MessageSentEventArgs args)
{
try
{
//casts the modality
InstantMessageModality modality = (InstantMessageModality)sender;
//gets the participant name
string name = (string)modality.Participant.Contact.GetContactInformation(ContactInformationType.DisplayName);
//reads the message in its plain text format (automatically converted)
string message = args.Text;
//List<string> mods = (List<string>)modality.Participant.Contact.GetContactInformation(ContactInformationType.InstantMessageAddresses);
string nuri = modality.Endpoint.Uri.ToString();
//string nuri = mods[0];
//notifies the UI about the new message
MessageRecived(message, name, nuri);
}
catch (Exception ex)
{
MessageError(ex);
}
}
// <summary>
/// Sends a notification about the composing state.
/// </summary>
public void SendComposingNotification(bool isComposing)
{
//send the event 'as-is' without checking the success
try
{
myImModality.BeginSetComposing(isComposing, null, null);
}
catch (LyncClientException e)
{
var eventHandler = MessageError;
if (eventHandler != null)
{
eventHandler(e);
}
}
catch (SystemException e)
{
//if (LyncModelExceptionHelper.IsLyncException(e))
//{
// // Handle the exception thrown by the Lync Model API.
// var eventHandler = MessageError;
// if (eventHandler != null)
// {
// eventHandler(e);
// }
//}
//else
//{
// Rethrow the SystemException which did not come from the Lync Model API.
throw;
//}
}
}
}
}
The final result will be a notification to your procedure conversationService_MessageReceived that will contain the message, participant name, and participant uri.
At this point you can do anything you want, I chose to speak the message if not busy;
synth.SpeakAsync(youmessage);
and then display a visual notification right about the task bar clock.
Sorry I can't give you more, but this is part of a commercial product, hopefully it's enough to get you started.
Doug Routledge, C# Lync, SQL, Exchange, UC Developer
Thanks for a great code. Now it works kind of as i want it to.
ReplyDeleteThanks for all the help.. you made my evening here.. :D