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

Web Based Winamp Controller

0.00/5 (No votes)
18 Dec 2002 1  
Web based WinAmp server

WinAmp controller

Introduction

This article shows a method of controlling WinAmp via a web browser.

Background

Sometime ago I was working at a place where all the developers worked in the same area away from other people. It didn't take long before our main development server began to fill up with quite a collection of MP3's. Once this happened the server then got connected to the phone system and to a decent set of speakers. The only thing left to do was remotely control the playlist. That's where this article comes in.

Using the code

WinAmp can be controlled using the Windows Messaging system. First you need to get a handle to WinAmp, this is done using the FindWindow API. It turns out that all of the WomAmp versions have the same class name: "Winamp v1.x".

Messages are sent in the form of:

int returnVal = SendMessage(hwndWinamp, WM_USER ,data, id);

In order for a Windows service to obtain the handle of the running WinAmp it needs to be able to interact with the desktop. This is done by editing the service properties and checking the 'Allow service to interact with desktop' button.

The web application communicates with the windows service via remoting. The class winampcontroller is remoted between the web application and the windows service. In fact you could do without the Windows service if you wanted to allow IIS to interact with the desktop, but we didn't want to modify the properties of IIS to do this because of security fears.

Since the application is written using the .NET framework, interop is used to call the native Windows API, the following code snippet shows how to send simple commands to WinAmp.

public class winampcontroller : MarshalByRefObject
{
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern IntPtr FindWindow(
        [MarshalAs(UnmanagedType.LPTStr)] string lpClassName,
        [MarshalAs(UnmanagedType.LPTStr)] string lpWindowName);
    
    [StructLayout(LayoutKind.Sequential)]
    struct COPYDATASTRUCT
    {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.LPStr)] public string lpData;
    }
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam,
        [In()] ref COPYDATASTRUCT lParam);
    
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    static extern int SendMessageA(IntPtr hwnd, int wMsg, int wParam,
        int lParam);
    
    //see table below for descriptions

    const int WM_COMMAND = 0x111;
    const int WM_USER = 1024;//0x4A;

    const int WA_PLAY = 40045;
    const int WA_STOP = 40047;
    const int WA_PAUSE = 40046;
    const int WA_PREVTRACK = 40044;
    const int WA_NEXTTRACK = 40048;
    const int WA_GETSTATUS = 104;
    const int WA_PLAYLISTLEN = 124;
    const int WA_SETVOLUME = 122;
    const int WA_SETPLAYLISTPOS = 121;
    const int WA_WRITEPLAYLIST  = 120;
    const int WA_VOLUMEUP = 40058;                    
    const int WA_VOLUMEDOWN = 40059;
    const int WA_CLEARPLAYLIST = 101;
    const int WA_NOTHING = 0;
    const int WA_RESTART = 135;
    const int WA_REFRESHPLCACHE = 247;
        
    public const int STOPPED = 0;
    public const int PLAYING = 1;
    public const int PAUSED = 3;
    protected string m_windowName;
    public winampcontroller()
    {
        try
        {
            m_windowName = ConfigurationSettings.AppSettings["WindowClassName"];
        }
        catch(NullReferenceException)
        {
            m_windowName = "Winamp v1.x";
        }
    }
    public void Stop()
    {
        IntPtr hwnd = FindWindow(m_windowName, null);            
        SendMessageA(hwnd, WM_COMMAND, WA_STOP, WA_NOTHING);
    }
    public void Play()  
    {            
        IntPtr hwnd = FindWindow(m_windowName, null);            
        SendMessageA(hwnd, WM_COMMAND, WA_PLAY, WA_NOTHING);
    }
    public void Pause()
    {
        IntPtr hwnd = FindWindow(m_windowName, null);            
        SendMessageA(hwnd, WM_COMMAND, WA_PAUSE, WA_NOTHING);
    }
}

WinAmp has pre-defined responses to different values of data, some of these are:

0 Retrieves the version of Winamp running. Version will be 0x20yx for 2.yx.
100 Starts playback.
101 Clears Winamp's playlist.
102 Plays selected track.
104 Returns the status of playback. If 'returnVal' is 1, Winamp is playing. If 'returnVal' is 3, Winamp is paused. Otherwise, playback is stopped.
121 Sets the playlist position to the position specified in tracks in 'data'.
122 Sets the volume to 'data', which can be between 0 (silent) and 255 (maximum).
124 Returns length of the current playlist, in tracks.
125 Returns the position in the current playlist, in tracks (requires Winamp 2.05+).
129 Adds the specified file
135 Restarts Winamp

The windows service consists of a few lines of code outside of the code generated by Visual Studio:

protected override void OnStart(string[] args)
{
    int tcpChannelVal = 0;
    try
    {
        tcpChannelVal = int.Parse(ConfigurationSettings.AppSettings["ChannelNum"]);
    }
    catch(Exception){
        tcpChannelVal = 1096;
    }

    m_channel = new TcpChannel(tcpChannelVal);
    ChannelServices.RegisterChannel(m_channel);
    RemotingConfiguration.ApplicationName = "WinampController";
    RemotingConfiguration.RegisterWellKnownServiceType(typeof(winampcontroller),
                               "WinampController",WellKnownObjectMode.Singleton);

}

protected override void OnStop()
{
    ChannelServices.UnregisterChannel(m_channel);
}

To install the windows service, you need to use the InstallUtil program that comes with the .NET Framework SDK or Visual Studio .NET

The web application's web.config files need to be changed to point to a directory that contains MP3's

The whole application was put together in a few hours, us being programmers and not designers means that the front end is not very pretty, but since it's only HTML it's easy to change. In terms of features, this example controls a playlist of files in a directory. More functionality and better error handling was destined for this project, but as usual not enough time has meant that it will have to stay this way.

If anyone wants to create a better front end or add more features you are more than welcome too, I would of course update the article with your name and contributions.

Points of Interest

When this code was originally written WinAmp was at version 2. Currently WinAmp is at version 3, which does not provide the same methods for manipulating the player; however, I did find this plugin which replicates the desired functions:

Winamp 2.x Plugin Manager for Winamp 3

History

10/12/2002 - Article Created

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