Hi!
A small problem in OS X CoreAudio:
Steps to reproduce:
* Start playing a song
* Pause song
* Quit
Both the despotify and simple client has the same problem. They will hang if the currently playing song is paused at program exit. If a song is playing normally the program will exit nice.
This problem only occurs on OS X with CoreAudio. I used Snow Leopard + MacPorts to compile, svn -r 514.
I also narrowed the problem down by enabling DEBUG and inserting more DSFYDEBUG lines. The program seems to hang in:
src/clients/despotify/coreaudio.c line 194, in the following call:
AudioDeviceStop (device->adev_id, device->proc_id)
The coreaudio.c file is duplicated in the simple client and the same problem is there too, most likely in the same line.
I have tried but didn't find any other workaround yet than to always have a song playing when giving the quit command.
NOTE: The same problem also occurs if despotify has played through all songs in the playlist and is quiet when you give the quit command. It must be playing a song for the quit command to work correctly.
Cheers!
/Albert
Maybe the source here can give some hints:
http://libao.sourcearchive.com/documentation/1.0.0-5/ao__macosx_8c-source.html
Especially this comment:
// For some rare cases (using atexit in your program) Coreaudio tears
// down the HAL itself, so we do not need to do that here.
// We wouldn't get an error if we did, but AO would hang waiting for the
// AU to flush the buffer
But libao doesn't seem to use exactly the same API. It is similar but still not the same, so I am not sure if that comment is relevant.
Workaround to the CoreAudio hangup problem
Now I found a workaround to the problem, I attached the diff in coreaudio.diff. It is not nice but it works.
I found out the problem has to do with device->mutex.
audio_callback is hanging right after the line saying
"Zero bytes available and playing, waiting."
So the workaround is to send a pthread_cond_signal(&device->event); *before* locking the mutex in audio_exit. Only do this if device->playing is 1 *and* device->bufsize is 0.
The problem with this is a small risk of a race condition. In case bufsize changes between the if() and pthread_cond_signal. It is probably possible to solve this in a better way, but I don't really know how.