Click here to Skip to main content
15,886,797 members
Articles / Programming Languages / Javascript
Article

RESTful Programming With Your Voyager Pro UC

7 Jan 2013CPOL7 min read 19.1K   2  
RESTful Programming With Your Voyager Pro UC.

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.

 

I've recently been handed a Voyager Pro UC headset and was told to "make something cool.". A couple suggestions were given on where to start and I was then let loose to do what I would with this new and exciting toy.

I thought the headset's ability to detect when it's being worn or not was really interesting. I wanted to jump right in to tinkering with the SDK and detect the current worn state of the device as my starting point. This resulted, after several minutes, in a C# plugin that created a pop-up window when the headset was put on my ear or taken off.

Then, on the Plantronics developer site, something caught my eye; there were other languages supported for the SDK other than C#. This is exciting! I had to investigate.

The main thing that had jumped out at me was the exposure of the Spokes service through JavaScript and the REST protocol. This is some powerful stuff! Have you ever thought your headset could control a website? Me neither. Not until now; and this blog post is going to show you how to make it happen.

First thing's first - you're going to need the proper tools to work with.

Configuration and Setup

For this article, we will be developing in JavaScript. The following are required to follow along with this article:

  • The Spokes SDK from Plantronics (this is version 2.6. Feel free to use a newer version if one's available)
  • A text editor of some sort. Notepad works. I use Notepad++ for the syntax highlighting, custom color schemes, and its FTP plugin which is handy for the next requirement....
  • An HTTP server of some kind. REST's core lies in the HTTP protocol.* You can use the Apache HTTP server, whip up an HTTP server with node.js, etc. I pay a hosting service to run a web server for me but ran an Apache server from home prior to that.

*This is assuming you follow this post which focuses on getting Spokes to play nicely with web sites. There could be instances where you're using REST within a stand-alone application or integrating with something that isn't necessarily a web site.

The first thing you'll need to do is to run the Spokes SDK installer. The default installation folder is "C:/Program Files (x86)/Plantronics/Plantronics SDK". Nothing you write will run without the runtime found in the folder and life will be more difficult without the spokes.js file found in the installation's Samples/RestJsClient folder.

Coding

Preliminary Work

The way we're going to get our JavaScript application to work with a website of our choosing is going to be through JavaScript injection. To execute arbitrary JavaScript on any website you could normally write a script in the URL bar of a web browser such as "javascript:( function(){ alert("Hello Plantronics"); })();", as you would if visiting somewhere, such as www.google.com. What you'd see is a pop up window with our message instead of a new web page.

Unfortunately those URLs can only be up to 2000 characters long. This isn't nearly enough space for a larger JavaScript program so we have to create a little stub script which will slap the main application from our HTTP server into the site we want to work with (see why it's required now?).

This little script fits nicely in the limited space of a URL. This is what people will bookmark (and run) when visiting a site to be worked with (in my case, http://www.grooveshark.com).

javascript:
(
     function()
     {
           //create a <script></script> DOM element
          our_script = document.createElement('script');
          our_script.type = 'text/javascript';
          //Replace the url to the location of your main application file

          our_script.src = "http://www.guineacode.com/Plantronics/test.js"; 
           //Insert the <script> element we made between the <head></head> elements
          document.getElementsByTagName('head')[0].appendChild(our_script);
     }
)();

You don't have a main JavaScript file in the location being specified for our_script.src yet. Don't sweat it. We're getting there. Also note that the above script, with comments and whitespace comes out to 544 characters. Already hit 1/4 of the limit for a URL.

Main Application

It's time to write the meat of our program. To get started, make a new JavaScript file. Call it what you will (I'm naming mine test.js). All of the code will be wrapped in one anonymous function to help with variable scope.

Step the First - Building the Program's Skeleton

Let's start the main application file by building the skeleton of the program-to-be from which we can expand upon later.

(function()
{
     var spokes = null; //spokes session manager (class defined in spokes.js)
     var plugin_registered = false;
     var plugin_name = "SoundCake";
     //------------------------------------------------
     // connectToSpokes - attempt to create a new Spokes session manager, register this app,
     //      and get a valid device to work with. Begin polling for events on success.
     //------------------------------------------------

     var connectToSpokes = function()
     {
     };
     //------------------------------------------------
     // controllerInterface - callback function to that registers this app on successful contact with a valid device.
     //------------------------------------------------
     var controlInterface = function(session)
     {
     };

     //------------------------------------------------
     // registerPlugin - where the actual dirty work is done for app registration.
     //------------------------------------------------
     var registerPlugin = function()
     {
     };
     //------------------------------------------------
     // pollDeviceEvents - regularly ask the Spokes service for new, if any, events to work with. 
     //      This is the main program loop where all the program-specific work will be done.

     //------------------------------------------------
     var pollDeviceEvents = function()
     {
     };
}).call(this);

Step the Second - Making Contact

Now that we have a very bare-bones foundation to work off of, it's time to fill out the programs and make our functions function! We'll need to make a new session manager, get a hold of a device, and register this program with the Spokes service to begin polling for events. First, let's establish a new session and try to make contact with a device.

(function()
{
     var spokes = null; //spokes session manager (class defined in spokes.js)

     var plugin_registered = false;
     var plugin_name = "SoundCake";
     //------------------------------------------------
     // connectToSpokes - attempt to create a new Spokes session manager, register this app,
     //      and get a valid device to work with. Begin polling for events on success.
     //------------------------------------------------
     var connectToSpokes = function()
     {

          //attempt to make a new Spokes object with localhost:32001/Spokes as the base url path for REST calls
          spokes = new Spokes("http://localhost:32001/Spokes");
          spokes.Device.deviceList( function(result)
          {
               //on success...
               if(!result.isError)
               {
                    //on valid device found...
                    if(result.Result[0] !== null)

                    {
                         //attempt to connect to the valid device and start polling for events from it.
                         spokes.Device.attach(result.Result[0].Uid, controlInterface);
                         pollDeviceEvents();
                    }
                    else
                    {
                         alert("Error: Device was null on connecting to Spokes. Is there a Plantronics device connected?");
                    }

               }
               else
               {
                    alert("Error connecting to Spokes.");
               }
          });
     };
}).call(this);

Step the Third - Registration

Now that we have the ability to start a new session with Spokes and check to see if a valid device exists, we need to be able to register our app with Spokes

//------------------------------------------------
// controllerInterface - callback function to that registers this app on successful contact with a valid device.
//------------------------------------------------
var controlInterface = function(session)
{
     //if an error popped up in our session or we failed to connect with a device...
     if(session.isError || !spokes.Device.isAttached)
     {
          alert("Session Registration Error");

     }
     else
     {
          registerPlugin();
     }
};
//------------------------------------------------
// registerPlugin - where the actual dirty work is done for app registration.
//------------------------------------------------

var registerPlugin = function()
{
     //only register if we haven't done so already...
     if(!plugin_registered)
     {
          spokes.Plugin.register(plugin_name, function(result)
          {
               if(!result.isError)
               {

                    //successfully registered the plugin. Set status of plugin to active.
                    spokes.Plugin.isActive(plugin_name, true, function(result)
                    {
                         if(!result.isError)
                         {
                              plugin_registered = true;
                         }
                         else
                         {

                              alert("Error checking if plugin is active: " + result.Err.Description);
                         }
                    });
               }
               else
               {
                    alert("Error registering plugin: " + result.Err.Description);
               }
          });

     }
};

Step the Fourth - Event Polling

So we've made a new session and have made our app known to Spokes. Great. But, here's where the fun, and meat of the program, lies. It's time to start asking Spokes if there's any new events going on with our device and react based on the answer. Let's make some alert windows pop up when we wear or take off our Voyager Pro headset. Feel free to have something else happen on these events.

//------------------------------------------------
// pollDeviceEvents - regularly ask the Spokes service for new, if any, events to work with.
//      This is the main program loop where all the program-specific work will be done.
//------------------------------------------------

var pollDeviceEvents = function()
{
     setInterval(function()
     {
          if(spokes === null || !spokes.Device.isAttached)
          {
               return;
          }
          //ask for events, if any

          spokes.Device.events(function(result)
          {
               var i;
               if(result.isError)
               {
                    alert("Error polling for events: " + result.Err.Description);
               }
               else
               {

                    //we have one or more events!
                    if(result.Result.length > 0)
                    {
                         i = 0;
                         //iterate over the events while we haven't hit the end of the array of events returned
                         while(i < result.Result.length)
                         {

                              //the meat of our logic. Do unique actions based on event received.
                              //See SessionCallState() in Spokes.js for a detailed list of events
                              switch(result.Result[i].Event_Name)
                              {
                                   case "Don":
                                        alert("Your Voyager Pro is now on your head!");
                                        break;
                                   case "Doff":
                                        alert("You took off your Voyager Pro!");

                                        break;
                                   default:
                                        alert("You just did something crazy with your Voyager Pro.");
                                        break;
                            }
                              i++; //increment counter so we're not stuck in an infinite loop
                         }
                    }
               }

          });
     }, 2000); //repeat this loop every 2 seconds.
};

Step the Fifth - Execution and Ensuring Library Inclusion

One can't simply assume a site already has jQuery included on their page for you to use so you'll have to check for its existence. If jQuery is undefined, we'll have to slap in the latest jQuery script before anything else is done and then we can include spokes.js. Wait on spokes.js to be loaded up before doing anything else in the program otherwise you might accidentally call an undefined method as the code below executes asynchronously.

var main = function()
  {
  var spoke_js = document.createElement('script');
  spoke_js.type = 'text/javascript';

  spoke_js.src = 'http://www.guineacode.com/Plantronics/spokes.js'; 
  document.getElementsByTagName("head")[0].appendChild(spoke_js);
  //make sure spokes.js is up and ready to go before doing anything
  spoke_js.onload = spoke_js.onreadystatechange = function()
  {
          //the site is ready. We can begin our program.
          connectToSpokes();
  }
  };

     // Check to see if jQuery is loaded. Spokes needs it to function.
  if(typeof jQuery === 'undefined')
  {
       jquery_js = document.createElement('script');
       jquery_js.type = 'text/javascript';
       jquery_js.src = 'http://code.jquery.com/jquery-latest.js'; 
       document.getElementsByTagName("head")[0].appendChild(jquery_js);
       //make sure jQuery is up and ready to go before including spokes.js
       jquery_js.onload = jquery_js.onreadystatechange = main;

  }
  else
  {
       main();
  }

}).call(this);

The asynchronous execution of the code got me when I was first working on my program and was a bit frustrating. I resorted to just pasting the contents of spokes.js into the main code file instead of including it from an external file just so I could move on and hack out a prototype for my idea. I feel that the above is a much cleaner solution now after taking some time to come up with a fix.

Bringing It All Together

It's time to test out our program! Run PlantronicsURE.exe from the installation folder of your Spokes SDK (default is "C:/program files (x86)/Plantronics/Plantronics SDK"). Assuming you've uploaded both the main JavaScript file we wrote here and the spokes.js file to your host, you should be able to make a new bookmark in your browser and paste the stub code (first snippet) in the url (while ensuring the our_script.src property points to your main JavaScript file being hosted). 

Visit a random page of your choice, such as Facebook. Click on the bookmark you just made and either put your headset on or take it off. You should see a pop-up window indicating the event.

Congratulations, you're now able to make sites aware of your Voyager Pro!

Conclusion

With the above code you should have a basic framework to build off of now to create more complex browser-based programs. This code is heavily based off the REST API JavaScript Example which I'd recommend digging through.

I mention that you should be hosting spokes.js and emphasize pointing to your host as I can't guarantee the files I'm hosting will always be online. If my site has issues, so will your app if you're using the spokes.js file on my server.

Source Code:

You can find a fully working version of the main application code above at http://www.guineacode.com/Plantronics/test.js

An example of how this same code (with spokes.js pasted into the file instead of being included nicely) can be seen with the Grooveshark Spokes plugin, SoundCake, which I wrote about a week ago.

If you have any questions or suggestions leave a comment. Good luck with your programming endeavors!

This article was written by Brandon Haston. Brandon is a software developer currently making cool stuff happen with Plantronics since July 2012. Brandon first joined the software industry in 2001 while working as a freelance PHP instructor. He has worked primarily in the videogame industry as a programmer for IsoTX and Chronic Logic and then as a co-founder of an independent game studio called Ethereal Muse Studios. Brandon currently lives in Santa Cruz, CA.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Today’s smart devices and applications have untapped potential in the realm of context-aware computing. Plantronics is making it possible for its audio devices to deliver contextual information to a range of applications through Plantronics headsets. The Plantronics Spokes SDK allows developers to create a range of business applications that will have the power to change the way we communicate and collaborate.

Please check out our DevZone for more info on the Spokes SDK:
http://developer.plantronics.com/community/devzone

Comments and Discussions

 
-- There are no messages in this forum --