Here's the issue:

2 PCs:

#1 is a desktop with decent Soundblaster card.

#2 is budget laptop with cheapo soundcard.

PC #1 can play anything at any time or at the same time, it doesn't care. The soundcard never blocks on writes. Very friendly, if you like.

PC #2 can only play one thing at a time, and blocks forever on writes if something else is using /dev/dsp. Not very friendly.

I play music almost all the time, and I use PC #2 for this, as PC #1 is in the other room, and usually being used for something else. Sometimes the volume gets turned down and I forget that music is actually playing. If I run some program that tries to use the soundcard, it just hangs. No error, no warning, nothing. I'm left scratching my head as to what is going on, until I realize xmms is still running on workspace 9.

This has always mystified me, as I've never quite narrowed down the solution to one that I like.

Solution #1:
Code:
$ /sbin/fuser -v /dev/dsp
                          USER        PID ACCESS COMMAND
/dev/dsp             miven      1461 f....        xmms
That works. It tells me what is using the device.
Solution #2:
Code:
$ /usr/sbin/lsof | grep dsp
xmms  1470 miven    5w   CHR  14,3  1665 /dev/sound/dsp
That also works, and tells me the same thing.

However, I don't really care who is using the device, all I want to know is if I can use the device.

Recently, I have been writing my own music player, and I encountered this issue in a bad way. My app has a main routine that shows the playlist and responds to key presses. It also forks to create the actual player thread. The player plays 1 tune and exits. The 2 threads communicate through a shared memory segment so main thread can tell player thread what to do, and player thread can tell main thread what it's up to.

The problem is that if /dev/dsp is being used, ao_open_file() hangs forever, until the device becomes available, then it takes over. This is not the behavior I'm looking for. I want it to return immediately with an error so I can get on with life, not leave me in suspense, whether my program crashed or I forgot to increment a variable in a while loop, or whatever else could go wrong when I'm hacking at 4 o'clock in the morning.

I've tested out many many sound programs and almost all of them do the same thing: hang forever.

Here's the simple and elegant solution I devised:
Code:
int dev_is_writable ( char *dev ) {
    int fd;
    struct stat st;
    if ( dev ) {
	// this always works
	if ( stat(dev,&st) == 0 ) { // it exists!
	    // but this fails
	    // here's the secret to not hanging here forever: O_NONBLOCK
	    fd = open ( dev, O_RDWR | O_NONBLOCK ); // returns instantly with error
	    if ( fd > 0 ) { // we can open it for write
		close(fd);
		return TRUE;
	    }
	}
    }
    return FALSE;
}
It works perfectly. The fork prints error and returns immediately (actually, make it sleep(1) otherwise parent and child get confused), and the user can see what is going on. The playlist keeps trying a new track every second, and the issue is completely obvious.

I thought I'd share some hard won programming trivia here.

Peace and Cheer.