Using WMP and Quicktime with Silverlight

August 15, 2007 at 7:47 am | Posted in Silverlight | 9 Comments

 

Note: There have been some breaking changes in Silverlight since this post was published.  For the latest info see this link.

Silverlight has a MediaElement control  which can be used for most cross-platform media display tasks.  I was disappointed that my application can not use it because it currently does not support playback at a variable rate.

My application requires a media player that can playback speech mp3 files at rates varying from 0.5 to 1.0x realtime.  Windows Media Player (WMP) is especially good at this in that the playback at reduced speed does not modify the pitch of the speech.

My solution to this problem is to instantiate a WMP or Quicktime player in the page depending on the platform and control the player from Silverlight C# code through a Javascript layer.

First, the player is installed in the body of the html page like this:

<!--Player goes here-->
     <div id="PlayerDiv"></div>    

 <script type="text/javascript">  

 //Installs the player
 var wmp;
 var qtp;
 document.getElementById('PlayerDiv').innerHTML = playerCreate('news clip.mp3');
 if(useWmp){
 wmp = document.getElementById('wmPlayer');
 }else{
 qtp = document.qtPlayer;
 }    

 </script>

The playerCreate function is a bit of Javascript that determines the browser capabilities and installs either a WMP or Quicktime player.  If IE is detected or Firefox is detected with the WMP component, then WMP is installed else use Quicktime.  (WMP is preferred over Quicktime for this application because while Quicktime has a rate control, the pitch is not preserved for mp3 playback.)  Here is the playerCreate Javascript:

var useWmp;
    function playerCreate(url) {
    //Find browser
var userAgent = navigator.userAgent.toLowerCase();
var is_opera  = (userAgent.indexOf('opera') != -1);
var is_saf    = ((userAgent.indexOf('applewebkit') != -1) || (navigator.vendor == "Apple Computer, Inc."));
var is_webtv  = (userAgent.indexOf('webtv') != -1);
var is_ie     = ((userAgent.indexOf('msie') != -1) && (!is_opera) && (!is_saf) && (!is_webtv));
var is_ie4    = ((is_ie) && (userAgent.indexOf("msie 4.") != -1));
var is_moz    = ((navigator.product == 'Gecko') && (!is_saf));
var is_kon    = (userAgent.indexOf('konqueror') != -1);
var is_ns     = ((userAgent.indexOf('compatible') == -1) && (userAgent.indexOf('mozilla') != -1) && (!is_opera) && (!is_webtv) && (!is_saf));
var is_ns4    = ((is_ns) && (parseInt(navigator.appVersion) == 4));   

    var str = "";
    if (is_ie) {
    // create the WMP for IE 
    useWmp = true;
    str = '<object id="wmPlayer" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" width="0" height="0">';
// str += '<param name="URL" value="'+url+'" />'; 
    str += '<param name="uiMode" value="none">';
    str += '<param name="autoStart" value="false">';
    str += '</object>';
    return str;  

    }else if(is_moz && navigator.plugins["Microsoft® Windows Media Player Firefox Plugin"]){
    // create WMP for FF. 
    useWmp = true;
    str = '<object id="wmPlayer" type="application/x-ms-wmp" data="'+url+'" width="0" height="0">';
// str += '<param name="URL" value="'+url+'" />'; 
    str += '<param name="uiMode" value="none">';
    str += '<param name="autoStart" value="false">';
    str += '</object>';
    return str;      

    }else{
    //try to create the qtp as last resort
    useWmp = false;
    str ='<object id="qtPlayer" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="0" height="0" >';
// str += '<param name="src" value="'+url+'">';
    str += '<param name="autoplay" value="false">';
    str += 'http://qtStartUp.mp3';
    str += ' </embed> ';
    str += '</object> ';
    return str;  

}
}

A set of Javascript functions were defined in order to create a common API for the Silverlight C# code to use.

function playerPlay(){
if(useWmp){
wmp.controls.play();
}else{
qtp.Play();
}
}  

function playerStop(){
if(useWmp){
wmp.controls.stop();
}else{
qtp.Stop();
qtp.Rewind();
}
}   

function playerPause(){
if(useWmp){
wmp.controls.pause();
}else{
qtp.Stop();
}
}   

function playerUrl(url){  

if(useWmp){  

wmp.URL = url;
}else{
qtp.SetURL(url);
qtp.Stop();
}
}   

function playerGetPosition(){
if(useWmp){
return wmp.controls.currentPosition;
}else{
return qtp.GetTime()/600;
}
}   

function playerSetPosition(t){
if(useWmp){
wmp.controls.currentPosition = t;
}else{
qtp.SetTime(t*600); //int
}
}   

function playerSetVolume(v){
if(useWmp){
wmp.settings.volume = v;
}else{
qtp.SetVolume(v); //int 0-100
}
}   

function playerSetRate(r){
if(useWmp){
wmp.settings.rate = r;
}else{
qtp.SetRate(r); //flost 0.5-1.0
}
}

These functions are called by a single event handler that manages calls from the Silverlight C# code using the techniques for C# to Javascript communications described in the QuickStart guide.

//Event handler for Silverlight control
function agEventHandler(sender, args){
switch (args.Name){
case 'stop':
playerStop();
break;
case 'play':
playerPlay();
break;
case 'pause':
playerPause();
break;
case 'url':
playerUrl(args.Sdata);
break;
case 'position':
playerSetPosition(args.Data);
break;
case 'volume':
playerSetVolume(args.Data);
break;
case 'rate':
playerSetRate(args.Data);
break;  

default:
}

The event handler arguments are defined on the C# side as follows:

//This class defines the arguments for the control's events
[Scriptable]
public class CustomEventArgs : EventArgs
{
    private double data;
    private string name;
    private string sdata;  

    public CustomEventArgs(string iname, double idata, string isdata)
    {
        data = idata;
        name = iname;
        sdata = isdata;
    }  

    [Scriptable]
    public string Name
    {
        get { return name; }
        set { name = value; }
    }  

    [Scriptable]
    public double Data
    {
        get { return data; }
        set { data = value; }
    }  

    [Scriptable]
    public string Sdata
    {
        get { return sdata; }
        set { sdata = value; }
    }
}//End of class

This class of custom event arguments allows the passing of a string name which specifies the media player event to control as well as a double and string parameter for data.

The event method is defined in the C# code like this:

//This defines the event from the control
//This is an example of how to fire an event from the control to Javascript
//AgEvents(this, new CustomEventArgs("hello", 25, "something"));
[Scriptable]
public event EventHandler<CustomEventArgs> AgEvents;

Finally, here is an example of C# code controlling the media player:

void play()
{
    if (playerState != (int)playerStates.paused)
    {
        AgEvents(this, new CustomEventArgs("position", t1, null));
    }  

    AgEvents(this, new CustomEventArgs("play", 0, null));

 

Hopefully, future releases of Silverlight will have a MediaElement with a rate control so that my application can be greatly simplified.

About these ads

9 Comments »

RSS feed for comments on this post. TrackBack URI

  1. I can’t create this example… Is it possible to have to source code please ?

    A quick answer will be greatly appreciated

  2. Most of the source is in the code blocks here. I will have to do some work to extract a stand alone demo but I will try to do that today. In the meantime, can you describe in more detail the problem you are having?

  3. Links were added in the blog for source code and demo.

  4. Since the release of the 2.0 Beta, the application posted above is broken. I’ll see if I can fix it when I have time.

  5. have you fixed it??

  6. i need this example please…..

    • There have been many breaking changes in Silverlight since I wrote this program in 2007. Today, I started to port the code to Silverlight 4. Hopefully, I can have something to show in a couple of days.

  7. [...] In 2007, I was working on a Silverlight application in which I wanted to change the rate of speech playback without affecting the pitch.  At that time, the media element available to Silverlight did not have a rate control while Windows Media Player works wonderfully for mp3 files.  I found that I could actually use WMP in a Silverlight application by embedding the player in the HTML file that hosted the Silverlight control and then controlling the player by using a bridge between managed C# and JavaScript.  The technique was documented in this blog post. [...]

  8. I have now updated the code for Silverlight 4. See the post here:

    http://dotupdate.wordpress.com/2011/11/06/using-wmp-and-quicktime-in-silverlight-revisited/


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com. | The Pool Theme.
Entries and comments feeds.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: