QUEUE adds a new song to the player's queue. CANCEL clears the queue.
These two commands replace the old and complex queueState and
queueLockState code.
This variable is superfluous, it is only used to copy its value to
player_control.totalTime. Since the original source of this value
(song->tag->time) will still be available at this point, we can safely
remove fileTime.
The decoder was woken up after each chunk which had been played. That
caused a lot of superfluous context switches. Wake up the decoder
only when a certain amount of the buffer has been consumed. This
formula is somewhat arbitrary, and has to be proven experimentally.
pause() puts the audio output into pause mode: if supported, it may
perform a special action, which keeps the device open, but does not
play anything. Output plugins like "shout" might want to play silence
during pause, so their clients won't be disconnected. Plugins which
do not support pausing will simply be closed, and have to be reopened
when unpaused.
This pach includes an implementation for the shout plugin, which
sends silence chunks.
There was a known deadlocking bug in the notify library: when the
other thread set notify->pending after the according check in
notify_wait(), the latter thread was deadlocked. Resolve this by
synchronizing all accesses to notify->pending with the notify object's
mutex. Since notify_signal_sync() was never used, we can remove it.
As a consequence, we don't need notify_enter() and notify_leave()
anymore; eliminate them, too.
Unfortunately, we have to pass the DecoderControl pointer to these
inline functions, because the global variable "dc" may not be
available here. This will be fixed later.
The decoder thread is responsible for resetting dc->command after a
command was executed. As a consequence, we can assume that
dc->command is already NONE after decoder_stop().
playerKill() was marked as deprecated, but it seems like a good idea
to do proper cleanup in all threads (e.g. for usable valgrind
results). Introduce the command "EXIT" which makes the player thread
exit cleanly.
playerWait() stops the player thread (twice!) and closes the output
device. It should be well enough to just send CLOSE_AUDIO, without
STOP.
This requires a tiny change to the player thread code: make it break
when CLOSE_AUDIO is sent.