Control sound / audio playback with Windows Media Player

Try it now!

When I started looking for ways to include an audio track on my web page, I was extremely frustrated. I am posting this example to spare others the same frustration.

Considerations

Windows Media PlayerI am looking for a solution in an environment where 98% of the users are running Internet Explorer on a Windows box. I will look into supporting the other 2% of users at some time in the future. For now, Windows Media Player makes the most sense.
WMP version 6.4I had originally planned to use a higher version of the Windows Media Player, but I discovered that version 6.4 is the highest version that is supported for some of my users (Windows NT). Even though the Microsoft site says not to use that version, it seems to make the most sense.

See the Windows Media Player 6.4 SDKdocumentation on the MSDN site.

Preloading the soundDepending on the connection speed, the playback quality can be really bad if the audio starts playing before it’s completely downloaded. My solution won’t start the playback until the audio has been downloaded to the user’s brower.
Make them listen!This is being used in a mandatory training module. To be effective, the user has to listen to the entire audio track. This solution won’t enable the “Next” button until the audio track has been completed. It also treats the “mute” button or setting the volume to an inaudible level as though the “Stop” button is pressed.

The solution
Comments
<html>
<head>
  <title>Audio Example</title>
</head>
<body onload="runIt()">
<script>
var monTimer=-1

function runIt()
{
  if (document.audio.ReadyState < 4)
  {
    setTimeout("runIt()", 100)
    return
  }
  startPlayback()
}
Three things ensure that the sound is completely loaded before it plays:
  • The JavaScript function runIt will not be invoked until the page has completed loading.
  • The sound is loaded using <EMBED>, which must be loaded before onload function runs.
  • The WMP object “audio” has its AutoStart parameter set to false.

The runIt function waits until the “audio” object has a ReadyState value of 4 before it starts the playback of the audio track.

function startPlayback()
{
  document.audio.Play()
  monitorPlayback()
}
The startPlayback function invokes the Play method of the WMP object and starts the local monitoring function.
function stopPlayback()
{
  stopMonitor()
  document.audio.Stop()
}
The stopPlayback function invokes the Stop method of the WMP object and stops the local monitoring function.
function monitorPlayback()
{
  monTimer = -1
  if (document.audio.Mute)
  {
    stopPlayback()
    return
  }
  if (document.audio.Volume <= -10000)
  {
    stopPlayback()
    return
  }
  if (document.audio.PlayState != 0)
    monTimer = setTimeout("monitorPlayback('')", 100)
}

function stopMonitor()
{
  if (monTimer != -1) clearTimeout(monTimer)
  monTimer = -1
}
The monitoring function watches two properties of the “audio” object: Mute and Volume. If Mute becomes true or Volume drops to -10,000 or less, the monitor stops the playback.
function audioEnded()
{
  stopMonitor()

  var p = document.nextBtn.src.lastIndexOf("/")
  document.nextBtn.src =
    document.nextBtn.src.substring(0,p+1) + "next.gif"

  setStopPlay("play","audioEnded")
}
When the audio playback has completed,
  • the monitor is stopped,
  • the “Next” button is enabled, and
  • the Stop/Play button is changed to “Play”.
function audioStarted()
{
  document.audio.Mute = 0
  if (document.audio.Volume <= -10000)
    document.audio.Volume = -600
  if (monTimer = -1) monitorPlayback()
  setStopPlay("stop","audioStarted")
}
When audio playback starts,
  • Mute is disabled,
  • the Volume is set to a detectable level (if necessary),
  • the playback monitor is started, and
  • the Stop/Play button is changed to “Stop”.
function audioStopped()
{
  setStopPlay("play","audioStopped")
}
When audio playback is stopped (before the completion of the track), the Stop/Play button is changed to “Play”.
function setStopPlay(v,where)
{
  var p = document.stopPlay.src.lastIndexOf("/")
  document.stopPlay.src =
    document.stopPlay.src.substring(0,p+1) + v + ".gif"
}
This function sets the current state of the Stop/Play button.
function doStopPlay()
{
  var currSrc = document.stopPlay.src
  var curr = currSrc.substring(currSrc.lastIndexOf("/")+1)
  if (curr == "stop.gif")
  {
    stopPlayback()
  }
  else
  {
    startPlayback()
  }
  return 0
}
This function manages clicks on the Stop/Play button.
function isNotDim()
{
  var p = document.nextBtn.src.lastIndexOf("/")
  p++
  return (document.nextBtn.src.substring(p) == "next.gif")
}
This function determines if the “Next” button is dimmed out.
function doNextSlide()
{
  var p = document.nextBtn.src.lastIndexOf("/")
  document.nextBtn.src =
    document.nextBtn.src.substring(0,p+1) + "next-dim.gif"

  alert("Ready for the next slide")
}
</script>
This function is left as an exercise to the reader.

Do whatever is appropriate for your purposes.

<script for=audio event=EndOfStream(result)>
  audioEnded()
</script>
The EndOfStream event is invoked by the Windows Media Player when the audio playback has completed.
<script for=audio
      event=PlayStateChange(oldState,newState)>
  if (newState == 0) audioStopped()
  if (newState == 2) audioStarted()
</script>
The PlayStateChange event is invoked when the state of playing the audio changes. A value of 0 means Stopped and a value of 2 means Playing.

Note: the property SendPlayStateChangeEvents must be true for this event to fire.

<center>
<table>
<tr><td>
I use a table to layout the screen.

The left column contains the control buttons.

  <a onClick="return doStopPlay()"><img name=stopPlay
    src="/examples/stop.gif" border=0></a><p>
The Stop/Play button has one of two faces (“Stop” or “Play”). The face is changed automatically as the playback state of the audio clip changes.
  <a href="javascript:doNextSlide()"
      onClick="return isNotDim()">
    <img name=nextBtn src="/examples/next-dim.gif"
      border=0></a>
The “Next” is dimmed out until the audio clip has played to its completion. As long as the button is dim, it will not function.
</td><td>
  <center>
  <img name=slide src="/examples/slide01.gif"><p>
The right column contains the graphical content and the control for the Windows Media Player.
  <object ID="audio" WIDTH=300 HEIGHT=26
      CLASSID="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95">
   <param name="FileName"  value="/examples/slide01.wav">
   <param name="AutoStart"                 value="false">
   <param name="SendPlayStateChangeEvents" value="true">
   <param name="ShowAudioControls"         value="true">
   <param name="ShowTracker"               value="false">
   <param name="AutoSize"                  value="true">
  </object>
  </center>
</td></tr>
</table>
</center>
This embeds the ActiveX object for the Windows Media Player version 6.4. Note that the object is named “audio”, which is referenced extensively in the JavaScript. I set the width and height to reasonable default values and then included the AutoSize parameter to resize it if necessary. The audio controls are shown, but the tracker is not; this prevents the user from sliding the playback bar to the right to skip over the content.
<EMBED NAME="loadsound"
  SRC="/examples/slide01.wav"
  LOOP=FALSE AUTOSTART=FALSE HIDDEN=TRUE MASTERSOUND>
</body>
</html>
This object is used as part of the “load before playing“ processing. It also provides a convenient object to preload the audio track for the next slide.


The code on this page is Copyright 2003 Tony Lewis <tlewis@exelana.com>.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.