Start/Stop Your Music Player with your Headphones
An application that starts your music app when you plug in the headphones and stops it when you unplug it!
Introduction
I tend to listen to music quite a lot while I work. And, of course, I have to use headphones to keep my colleagues from beating me up. Recently I started using my mobile phone as my music player. Since I have to move around the office now and then, I constantly found myself unplugging and plugging in my headphones. And every time I had to unplug the headphones, I would first have to stop the music player to stop it from blaring out Maiden tracks. And of course, since I had stopped it earlier, I would need to start it again when I returned to my seat! I needed a way of starting the music player when I plugged in the headphones and stopping it when I unplugged it.
And thus was born this application.
Using the Code
Note: This project uses OpenNETCF or Smart Device Framework as it is called now. It’s great! You can get a copy from http://www.opennetcf.com/.
Another note: I'm not an applications developer and am quite new to C#. So my code probably does not look very professional. But the intention here is only to present the idea and not the application itself.
The code itself is pretty simple. It does the following;
- On startup, checks if another instance is running. If yes, the app checks with the user to determine if he/she wants to stop the application.
- Registers a
ChangeEventHandler
for the propertySystemProperty.HeadsetPresent
. - Starts or Stops the music player application based on the change event notification
- Goes to sleep a lot
using System;
using System.Windows.Forms;
using Microsoft.WindowsMobile.Status;
using System.Diagnostics;
using OpenNETCF.ToolHelp;
using System.Threading;
using System.Runtime.InteropServices;
using System.Reflection;
namespace AutoNitro
{
static class Program
{
static SystemState bHPState;
// Music application name and path. Change here if your music application
// is different
const string MUSIC_APP_EXE_NAME = "Nitrogen.exe";
const string MUSIC_APP_PROGRAM_FOLDER = "\\Program Files\\Nitrogen";
public const Int32 NATIVE_ERROR_ALREADY_EXISTS = 183;
// .NetCF does not export CreateMutex. We have to explicitly import it here
[DllImport("coredll.dll", EntryPoint = "CreateMutex", SetLastError = true)]
public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes,
bool InitialOwner,
string MutexName);
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
[MTAThread]
static void Main()
{
// The name of this application
String sThisApp = Assembly.GetExecutingAssembly().GetName().Name + ".exe";
// Check if an instance is already running by trying to create a mutex
// with a fixed name. If mutex already exists, we assume that this is
// because another instance is running!
IntPtr hMutex = CreateMutex(IntPtr.Zero, true, "AutoNitro");
if (Marshal.GetLastWin32Error() == NATIVE_ERROR_ALREADY_EXISTS)
{
if (DialogResult.Yes == MessageBox.Show(sThisApp +
" is already running. Do you want to close it?",
sThisApp,
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1))
{
// Kill 'em All!
ProcessEntry[] processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();
foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
if (String.Compare(process.ExeFile,
sThisApp,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
process.Kill();
}
}
}
return;
}
// Register to be notified for any change to the HeadsetPreset property
bHPState = new SystemState(SystemProperty.HeadsetPresent);
bHPState.Changed += bState_Changed;
// Probably better to implement a message loop here instead of sleeping
// and DoEvents
while (true)
{
Application.DoEvents();
Thread.Sleep(1000);
}
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
// Returns true if the application with the name passed as parameter is
// currently running
static bool IsApplicationRunning(string pAppName)
{
ProcessEntry[] processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();
foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
if (String.Compare(process.ExeFile,
pAppName,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
return true;
}
}
return false;
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
// Shutsdown all running instances of the application pAppName
static void TerminateApplication(string pAppName)
{
ProcessEntry[] processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();
foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
if (String.Compare(process.ExeFile,
pAppName,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
// We can directly kill the process here but it is not safe.
// I don't prefer killing because the music app will not remember your
// last played track and position if you kill it.
// Instead ask for a shutdown politely.
int iPID = (int)process.ProcessID
Process p = System.Diagnostics.Process.GetProcessById(iPID);
p.CloseMainWindow();
}
}
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
private static void LaunchApplication(string pAppName)
{
System.Diagnostics.Process.Start(pAppName, "");
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
static void bState_Changed(object sender, ChangeEventArgs args)
{
Boolean blNewHPState = Convert.ToBoolean(args.NewValue);
bool blAppRunState = IsApplicationRunning(MUSIC_APP_EXE_NAME);
if (!blNewHPState)
{
if (true == blAppRunState)
{
TerminateApplication(MUSIC_APP_EXE_NAME);
}
}
else
{
if (false == blAppRunState)
{
string sApp = MUSIC_APP_PROGRAM_FOLDER + "\\" + MUSIC_APP_EXE_NAME;
try
{
LaunchApplication(sApp);
}
catch
{
throw new Exception("Failed to start music player.\nPath was " + sApp);
}
}
}
}
}
}
I use Nitrogen as my music player. The name and path of this application is hard coded in this app because I'm pretty lazy. You might want to change this if you use a different player.
Points of Interest
The tricky part of writing this application was to do with shutting down the application safely and in the right way. This aspect seems to be poorly documented or is poorly supported in .NET CF.
Things I Should Probably Do
- Allow user to select the music player instead of hard-coding it
- Get rid of the
Sleep
andDoEvents
business and implement a proper main loop
History
- 8th April, 2010: Initial post