Move code which runs in the player thread to player_thread.c.  Having
a lot of player thread code in decode.c isn't easy to understand.
---

 src/Makefile.am     |    2 
 src/decode.c        |  394 -------------------------------------------
 src/decode.h        |    2 
 src/main.c          |    4 
 src/player.c        |   53 ------
 src/player_thread.c |  466 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/player_thread.h |   24 +++
 7 files changed, 495 insertions(+), 450 deletions(-)
 create mode 100644 src/player_thread.c
 create mode 100644 src/player_thread.h

diff --git a/src/Makefile.am b/src/Makefile.am
index b097e90..006ccf2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,6 +68,7 @@ mpd_headers = \
        pcm_utils.h \
        permission.h \
        player.h \
+       player_thread.h \
        playerData.h \
        playlist.h \
        replayGain.h \
@@ -128,6 +129,7 @@ mpd_SOURCES = \
        pcm_utils.c \
        permission.c \
        player.c \
+       player_thread.c \
        playerData.c \
        playlist.c \
        replayGain.c \
diff --git a/src/decode.c b/src/decode.c
index 8d929d0..92f01a3 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -19,166 +19,10 @@
 #include "decode.h"
 #include "decoder_internal.h"
 
-#include "player.h"
 #include "playerData.h"
-#include "pcm_utils.h"
 #include "path.h"
 #include "log.h"
 #include "ls.h"
-#include "main_notify.h"
-#include "audio.h"
-#include "crossfade.h"
-
-enum xfade_state {
-       XFADE_DISABLED = -1,
-       XFADE_UNKNOWN = 0,
-       XFADE_ENABLED = 1
-};
-
-static void dc_command_wait(void)
-{
-       while (dc.command != DECODE_COMMAND_NONE) {
-               notify_signal(&dc.notify);
-               notify_wait(&pc.notify);
-       }
-}
-
-static void dc_command(enum decoder_command cmd)
-{
-       dc.command = cmd;
-       dc_command_wait();
-}
-
-static void stopDecode(void)
-{
-       if (dc.command == DECODE_COMMAND_START ||
-           dc.state != DECODE_STATE_STOP)
-               dc_command(DECODE_COMMAND_STOP);
-}
-
-static void quitDecode(void)
-{
-       stopDecode();
-       pc.state = PLAYER_STATE_STOP;
-       dc.command = DECODE_COMMAND_NONE;
-       pc.command = PLAYER_COMMAND_NONE;
-       wakeup_main_task();
-}
-
-static int waitOnDecode(int *decodeWaitedOn)
-{
-       while (dc.command == DECODE_COMMAND_START) {
-               notify_signal(&dc.notify);
-               notify_wait(&pc.notify);
-       }
-
-       if (dc.error != DECODE_ERROR_NOERROR) {
-               pc.errored_song = dc.next_song;
-               pc.error = PLAYER_ERROR_FILE;
-               quitDecode();
-               return -1;
-       }
-
-       pc.totalTime = pc.fileTime;
-       pc.bitRate = 0;
-       pc.sampleRate = 0;
-       pc.bits = 0;
-       pc.channels = 0;
-       *decodeWaitedOn = 1;
-
-       return 0;
-}
-
-static int decodeSeek(int *decodeWaitedOn, int *next)
-{
-       int ret = -1;
-
-       if (dc.state == DECODE_STATE_STOP ||
-           dc.error != DECODE_ERROR_NOERROR ||
-           dc.current_song != pc.next_song) {
-               stopDecode();
-               *next = -1;
-               ob_clear();
-               dc.next_song = pc.next_song;
-               dc.error = DECODE_ERROR_NOERROR;
-               dc.command = DECODE_COMMAND_START;
-               waitOnDecode(decodeWaitedOn);
-       }
-       if (dc.state != DECODE_STATE_STOP && dc.seekable) {
-               *next = -1;
-               dc.seekWhere = pc.seekWhere > pc.totalTime - 0.1 ?
-                   pc.totalTime - 0.1 : pc.seekWhere;
-               dc.seekWhere = 0 > dc.seekWhere ? 0 : dc.seekWhere;
-               dc.seekError = 0;
-               dc_command(DECODE_COMMAND_SEEK);
-               if (!dc.seekError) {
-                       pc.elapsedTime = dc.seekWhere;
-                       ret = 0;
-               }
-       }
-
-       player_command_finished();
-
-       return ret;
-}
-
-static void processDecodeInput(int *pause_r, unsigned int *bbp_r,
-                              enum xfade_state *do_xfade_r,
-                              int *decodeWaitedOn_r,
-                              int *next_r)
-{
-       switch (pc.command) {
-       case PLAYER_COMMAND_NONE:
-       case PLAYER_COMMAND_PLAY:
-       case PLAYER_COMMAND_STOP:
-       case PLAYER_COMMAND_CLOSE_AUDIO:
-               break;
-
-       case PLAYER_COMMAND_LOCK_QUEUE:
-               pc.queueLockState = PLAYER_QUEUE_LOCKED;
-               player_command_finished();
-               break;
-
-       case PLAYER_COMMAND_UNLOCK_QUEUE:
-               pc.queueLockState = PLAYER_QUEUE_UNLOCKED;
-               player_command_finished();
-               break;
-
-       case PLAYER_COMMAND_PAUSE:
-               *pause_r = !*pause_r;
-               if (*pause_r) {
-                       pc.state = PLAYER_STATE_PAUSE;
-               } else {
-                       if (openAudioDevice(NULL) >= 0) {
-                               pc.state = PLAYER_STATE_PLAY;
-                       } else {
-                               char tmp[MPD_PATH_MAX];
-                               pc.errored_song = dc.next_song;
-                               pc.error = PLAYER_ERROR_AUDIO;
-                               ERROR("problems opening audio device "
-                                     "while playing \"%s\"\n",
-                                     get_song_url(tmp, dc.next_song));
-                               *pause_r = -1;
-                       }
-               }
-               player_command_finished();
-               if (*pause_r == -1) {
-                       *pause_r = 1;
-               } else if (*pause_r) {
-                       dropBufferedAudio();
-                       closeAudioDevice();
-               }
-               break;
-
-       case PLAYER_COMMAND_SEEK:
-               dropBufferedAudio();
-               if (decodeSeek(decodeWaitedOn_r, next_r) == 0) {
-                       *do_xfade_r = XFADE_UNKNOWN;
-                       *bbp_r = 0;
-               }
-               break;
-       }
-}
 
 static void decodeStart(void)
 {
@@ -337,241 +181,3 @@ void decoderInit(void)
        if (pthread_create(&decoder_thread, &attr, decoder_task, NULL))
                FATAL("Failed to spawn decoder task: %s\n", strerror(errno));
 }
-
-static int playChunk(ob_chunk * chunk,
-                    const AudioFormat * format, double sizeToTime)
-{
-       pc.elapsedTime = chunk->times;
-       pc.bitRate = chunk->bitRate;
-
-       pcm_volumeChange(chunk->data, chunk->chunkSize,
-                        format, pc.softwareVolume);
-
-       if (playAudio(chunk->data,
-                     chunk->chunkSize) < 0)
-               return -1;
-
-       pc.totalPlayTime += sizeToTime * chunk->chunkSize;
-       return 0;
-}
-
-static void decodeParent(void)
-{
-       int do_pause = 0;
-       int buffering = 1;
-       unsigned int bbp = buffered_before_play;
-       enum xfade_state do_xfade = XFADE_UNKNOWN;
-       unsigned int crossFadeChunks = 0;
-       /** the position of the next cross-faded chunk in the next
-           song */
-       int nextChunk = 0;
-       int decodeWaitedOn = 0;
-       static const char silence[CHUNK_SIZE];
-       double sizeToTime = 0.0;
-       /** the position of the first chunk in the next song */
-       int next = -1;
-
-       ob_set_lazy(0);
-
-       if (waitOnDecode(&decodeWaitedOn) < 0)
-               return;
-
-       pc.elapsedTime = 0;
-       pc.state = PLAYER_STATE_PLAY;
-       player_command_finished();
-
-       while (1) {
-               processDecodeInput(&do_pause, &bbp, &do_xfade,
-                                  &decodeWaitedOn, &next);
-               if (pc.command == PLAYER_COMMAND_STOP) {
-                       dropBufferedAudio();
-                       break;
-               }
-
-               if (buffering) {
-                       if (ob_available() < bbp) {
-                               /* not enough decoded buffer space yet */
-                               notify_wait(&pc.notify);
-                               continue;
-                       } else {
-                               /* buffering is complete */
-                               buffering = 0;
-                               ob_set_lazy(1);
-                       }
-               }
-
-               if (decodeWaitedOn) {
-                       if(dc.state!=DECODE_STATE_START &&
-                          dc.error==DECODE_ERROR_NOERROR) {
-                               /* the decoder is ready and ok */
-                               decodeWaitedOn = 0;
-                               if(openAudioDevice(&(ob.audioFormat))<0) {
-                                       char tmp[MPD_PATH_MAX];
-                                       pc.errored_song = dc.next_song;
-                                       pc.error = PLAYER_ERROR_AUDIO;
-                                       ERROR("problems opening audio device "
-                                             "while playing \"%s\"\n",
-                                             get_song_url(tmp, dc.next_song));
-                                       break;
-                               }
-
-                               if (do_pause) {
-                                       dropBufferedAudio();
-                                       closeAudioDevice();
-                               }
-                               pc.totalTime = dc.totalTime;
-                               pc.sampleRate = dc.audioFormat.sampleRate;
-                               pc.bits = dc.audioFormat.bits;
-                               pc.channels = dc.audioFormat.channels;
-                               sizeToTime = 
audioFormatSizeToTime(&ob.audioFormat);
-                       }
-                       else if(dc.state!=DECODE_STATE_START) {
-                               /* the decoder failed */
-                               pc.errored_song = dc.next_song;
-                               pc.error = PLAYER_ERROR_FILE;
-                               break;
-                       }
-                       else {
-                               /* the decoder is not yet ready; wait
-                                  some more */
-                               notify_wait(&pc.notify);
-                               continue;
-                       }
-               }
-
-               if (dc.state == DECODE_STATE_STOP &&
-                   pc.queueState == PLAYER_QUEUE_FULL &&
-                   pc.queueLockState == PLAYER_QUEUE_UNLOCKED) {
-                       /* the decoder has finished the current song;
-                          make it decode the next song */
-                       next = ob.end;
-                       dc.next_song = pc.next_song;
-                       dc.error = DECODE_ERROR_NOERROR;
-                       dc.command = DECODE_COMMAND_START;
-                       pc.queueState = PLAYER_QUEUE_DECODE;
-                       wakeup_main_task();
-                       notify_signal(&dc.notify);
-               }
-               if (next >= 0 && do_xfade == XFADE_UNKNOWN &&
-                   dc.command != DECODE_COMMAND_START &&
-                   dc.state != DECODE_STATE_START) {
-                       /* enable cross fading in this song?  if yes,
-                          calculate how many chunks will be required
-                          for it */
-                       crossFadeChunks =
-                               cross_fade_calc(pc.crossFade, dc.totalTime,
-                                               &(ob.audioFormat),
-                                               ob.size -
-                                               buffered_before_play);
-                       if (crossFadeChunks > 0) {
-                               do_xfade = XFADE_ENABLED;
-                               nextChunk = -1;
-                       } else
-                               /* cross fading is disabled or the
-                                  next song is too short */
-                               do_xfade = XFADE_DISABLED;
-               }
-
-               if (do_pause)
-                       notify_wait(&pc.notify);
-               else if (!ob_is_empty() && (int)ob.begin != next) {
-                       ob_chunk *beginChunk = ob_get_chunk(ob.begin);
-                       unsigned int fadePosition;
-                       if (do_xfade == XFADE_ENABLED && next >= 0 &&
-                           (fadePosition = ob_relative(next))
-                           <= crossFadeChunks) {
-                               /* perform cross fade */
-                               if (nextChunk < 0) {
-                                       /* beginning of the cross fade
-                                          - adjust crossFadeChunks
-                                          which might be bigger than
-                                          the remaining number of
-                                          chunks in the old song */
-                                       crossFadeChunks = fadePosition;
-                               }
-                               nextChunk = ob_absolute(crossFadeChunks);
-                               if (nextChunk >= 0) {
-                                       ob_set_lazy(1);
-                                       cross_fade_apply(beginChunk,
-                                                        
ob_get_chunk(nextChunk),
-                                                        &(ob.audioFormat),
-                                                        fadePosition,
-                                                        crossFadeChunks);
-                               } else {
-                                       /* there are not enough
-                                          decoded chunks yet */
-                                       if (dc.state == DECODE_STATE_STOP) {
-                                               /* the decoder isn't
-                                                  running, abort
-                                                  cross fading */
-                                               do_xfade = XFADE_DISABLED;
-                                       } else {
-                                               /* wait for the
-                                                  decoder */
-                                               ob_set_lazy(0);
-                                               notify_wait(&pc.notify);
-                                               continue;
-                                       }
-                               }
-                       }
-
-                       /* play the current chunk */
-                       if (playChunk(beginChunk, &(ob.audioFormat),
-                                     sizeToTime) < 0)
-                               break;
-                       ob_shift();
-                       notify_signal(&dc.notify);
-               } else if (!ob_is_empty() && (int)ob.begin == next) {
-                       /* at the beginning of a new song */
-
-                       if (do_xfade == XFADE_ENABLED && nextChunk >= 0) {
-                               /* the cross-fade is finished; skip
-                                  the section which was cross-faded
-                                  (and thus already played) */
-                               ob_skip(crossFadeChunks);
-                       }
-
-                       do_xfade = XFADE_UNKNOWN;
-
-                       /* wait for the decoder to work on the new song */
-                       if (pc.queueState == PLAYER_QUEUE_DECODE ||
-                           pc.queueLockState == PLAYER_QUEUE_LOCKED) {
-                               notify_wait(&pc.notify);
-                               continue;
-                       }
-                       if (pc.queueState != PLAYER_QUEUE_PLAY)
-                               break;
-
-                       next = -1;
-                       if (waitOnDecode(&decodeWaitedOn) < 0)
-                               return;
-
-                       pc.queueState = PLAYER_QUEUE_EMPTY;
-                       wakeup_main_task();
-               } else if (dc.state == DECODE_STATE_STOP &&
-                          dc.command != DECODE_COMMAND_START) {
-                       break;
-               } else {
-                       /*DEBUG("waiting for decoded audio, play silence\n");*/
-                       if (playAudio(silence, CHUNK_SIZE) < 0)
-                               break;
-               }
-       }
-
-       quitDecode();
-}
-
-/* decode w/ buffering
- * this will fork another process
- * child process does decoding
- * parent process does playing audio
- */
-void decode(void)
-{
-       ob_clear();
-       dc.next_song = pc.next_song;
-       dc.error = DECODE_ERROR_NOERROR;
-       dc_command(DECODE_COMMAND_START);
-
-       decodeParent();
-}
diff --git a/src/decode.h b/src/decode.h
index fbee97c..29e2539 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -59,8 +59,6 @@ typedef struct _DecoderControl {
        volatile float totalTime;
 } DecoderControl;
 
-void decode(void);
-
 void decoderInit(void);
 
 #endif
diff --git a/src/main.c b/src/main.c
index 7f66fd6..53b204e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,7 +20,7 @@
 #include "command.h"
 #include "playlist.h"
 #include "directory.h"
-#include "player.h"
+#include "player_thread.h"
 #include "listen.h"
 #include "conf.h"
 #include "path.h"
@@ -432,7 +432,7 @@ int main(int argc, char *argv[])
 
        openVolumeDevice();
        decoderInit();
-       playerInit();
+       player_create();
        read_state_file();
 
        while (COMMAND_RETURN_KILL != doIOForInterfaces() &&
diff --git a/src/player.c b/src/player.c
index 08ad940..c2e84c1 100644
--- a/src/player.c
+++ b/src/player.c
@@ -17,67 +17,16 @@
  */
 
 #include "player.h"
+#include "player_thread.h"
 #include "path.h"
 #include "command.h"
-#include "log.h"
 #include "playerData.h"
 #include "ack.h"
 #include "os_compat.h"
 #include "main_notify.h"
-#include "audio.h"
 
 static void playerCloseAudio(void);
 
-static void * player_task(mpd_unused void *arg)
-{
-       notify_enter(&pc.notify);
-
-       while (1) {
-               switch (pc.command) {
-               case PLAYER_COMMAND_PLAY:
-                       decode();
-                       break;
-
-               case PLAYER_COMMAND_STOP:
-               case PLAYER_COMMAND_SEEK:
-               case PLAYER_COMMAND_PAUSE:
-                       player_command_finished();
-                       break;
-
-               case PLAYER_COMMAND_CLOSE_AUDIO:
-                       closeAudioDevice();
-                       player_command_finished();
-                       break;
-
-               case PLAYER_COMMAND_LOCK_QUEUE:
-                       pc.queueLockState = PLAYER_QUEUE_LOCKED;
-                       player_command_finished();
-                       break;
-
-               case PLAYER_COMMAND_UNLOCK_QUEUE:
-                       pc.queueLockState = PLAYER_QUEUE_UNLOCKED;
-                       player_command_finished();
-                       break;
-
-               case PLAYER_COMMAND_NONE:
-                       notify_wait(&pc.notify);
-                       break;
-               }
-       }
-       return NULL;
-}
-
-void playerInit(void)
-{
-       pthread_attr_t attr;
-       pthread_t player_thread;
-
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       if (pthread_create(&player_thread, &attr, player_task, NULL))
-               FATAL("Failed to spawn player task: %s\n", strerror(errno));
-}
-
 int playerWait(int fd)
 {
        if (playerStop(fd) < 0)
diff --git a/src/player_thread.c b/src/player_thread.c
new file mode 100644
index 0000000..0937fb3
--- /dev/null
+++ b/src/player_thread.c
@@ -0,0 +1,466 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2003-2007 by Warren Dukes ([EMAIL PROTECTED])
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "player_thread.h"
+#include "playerData.h"
+#include "audio.h"
+#include "pcm_utils.h"
+#include "path.h"
+#include "log.h"
+#include "main_notify.h"
+#include "crossfade.h"
+
+enum xfade_state {
+       XFADE_DISABLED = -1,
+       XFADE_UNKNOWN = 0,
+       XFADE_ENABLED = 1
+};
+
+static void dc_command_wait(void)
+{
+       while (dc.command != DECODE_COMMAND_NONE) {
+               notify_signal(&dc.notify);
+               notify_wait(&pc.notify);
+       }
+}
+
+static void dc_command(enum decoder_command cmd)
+{
+       dc.command = cmd;
+       dc_command_wait();
+}
+
+static void stopDecode(void)
+{
+       if (dc.command == DECODE_COMMAND_START ||
+           dc.state != DECODE_STATE_STOP)
+               dc_command(DECODE_COMMAND_STOP);
+}
+
+static void quitDecode(void)
+{
+       stopDecode();
+       pc.state = PLAYER_STATE_STOP;
+       dc.command = DECODE_COMMAND_NONE;
+       pc.command = PLAYER_COMMAND_NONE;
+       wakeup_main_task();
+}
+
+static int waitOnDecode(int *decodeWaitedOn)
+{
+       while (dc.command == DECODE_COMMAND_START) {
+               notify_signal(&dc.notify);
+               notify_wait(&pc.notify);
+       }
+
+       if (dc.error != DECODE_ERROR_NOERROR) {
+               pc.errored_song = dc.next_song;
+               pc.error = PLAYER_ERROR_FILE;
+               quitDecode();
+               return -1;
+       }
+
+       pc.totalTime = pc.fileTime;
+       pc.bitRate = 0;
+       pc.sampleRate = 0;
+       pc.bits = 0;
+       pc.channels = 0;
+       *decodeWaitedOn = 1;
+
+       return 0;
+}
+
+static int decodeSeek(int *decodeWaitedOn, int *next)
+{
+       int ret = -1;
+
+       if (dc.state == DECODE_STATE_STOP ||
+           dc.error != DECODE_ERROR_NOERROR ||
+           dc.current_song != pc.next_song) {
+               stopDecode();
+               *next = -1;
+               ob_clear();
+               dc.next_song = pc.next_song;
+               dc.error = DECODE_ERROR_NOERROR;
+               dc.command = DECODE_COMMAND_START;
+               waitOnDecode(decodeWaitedOn);
+       }
+       if (dc.state != DECODE_STATE_STOP && dc.seekable) {
+               *next = -1;
+               dc.seekWhere = pc.seekWhere > pc.totalTime - 0.1 ?
+                   pc.totalTime - 0.1 : pc.seekWhere;
+               dc.seekWhere = 0 > dc.seekWhere ? 0 : dc.seekWhere;
+               dc.seekError = 0;
+               dc_command(DECODE_COMMAND_SEEK);
+               if (!dc.seekError) {
+                       pc.elapsedTime = dc.seekWhere;
+                       ret = 0;
+               }
+       }
+
+       player_command_finished();
+
+       return ret;
+}
+
+static void processDecodeInput(int *pause_r, unsigned int *bbp_r,
+                              enum xfade_state *do_xfade_r,
+                              int *decodeWaitedOn_r,
+                              int *next_r)
+{
+       switch (pc.command) {
+       case PLAYER_COMMAND_NONE:
+       case PLAYER_COMMAND_PLAY:
+       case PLAYER_COMMAND_STOP:
+       case PLAYER_COMMAND_CLOSE_AUDIO:
+               break;
+
+       case PLAYER_COMMAND_LOCK_QUEUE:
+               pc.queueLockState = PLAYER_QUEUE_LOCKED;
+               player_command_finished();
+               break;
+
+       case PLAYER_COMMAND_UNLOCK_QUEUE:
+               pc.queueLockState = PLAYER_QUEUE_UNLOCKED;
+               player_command_finished();
+               break;
+
+       case PLAYER_COMMAND_PAUSE:
+               *pause_r = !*pause_r;
+               if (*pause_r) {
+                       pc.state = PLAYER_STATE_PAUSE;
+               } else {
+                       if (openAudioDevice(NULL) >= 0) {
+                               pc.state = PLAYER_STATE_PLAY;
+                       } else {
+                               char tmp[MPD_PATH_MAX];
+                               pc.errored_song = dc.next_song;
+                               pc.error = PLAYER_ERROR_AUDIO;
+                               ERROR("problems opening audio device "
+                                     "while playing \"%s\"\n",
+                                     get_song_url(tmp, dc.next_song));
+                               *pause_r = -1;
+                       }
+               }
+               player_command_finished();
+               if (*pause_r == -1) {
+                       *pause_r = 1;
+               } else if (*pause_r) {
+                       dropBufferedAudio();
+                       closeAudioDevice();
+               }
+               break;
+
+       case PLAYER_COMMAND_SEEK:
+               dropBufferedAudio();
+               if (decodeSeek(decodeWaitedOn_r, next_r) == 0) {
+                       *do_xfade_r = XFADE_UNKNOWN;
+                       *bbp_r = 0;
+               }
+               break;
+       }
+}
+
+static int playChunk(ob_chunk * chunk,
+                    const AudioFormat * format, double sizeToTime)
+{
+       pc.elapsedTime = chunk->times;
+       pc.bitRate = chunk->bitRate;
+
+       pcm_volumeChange(chunk->data, chunk->chunkSize,
+                        format, pc.softwareVolume);
+
+       if (playAudio(chunk->data,
+                     chunk->chunkSize) < 0)
+               return -1;
+
+       pc.totalPlayTime += sizeToTime * chunk->chunkSize;
+       return 0;
+}
+
+static void decodeParent(void)
+{
+       int do_pause = 0;
+       int buffering = 1;
+       unsigned int bbp = buffered_before_play;
+       enum xfade_state do_xfade = XFADE_UNKNOWN;
+       unsigned int crossFadeChunks = 0;
+       /** the position of the next cross-faded chunk in the next
+           song */
+       int nextChunk = 0;
+       int decodeWaitedOn = 0;
+       static const char silence[CHUNK_SIZE];
+       double sizeToTime = 0.0;
+       /** the position of the first chunk in the next song */
+       int next = -1;
+
+       ob_set_lazy(0);
+
+       if (waitOnDecode(&decodeWaitedOn) < 0)
+               return;
+
+       pc.elapsedTime = 0;
+       pc.state = PLAYER_STATE_PLAY;
+       player_command_finished();
+
+       while (1) {
+               processDecodeInput(&do_pause, &bbp, &do_xfade,
+                                  &decodeWaitedOn, &next);
+               if (pc.command == PLAYER_COMMAND_STOP) {
+                       dropBufferedAudio();
+                       break;
+               }
+
+               if (buffering) {
+                       if (ob_available() < bbp) {
+                               /* not enough decoded buffer space yet */
+                               notify_wait(&pc.notify);
+                               continue;
+                       } else {
+                               /* buffering is complete */
+                               buffering = 0;
+                               ob_set_lazy(1);
+                       }
+               }
+
+               if (decodeWaitedOn) {
+                       if(dc.state!=DECODE_STATE_START &&
+                          dc.error==DECODE_ERROR_NOERROR) {
+                               /* the decoder is ready and ok */
+                               decodeWaitedOn = 0;
+                               if(openAudioDevice(&(ob.audioFormat))<0) {
+                                       char tmp[MPD_PATH_MAX];
+                                       pc.errored_song = dc.next_song;
+                                       pc.error = PLAYER_ERROR_AUDIO;
+                                       ERROR("problems opening audio device "
+                                             "while playing \"%s\"\n",
+                                             get_song_url(tmp, dc.next_song));
+                                       break;
+                               }
+
+                               if (do_pause) {
+                                       dropBufferedAudio();
+                                       closeAudioDevice();
+                               }
+                               pc.totalTime = dc.totalTime;
+                               pc.sampleRate = dc.audioFormat.sampleRate;
+                               pc.bits = dc.audioFormat.bits;
+                               pc.channels = dc.audioFormat.channels;
+                               sizeToTime = 
audioFormatSizeToTime(&ob.audioFormat);
+                       }
+                       else if(dc.state!=DECODE_STATE_START) {
+                               /* the decoder failed */
+                               pc.errored_song = dc.next_song;
+                               pc.error = PLAYER_ERROR_FILE;
+                               break;
+                       }
+                       else {
+                               /* the decoder is not yet ready; wait
+                                  some more */
+                               notify_wait(&pc.notify);
+                               continue;
+                       }
+               }
+
+               if (dc.state == DECODE_STATE_STOP &&
+                   pc.queueState == PLAYER_QUEUE_FULL &&
+                   pc.queueLockState == PLAYER_QUEUE_UNLOCKED) {
+                       /* the decoder has finished the current song;
+                          make it decode the next song */
+                       next = ob.end;
+                       dc.next_song = pc.next_song;
+                       dc.error = DECODE_ERROR_NOERROR;
+                       dc.command = DECODE_COMMAND_START;
+                       pc.queueState = PLAYER_QUEUE_DECODE;
+                       wakeup_main_task();
+                       notify_signal(&dc.notify);
+               }
+               if (next >= 0 && do_xfade == XFADE_UNKNOWN &&
+                   dc.command != DECODE_COMMAND_START &&
+                   dc.state != DECODE_STATE_START) {
+                       /* enable cross fading in this song?  if yes,
+                          calculate how many chunks will be required
+                          for it */
+                       crossFadeChunks =
+                               cross_fade_calc(pc.crossFade, dc.totalTime,
+                                               &(ob.audioFormat),
+                                               ob.size -
+                                               buffered_before_play);
+                       if (crossFadeChunks > 0) {
+                               do_xfade = XFADE_ENABLED;
+                               nextChunk = -1;
+                       } else
+                               /* cross fading is disabled or the
+                                  next song is too short */
+                               do_xfade = XFADE_DISABLED;
+               }
+
+               if (do_pause)
+                       notify_wait(&pc.notify);
+               else if (!ob_is_empty() && (int)ob.begin != next) {
+                       ob_chunk *beginChunk = ob_get_chunk(ob.begin);
+                       unsigned int fadePosition;
+                       if (do_xfade == XFADE_ENABLED && next >= 0 &&
+                           (fadePosition = ob_relative(next))
+                           <= crossFadeChunks) {
+                               /* perform cross fade */
+                               if (nextChunk < 0) {
+                                       /* beginning of the cross fade
+                                          - adjust crossFadeChunks
+                                          which might be bigger than
+                                          the remaining number of
+                                          chunks in the old song */
+                                       crossFadeChunks = fadePosition;
+                               }
+                               nextChunk = ob_absolute(crossFadeChunks);
+                               if (nextChunk >= 0) {
+                                       ob_set_lazy(1);
+                                       cross_fade_apply(beginChunk,
+                                                        
ob_get_chunk(nextChunk),
+                                                        &(ob.audioFormat),
+                                                        fadePosition,
+                                                        crossFadeChunks);
+                               } else {
+                                       /* there are not enough
+                                          decoded chunks yet */
+                                       if (dc.state == DECODE_STATE_STOP) {
+                                               /* the decoder isn't
+                                                  running, abort
+                                                  cross fading */
+                                               do_xfade = XFADE_DISABLED;
+                                       } else {
+                                               /* wait for the
+                                                  decoder */
+                                               ob_set_lazy(0);
+                                               notify_wait(&pc.notify);
+                                               continue;
+                                       }
+                               }
+                       }
+
+                       /* play the current chunk */
+                       if (playChunk(beginChunk, &(ob.audioFormat),
+                                     sizeToTime) < 0)
+                               break;
+                       ob_shift();
+                       notify_signal(&dc.notify);
+               } else if (!ob_is_empty() && (int)ob.begin == next) {
+                       /* at the beginning of a new song */
+
+                       if (do_xfade == XFADE_ENABLED && nextChunk >= 0) {
+                               /* the cross-fade is finished; skip
+                                  the section which was cross-faded
+                                  (and thus already played) */
+                               ob_skip(crossFadeChunks);
+                       }
+
+                       do_xfade = XFADE_UNKNOWN;
+
+                       /* wait for the decoder to work on the new song */
+                       if (pc.queueState == PLAYER_QUEUE_DECODE ||
+                           pc.queueLockState == PLAYER_QUEUE_LOCKED) {
+                               notify_wait(&pc.notify);
+                               continue;
+                       }
+                       if (pc.queueState != PLAYER_QUEUE_PLAY)
+                               break;
+
+                       next = -1;
+                       if (waitOnDecode(&decodeWaitedOn) < 0)
+                               return;
+
+                       pc.queueState = PLAYER_QUEUE_EMPTY;
+                       wakeup_main_task();
+               } else if (dc.state == DECODE_STATE_STOP &&
+                          dc.command != DECODE_COMMAND_START) {
+                       break;
+               } else {
+                       /*DEBUG("waiting for decoded audio, play silence\n");*/
+                       if (playAudio(silence, CHUNK_SIZE) < 0)
+                               break;
+               }
+       }
+
+       quitDecode();
+}
+
+/* decode w/ buffering
+ * this will fork another process
+ * child process does decoding
+ * parent process does playing audio
+ */
+static void decode(void)
+{
+       ob_clear();
+
+       dc.next_song = pc.next_song;
+       dc.error = DECODE_ERROR_NOERROR;
+       dc_command(DECODE_COMMAND_START);
+
+       decodeParent();
+}
+
+static void * player_task(mpd_unused void *arg)
+{
+       notify_enter(&pc.notify);
+
+       while (1) {
+               switch (pc.command) {
+               case PLAYER_COMMAND_PLAY:
+                       decode();
+                       break;
+
+               case PLAYER_COMMAND_STOP:
+               case PLAYER_COMMAND_SEEK:
+               case PLAYER_COMMAND_PAUSE:
+                       player_command_finished();
+                       break;
+
+               case PLAYER_COMMAND_CLOSE_AUDIO:
+                       closeAudioDevice();
+                       player_command_finished();
+                       break;
+
+               case PLAYER_COMMAND_LOCK_QUEUE:
+                       pc.queueLockState = PLAYER_QUEUE_LOCKED;
+                       player_command_finished();
+                       break;
+
+               case PLAYER_COMMAND_UNLOCK_QUEUE:
+                       pc.queueLockState = PLAYER_QUEUE_UNLOCKED;
+                       player_command_finished();
+                       break;
+
+               case PLAYER_COMMAND_NONE:
+                       notify_wait(&pc.notify);
+                       break;
+               }
+       }
+       return NULL;
+}
+
+void player_create(void)
+{
+       pthread_attr_t attr;
+       pthread_t player_thread;
+
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+       if (pthread_create(&player_thread, &attr, player_task, NULL))
+               FATAL("Failed to spawn player task: %s\n", strerror(errno));
+}
diff --git a/src/player_thread.h b/src/player_thread.h
new file mode 100644
index 0000000..4d154d6
--- /dev/null
+++ b/src/player_thread.h
@@ -0,0 +1,24 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2008 Max Kellermann <[EMAIL PROTECTED]>
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef PLAYER_THREAD_H
+#define PLAYER_THREAD_H
+
+void player_create(void);
+
+#endif


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team

Reply via email to