Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How To Get Your Voyager Pro UC to Tweet

7 Jan 2013 1  
How To Get Your Voyager Pro UC to Tweet.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

 

When I first started at Plantronics, my boss handed me a Voyager Pro UC headset and a link to download the SDK and said "Build me something". The result of that thought experiment is this blog post and some sample code for you to tinker around with.

By the end of this posting, you should have your very own application that allows you to access the contextual information within a Plantronics headset and tweet to the world about.

Let's get started ...

Bootstrapping Your Development Environment

Here are some things I assume you are developing with:

  • Microsoft Visual Studio 2010
  • C#

Here is the shopping list you will need:

Install the Spokes SDK

The default install location for the SDK is C:\Program Files\Plantronics\PlantronicsSDK. The Plantronics Spokes runtime and supporting developer libraries are located in this folder.

Launch Microsoft Visual Studio

Create a .NET 3.5 C# Class Library project - In this example I created a project called TweetMe

After the project has been created rename the default Class1.cs to TweetMe.cs

Adding The Plantronics and TweetSharp Dependencies

Getting TweetSharp

NuGet can be found under the Project menu in Visual Studio. To add TweetSharp to your project, click on the Project menu and select the "Manage NuGet Packages" option. Once the NuGet dialog box shows up search for the TweetSharp libraries and add them to your project.

Add the Plantronics SDK References

There are two Plantronics assemblies we will need for this application the Plantronics.Device.Common.dll and the Plantronics.UC.Common.dll. These assemblies are located in the install directory C:\Program Files\Plantronics\PlantronicsSDK. To add the references, you use the conventional reference adding mechanism in Visual Studio.

Once you have the TweetSharp and Plantronics assemblies referenced, your project's reference list should look like this:

Coding Plantronics Plug-in

With your development environment up and running, you are now ready to start coding.

What we are going create here is a plug-in for the Plantronics Spokes runtime engine. For more information on Spokes please see Spokes SDK 2.7 Documentation

Step 1: Creating a Basic IPlugin Implementation.

The IPlugin interface has three methods that must be implemented Name, Init and Exit, below is a skeleton of what an empty plug-in implementation looks like.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plantronics.UC.Common;
using Plantronics.Device.Common;
namespace TweetMe
{
    public class TweetMe : IPlugin
    {
        //Begin IPlugin Interface Implementations
        //returns the name of the plugin
        public string Name
        {
        }
        //Called by the Plantronics Runtime to initialize the plugin

        public bool Init()
        {
            return true;
        }
        //Called by the Plantronics Runtime when exiting
        public void Exit()
        {
        }
        //End IPlugin Interface Implementations

    }
}

Step 2. Add Plantronics Objects

Start to fill in our plug-in skeleton with the Plantronics objects we will be using to gain access to the headset events.

....
public class TweetMe : IPlugin
    {
     //Plantronics session classes
     ISessionManager sessionManager = null;
     ISession session = null;
     //Plantronics device
     IDevice myVoyagerPro = null;

     IDeviceEvents myVoyagerProEvents = null;
     IHostCommandExt command = null;
        //Begin IPlugin Interface Implementations
        //returns the name of the plugin
        public string Name
        {
        get { return "Tweet Me Plugin"; }
        }
        //Called by the Plantronics Runtime to initialize the plugin

        public bool Init()
        {
          //get the session manager instance
            sessionManager = SessionManager.Instance;
            if (sessionManager == null)
            {
                //error case return false;
                return false;
            }

            return true;
        }
        //Called by the Plantronics Runtime when exiting
        public void Exit()
        {...

Step 3: Add an Event Handler to Receive SessionManager Object Events

The SessionManager object knows when Plantronics headsets are connecting, connected, disconnecting or disconnected. This event handler will use the device added and removed events from the SessionManager to provide a some robustness to our code, allowing for plugin to adapt as headsets connect, disconnect or reconnect.

  //Called by the Plantronics Runtime to initialize the plugin

        public bool Init()
        {
            //get the session manager instance
            sessionManager = SessionManager.Instance;
            if (sessionManager == null)
            {
                //error case return false;
                return false;
            }

            //regiester with the session manager to get notification when a Plantronics connects/disconnects
            sessionManager.DeviceStateChanged +=new DeviceStateEventHandler(MyVoyagerProOnOffHandler);
            return true;
        }
...
   //End IPlugin Interface Implementations
        //Begin event handler code
        public void MyVoyagerProOnOffHandler(object sender, DeviceStateEventArgs deviceStateEventArgs)
        {
            switch (deviceStateEventArgs.State)

            {
                case DeviceState.Added:
                    //do something with the added device
                    break;
                case DeviceState.Removed:
                   //do some cleanup
                    break;
                default:
                    break;

            }
        }

Step 4: Get the Connected Plantronics Headset

The code added here will try to get the active device (headset) from the Session object and activate the plugin with the SessionManager. If a device is found then we will register for headset event notification.

Also this code snippet shows the SessionManager device state change event handler implementation. The implementation is pretty simple here, when a headset connects to the host, we want to register for events from the headset, when a headset disconnects from the host, we want to clean up any previous device event registrations.

  //Called by the Plantronics Runtime to initialize the plugin
        public bool Init()
        {

            //get the session manager instance
            sessionManager = SessionManager.Instance;
            if (sessionManager == null)
            {
                //error case return false;
                return false;
            }
            //regiester with the session manager to get notification when a Plantronics connects/disconnects
            sessionManager.DeviceStateChanged +=new DeviceStateEventHandler(MyVoyagerProOnOffHandler);

            //register the plugin with session from the session manager
            session = sessionManager.Register(Name);
            if (session == null)
            {
                //error case
                return false;
            }
            //tell the session manager we are active
            sessionManager.IsActive(Name, true);

            //get my connected Plantronics headset
            GetMyVoyagerPro();
            return true;
        }
...
       //Begin my plantronics voyager pro methods
        //sets the active plantronics device
        private void GetMyVoyagerPro()
        {
           if (myVoyagerPro != null)

            {
                UnregisterMyVoyagerPro();
            }
            myVoyagerPro = session.ActiveDevice;
            RegisterMyVoyagerProForEvents();
        }
        private void RegisterMyVoyagerProForEvents()
        {
        }

        private void UnregisterMyVoyagerPro()
        {
       }
        //End my voyager pro methods
        //Begin event handler code
        public void MyVoyagerProOnOffHandler(object sender, DeviceStateEventArgs deviceStateEventArgs)
        {
  switch (deviceStateEventArgs.State)
            {

                case DeviceState.Added:
                    GetMyVoyagerPro();
                    break;
                case DeviceState.Removed:
                    UnregisterMyVoyagerPro();
                    break;
                default:
                    break;
            }

         }

Step 5: Implement the Plantronics Headset Event Registration Logic

To receive the sensor events from the Device object one needs to register a HeadsetStateChanged event handler with the active device. The code below shows how to do this as well as un-register the event handler once we are done with the device

As a note, proximity detection is disabled by default on the device, whenever we register to receive device events, proximity needs to be enabled (if we want the event). The code snippet contains a method, EnableProximity, which turns on the feature.

  //sets the active plantronics device
        private void GetMyVoyagerPro()
        {
           if (myVoyagerPro != null)
            {

                UnregisterMyVoyagerPro();
            }
            myVoyagerPro = session.ActiveDevice;
            RegisterMyVoyagerProForEvents();
        }
        private void RegisterMyVoyagerProForEvents()
        {
          if (myVoyagerPro == null)
            {

                return;.
            }
            //turn on proximity events
            EnableProximity();
            myVoyagerProEvents = myVoyagerPro.DeviceEvents;
           (myVoyagerProEvents as IDeviceEventsExt).HeadsetStateChanged += new HeadsetStateEventHandler(MyVoyagerProStateChangeListener);
        }
        private void EnableProximity()
        {

            if (myVoyagerPro != null)
            {
                command = myVoyagerPro.HostCommand as IHostCommandExt;
                if (command == null)
                {
                    return;
                }
                //turn on proximity
                command.EnableProximity(true);

  
                //tell myVoyagerPro to send the proximity events
                command.GetProximity();
            }
        }
        private void UnregisterMyVoyagerPro()
        {
            (myVoyagerProEvents as IDeviceEventsExt).HeadsetStateChanged -= MyVoyagerProStateChangeListener;
            myVoyagerPro = null;

        }
        //End my plantronics methods
        //Begin event handler code
        //handle events from the headset
        public void MyVoyagerProStateChangeListener(object sender, HeadsetStateEventArgs myVoyagerProEventArgs){
        }
        public void MyVoyagerProOnOffHandler(object sender, DeviceStateEventArgs deviceStateEventArgs)
        { ... 

Step 6: Adding Twitter Objects

Now that we have the basic plumbing to get the active Plantronics headset and to register for the headset's events, its time to plug in the TweetSharp objects so we can tweet to the world that you are wearing a sensor enabled headset.

To programmatically access my @myvoyagerpro account I created a Twitter application on Twitter. This application can post tweets on my behalf using the Twitter OAuth APIs. Because Twitter application keys are supposed to be secret, I have omited them from this snippet, to get your own Twitter application access keys create your own application via the Twitter developer site https://dev.twitter.com.

Note: The code snipped also shows the implementation of our plug-in's cleanup code within the Exit method.

...
using TweetSharp;
namespace TweetMe
{
    public class TweetMe : IPlugin
    {
     //Plantronics session classes
     ...
     //twitter integration stuff
     String twitterConsumerKey = "yourconsumerkey";
     String twitterConsumerSecret = "yourconsumersecret";
     String twitterAccessToken = "youraccesstoken";

     String twitterAccessTokenSecret = "youraccesstokensecret";
     String twitterUserHandle = "@yourtwitterhandle";
     TwitterService twitter = null;
        //Begin IPlugin Interface Implementations
        ...
        //Called by the Plantronics Runtime to initialize the plugin
        public bool Init()
        {
           ...

            //get my connected Plantronics
            GetMyVoyagerPro();
            //initialize twitter
            InitializeTwitter();
           return true;
        }
        //Called by the Plantronics Runtime when exiting
        public void Exit()
        {

           //clean up
           UnregisterMyVoyagerPro();
           sessionManager.UnRegister(session);
           twitter.EndSession();
        }
        //End IPlugin Interface Implementations
        //twitter initialization
        private void InitializeTwitter()
        {

            //initialize twitter
            twitter = new TwitterService(twitterConsumerKey, twitterConsumerSecret);
            twitter.AuthenticateWith(twitterAccessToken, twitterAccessTokenSecret);
        }

Step 7: Turning headset events into Tweets

The implementation of the MyVoyagerProStateChangeListener below is where we turn headset events into tweets. While the Plantronics headset can send many contextual events that can be received and acted upon, this plugin is purposefully simple and only focuses on the following events:

  • HeadsetState.Don - Capacitive sensor event that the user is wearing their headset
  • HeadsetState.Doff - Capacitive sensor event the user has take off their headset
  • HeadsetState.InRange - event that the headset is in range of host system
  • HeadsetState.OutofRange - event that the headset is out of range of the host system
  • Proximity.Near - event that the headset is near the host system
  • Proximity.Far - event that the headset is far from the host system (but still in range)
      //Begin event handler code
        public void MyVoyagerProStateChangeListener(object sender, HeadsetStateEventArgs myVoyagerProEventArgs)
        {
            switch (myVoyagerProEventArgs.State)
            {
                //there are many other change events we can receive - this example just shows capturing wear state
                case HeadsetState.Don:
                    //The user is wearing thier Plantronics
                    twitter.SendTweet("At " + DateTime.Now.ToString("H:mm:ss") + " my Sensors told me that " + twitterUserHandle + " is wearing me!");

                    break;
                case HeadsetState.Doff:
                    //the user is not wearing their Plantronics
                    twitter.SendTweet("At " + DateTime.Now.ToString("H:mm:ss") + " my sensors told me that " + twitterUserHandle + " has taken me off.");
                    break;
                case HeadsetState.InRange:
                    //the user is near their connection point
                    twitter.SendTweet("At " + DateTime.Now.ToString("H:mm:ss") + " my sensors told me that " + twitterUserHandle + " is in the building.");
                  //proximity as it has to be re-enabled when the headset comes into range
enableProximity();
break;

                case HeadsetState.OutofRange:
                    //The user is away from their connection point
                    twitter.SendTweet("At " + DateTime.Now.ToString("H:mm:ss") + " my sensors told me that " + twitterUserHandle + " is out of the building");
                    break;
                default:
                    break;
            }
//check for proximity event state
  switch (myVoyagerProEventArgs.Proximity)
            {

                case Proximity.Far:
                    // device is far
                    twitter.SendTweet("At " + DateTime.Now.ToString("H:mm:ss") + " my sensors told me that " + twitterUserHandle + " is away from their desk.");
                    break;
                case Proximity.Near:
                    twitter.SendTweet("At " + DateTime.Now.ToString("H:mm:ss") + " my sensors told me that " + twitterUserHandle + " is at their desk.");
                    // device is near
                    break;
            }

        }

Step 9: Configuring the plugin to run in the Plantronics runtime environment, Spokes.

The Plantronics Spokes runtime has a pluggable architecture that is configured via an XML file.

The following XML fragment is what we will be adding to the Spokes configuration file.

<!-- XML Fragment for PURE.xml -->
<Plugin Name="TweetMe" ProcessName="" Enabled="true" Active="false">
    <Assembly>TweetMe.dll</Assembly>
    <ClassType/>

    <Type>SoftPhone</Type>
  <FeatureType>0</FeatureType>
</Plugin>

To configure Spokes we will navigate to the Plantronics SDK install directory and edit the PURE.xml file adding the xml fragment detailed above.

After configuring the PURE.xml file, make sure your assemblies are copied over to the Plantronics SDK install directory.

In the case of my application, I added the following assemblies to my SDK folder:

  • Hammock.ClientProfile.dll - Used by TweetSharp
  • Hammock.dll - Used by TweetSharp
  • Newtonsoft.Json.dll - Used by TweetSharp
  • TweetSharp.dll - TweetSharp library
  • TweetMe.dll - Spokes plugin we created

Step 10: Tweet Away

In the Plantronics SDK install directory there is an executable file called PlantronicesURE.exe, this is the Spokes runtime engine service. Please check that there are no instances of this service running before you test your new plugin. Launch PlantronicsURE.exe and you should be ready to tweet. To test if your code works, put on your Plantronics Voyager Pro UC and check your Twitter page.

Step 10b. What if I don't have a headset?

No worries, the Plantronics SDK ships with a comprehensive headset emulator that can be used if you don't have one of our headsets. For more information on the emulator, click here Plantronics Device Emulator Documentation.

The Source Code:

TweetMe.zip

Well there you go... I hope this works for you, if you encounter any problems let me know!

Cheers,

-Cary

This article was written by Cary Bran. Cary works for Plantronics out of his backyard shed located in Seattle, Washington. His job title is Senior Director, Advanced Software and Architecture. What that translates to is he leads the research and development of next generation software and device concepts.

He's been developing solutions in the unified communications and collaboration space since 1998. In recent history, he's served as a software architect, technical strategist and contributor to the IETF and W3C WebRTC standardization efforts. He has a BS in Computer Science and an MBA from the Foster School of Business at the University of Washington.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here