Initial revision 6759
[qball-mpd.git] / src / .svn / text-base / decode.c.svn-base
blobee8d43d3ea98851071487e2482a1b3e8c98d82cd
1 /* the Music Player Daemon (MPD)
2  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
19 #include "decode.h"
21 #include "player.h"
22 #include "playerData.h"
23 #include "utils.h"
24 #include "pcm_utils.h"
25 #include "audio.h"
26 #include "path.h"
27 #include "log.h"
28 #include "sig_handlers.h"
29 #include "ls.h"
30 #include "utf8.h"
32 #include <signal.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/wait.h>
37 #include <unistd.h>
38 #include <string.h>
40 static int decode_pid;
42 void decodeSigHandler(int sig, siginfo_t * si, void *v)
44         if (sig == SIGCHLD) {
45                 int status;
46                 if (decode_pid == wait3(&status, WNOHANG, NULL)) {
47                         if (WIFSIGNALED(status)) {
48                                 if (WTERMSIG(status) != SIGTERM) {
49                                         ERROR("decode process died from "
50                                               "signal: %i\n", WTERMSIG(status));
51                                 }
52                         }
53                         decode_pid = 0;
54                         getPlayerData()->playerControl.decode_pid = 0;
55                 }
56         } else if (sig == SIGTERM) {
57                 int pid = decode_pid;
58                 if (pid > 0) {
59                         DEBUG("player (or child) got SIGTERM\n");
60                         kill(pid, SIGCONT);
61                         kill(pid, SIGTERM);
62                 } else
63                         DEBUG("decoder (or child) got SIGTERM\n");
64                 exit(EXIT_SUCCESS);
65         }
68 static void stopDecode(DecoderControl * dc)
70         if (decode_pid > 0 && (dc->start || dc->state != DECODE_STATE_STOP)) {
71                 dc->stop = 1;
72                 while (decode_pid > 0 && dc->stop)
73                         my_usleep(10000);
74         }
77 static void quitDecode(PlayerControl * pc, DecoderControl * dc)
79         int pid;
81         stopDecode(dc);
82         pc->state = PLAYER_STATE_STOP;
83         dc->seek = 0;
84         pc->play = 0;
85         pc->stop = 0;
86         pc->pause = 0;
88         pid = decode_pid;
89         if (pid > 0)
90                 kill(pid, SIGSTOP);
92         kill(getppid(), SIGUSR1);
95 static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af)
97         long chunks;
99         if (pc->crossFade <= 0)
100                 return 0;
102         chunks = (af->sampleRate * af->bits * af->channels / 8.0 / CHUNK_SIZE);
103         chunks = (chunks * pc->crossFade + 0.5);
105         if (chunks > (buffered_chunks - buffered_before_play)) {
106                 chunks = buffered_chunks - buffered_before_play;
107         }
109         if (chunks < 0)
110                 chunks = 0;
112         return (int)chunks;
115 #define handleDecodeStart() \
116         if(decodeWaitedOn) { \
117                 if(dc->state!=DECODE_STATE_START &&  decode_pid > 0 && \
118                                 dc->error==DECODE_ERROR_NOERROR) \
119                 { \
120                         decodeWaitedOn = 0; \
121                         if(openAudioDevice(&(cb->audioFormat))<0) { \
122                                 pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
123                                 pc->error = PLAYER_ERROR_AUDIO; \
124                                 ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
125                                 quitDecode(pc,dc); \
126                                 return; \
127                         } \
128                         if (pause) { \
129                                 dropBufferedAudio(); \
130                                 closeAudioDevice(); \
131                         } \
132                         pc->totalTime = dc->totalTime; \
133                         pc->sampleRate = dc->audioFormat.sampleRate; \
134                         pc->bits = dc->audioFormat.bits; \
135                         pc->channels = dc->audioFormat.channels; \
136                         sizeToTime = 8.0/cb->audioFormat.bits/ \
137                                         cb->audioFormat.channels/ \
138                                         cb->audioFormat.sampleRate; \
139                 } \
140                 else if(dc->state!=DECODE_STATE_START || decode_pid <= 0) { \
141                         pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
142                         pc->error = PLAYER_ERROR_FILE; \
143                         quitDecode(pc,dc); \
144                         return; \
145                 } \
146                 else { \
147                         my_usleep(10000); \
148                         continue; \
149                 } \
150         }
152 static int waitOnDecode(PlayerControl * pc, DecoderControl * dc,
153                         OutputBuffer * cb, int *decodeWaitedOn)
155         MpdTag *tag = NULL;
156         pathcpy_trunc(pc->currentUrl, pc->utf8url);
158         while (decode_pid > 0 && dc->start)
159                 my_usleep(10000);
161         if (dc->start || dc->error != DECODE_ERROR_NOERROR) {
162                 pathcpy_trunc(pc->erroredUrl, pc->utf8url);
163                 pc->error = PLAYER_ERROR_FILE;
164                 quitDecode(pc, dc);
165                 return -1;
166         }
168         if ((tag = metadataChunkToMpdTagDup(&(pc->fileMetadataChunk)))) {
169                 sendMetadataToAudioDevice(tag);
170                 freeMpdTag(tag);
171         }
173         pc->totalTime = pc->fileTime;
174         pc->bitRate = 0;
175         pc->sampleRate = 0;
176         pc->bits = 0;
177         pc->channels = 0;
178         *decodeWaitedOn = 1;
180         return 0;
183 static int decodeSeek(PlayerControl * pc, DecoderControl * dc,
184                       OutputBuffer * cb, int *decodeWaitedOn, int *next)
186         int ret = -1;
188         if (decode_pid > 0) {
189                 if (dc->state == DECODE_STATE_STOP || dc->error ||
190                     strcmp(dc->utf8url, pc->utf8url) != 0) {
191                         stopDecode(dc);
192                         *next = -1;
193                         cb->begin = 0;
194                         cb->end = 0;
195                         dc->error = 0;
196                         dc->start = 1;
197                         waitOnDecode(pc, dc, cb, decodeWaitedOn);
198                 }
199                 if (decode_pid > 0 && dc->state != DECODE_STATE_STOP &&
200                     dc->seekable) {
201                         *next = -1;
202                         dc->seekWhere = pc->seekWhere > pc->totalTime - 0.1 ?
203                             pc->totalTime - 0.1 : pc->seekWhere;
204                         dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere;
205                         dc->seekError = 0;
206                         dc->seek = 1;
207                         while (decode_pid > 0 && dc->seek)
208                                 my_usleep(10000);
209                         if (!dc->seekError) {
210                                 pc->elapsedTime = dc->seekWhere;
211                                 ret = 0;
212                         }
213                 }
214         }
215         pc->seek = 0;
217         return ret;
220 #define processDecodeInput() \
221         if(pc->cycleLogFiles) { \
222                 cycle_log_files(); \
223                 pc->cycleLogFiles = 0; \
224         } \
225         if(pc->lockQueue) { \
226                 pc->queueLockState = PLAYER_QUEUE_LOCKED; \
227                 pc->lockQueue = 0; \
228         } \
229         if(pc->unlockQueue) { \
230                 pc->queueLockState = PLAYER_QUEUE_UNLOCKED; \
231                 pc->unlockQueue = 0; \
232         } \
233         if(pc->pause) { \
234                 pause = !pause; \
235                 if (pause) { \
236                         pc->state = PLAYER_STATE_PAUSE; \
237                 } else { \
238                         if (openAudioDevice(NULL) >= 0) { \
239                                 pc->state = PLAYER_STATE_PLAY; \
240                         } else { \
241                                 pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
242                                 pc->error = PLAYER_ERROR_AUDIO; \
243                                 ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
244                                 pause = -1; \
245                         } \
246                 } \
247                 pc->pause = 0; \
248                 kill(getppid(), SIGUSR1); \
249                 if (pause == -1) { \
250                         pause = 1; \
251                 } else if (pause) { \
252                         dropBufferedAudio(); \
253                         closeAudioDevice(); \
254                 } \
255         } \
256         if(pc->seek) { \
257                 dropBufferedAudio(); \
258                 if(decodeSeek(pc,dc,cb,&decodeWaitedOn,&next) == 0) { \
259                         doCrossFade = 0; \
260                         nextChunk =  -1; \
261                         bbp = 0; \
262                 } \
263         } \
264         if(pc->stop) { \
265                 dropBufferedAudio(); \
266                 quitDecode(pc,dc); \
267                 return; \
268         }
270 static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
271                         DecoderControl * dc)
273         int ret;
274         InputStream inStream;
275         InputPlugin *plugin = NULL;
276         char *path;
278         if (isRemoteUrl(pc->utf8url))
279                 path = utf8StrToLatin1Dup(pc->utf8url);
280         else
281                 path = xstrdup(rmp2amp(utf8ToFsCharset(pc->utf8url)));
283         if (!path) {
284                 dc->error = DECODE_ERROR_FILE;
285                 dc->state = DECODE_STATE_STOP;
286                 dc->start = 0;
287                 return;
288         }
290         copyMpdTagToOutputBuffer(cb, NULL);
292         pathcpy_trunc(dc->utf8url, pc->utf8url);
294         if (openInputStream(&inStream, path) < 0) {
295                 dc->error = DECODE_ERROR_FILE;
296                 dc->state = DECODE_STATE_STOP;
297                 dc->start = 0;
298                 free(path);
299                 return;
300         }
302         dc->state = DECODE_STATE_START;
303         dc->start = 0;
304 #if 0 /* this code is moved to the http stuff */
305         while (!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
306                && !dc->stop) {
307                 /* sleep so we don't consume 100% of the cpu */
308                 my_usleep(1000);
309         }
310 #endif
311         /* for http streams, seekable is determined in bufferInputStream */
312         dc->seekable = inStream.seekable;
313         
314         if (dc->stop) {
315                 dc->state = DECODE_STATE_STOP;
316                 dc->stop = 0;
317                 free(path);
318                 return;
319         }
321         /*if(inStream.metaName) {
322            MpdTag * tag = newMpdTag();
323            tag->name = xstrdup(inStream.metaName);
324            copyMpdTagToOutputBuffer(cb, tag);
325            freeMpdTag(tag);
326            } */
328         /* reset Metadata in OutputBuffer */
330         ret = DECODE_ERROR_UNKTYPE;
331         if (isRemoteUrl(dc->utf8url)) {
332                 unsigned int next = 0;
333                 cb->acceptMetadata = 1;
335                 /* first we try mime types: */
336                 while (ret && (plugin = getInputPluginFromMimeType(inStream.mime, next++))) {
337                         if (!plugin->streamDecodeFunc)
338                                 continue;
339                         if (!(plugin->streamTypes & INPUT_PLUGIN_STREAM_URL))
340                                 continue;
341                         if (plugin->tryDecodeFunc
342                             && !plugin->tryDecodeFunc(&inStream))
343                                 continue;
344                         ret = plugin->streamDecodeFunc(cb, dc, &inStream);
345                         break;
346                 }
348                 /* if that fails, try suffix matching the URL: */
349                 if (plugin == NULL) {
350                         char *s = getSuffix(dc->utf8url);
351                         next = 0;
352                         while (ret && (plugin = getInputPluginFromSuffix(s, next++))) {
353                                 if (!plugin->streamDecodeFunc)
354                                         continue;
355                                 if (!(plugin->streamTypes &
356                                       INPUT_PLUGIN_STREAM_URL))
357                                         continue;
358                                 if (plugin->tryDecodeFunc &&
359                                     !plugin->tryDecodeFunc(&inStream))
360                                         continue;
361                                 ret = plugin->streamDecodeFunc(cb, dc, &inStream);
362                                 break;
363                         }
364                 }
365                 /* fallback to mp3: */
366                 /* this is needed for bastard streams that don't have a suffix
367                    or set the mimeType */
368                 if (plugin == NULL) {
369                         /* we already know our mp3Plugin supports streams, no
370                          * need to check for stream{Types,DecodeFunc} */
371                         if ((plugin = getInputPluginFromName("mp3")))
372                                 ret = plugin->streamDecodeFunc(cb, dc, &inStream);
373                 }
374         } else {
375                 unsigned int next = 0;
376                 char *s = getSuffix(dc->utf8url);
377                 cb->acceptMetadata = 0;
378                 while (ret && (plugin = getInputPluginFromSuffix(s, next++))) {
379                         if (!plugin->streamTypes & INPUT_PLUGIN_STREAM_FILE)
380                                 continue;
382                         if (plugin->tryDecodeFunc &&
383                             !plugin->tryDecodeFunc(&inStream))
384                                 continue;
386                         if (plugin->fileDecodeFunc) {
387                                 closeInputStream(&inStream);
388                                 ret = plugin->fileDecodeFunc(cb, dc, path);
389                                 break;
390                         } else if (plugin->streamDecodeFunc) {
391                                 ret = plugin->streamDecodeFunc(cb, dc, &inStream);
392                                 break;
393                         }
394                 }
395         }
397         if (ret < 0 || ret == DECODE_ERROR_UNKTYPE) {
398                 pathcpy_trunc(pc->erroredUrl, dc->utf8url);
399                 if (ret != DECODE_ERROR_UNKTYPE) {
400                         dc->error = DECODE_ERROR_FILE;
401                 } else {
402                         dc->error = DECODE_ERROR_UNKTYPE;
403                         closeInputStream(&inStream);
404                 }
405                 dc->stop = 0;
406                 dc->state = DECODE_STATE_STOP;
407         }
409         free(path);
412 static int decoderInit(PlayerControl * pc, OutputBuffer * cb,
413                        DecoderControl * dc)
415         int pid;
417         pid = decode_pid;
418         if (pid > 0) {
419                 kill(pid, SIGCONT);
420                 return 0;
421         }
423         blockSignals();
424         getPlayerData()->playerControl.decode_pid = 0;
425         decode_pid = fork();
427         if (decode_pid == 0) {
428                 /* CHILD */
429                 unblockSignals();
431                 while (1) {
432                         if (dc->cycleLogFiles) {
433                                 cycle_log_files();
434                                 dc->cycleLogFiles = 0;
435                         } else if (dc->start || dc->seek)
436                                 decodeStart(pc, cb, dc);
437                         else if (dc->stop) {
438                                 dc->state = DECODE_STATE_STOP;
439                                 dc->stop = 0;
440                         } else
441                                 my_usleep(10000);
442                 }
444                 exit(EXIT_SUCCESS);
445                 /* END OF CHILD */
446         } else if (decode_pid < 0) {
447                 unblockSignals();
448                 pathcpy_trunc(pc->erroredUrl, pc->utf8url);
449                 pc->error = PLAYER_ERROR_SYSTEM;
450                 return -1;
451         }
452         DEBUG("decoder PID: %d\n", decode_pid);
453         getPlayerData()->playerControl.decode_pid = decode_pid;
454         unblockSignals();
456         return 0;
459 static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int *previous,
460                            int *currentChunkSent, MetadataChunk * currentChunk)
462         if (cb->begin != cb->end) {
463                 int meta = cb->metaChunk[cb->begin];
464                 if (meta != *previous) {
465                         DEBUG("player: metadata change\n");
466                         if (meta >= 0 && cb->metaChunkSet[meta]) {
467                                 DEBUG("player: new metadata from decoder!\n");
468                                 memcpy(currentChunk,
469                                        cb->metadataChunks + meta,
470                                        sizeof(MetadataChunk));
471                                 *currentChunkSent = 0;
472                                 cb->metaChunkSet[meta] = 0;
473                         }
474                 }
475                 *previous = meta;
476         }
477         if (!(*currentChunkSent) && pc->metadataState ==
478             PLAYER_METADATA_STATE_WRITE) {
479                 MpdTag *tag = NULL;
481                 *currentChunkSent = 1;
483                 if ((tag = metadataChunkToMpdTagDup(currentChunk))) {
484                         sendMetadataToAudioDevice(tag);
485                         freeMpdTag(tag);
486                 }
488                 memcpy(&(pc->metadataChunk), currentChunk,
489                        sizeof(MetadataChunk));
490                 pc->metadataState = PLAYER_METADATA_STATE_READ;
491                 kill(getppid(), SIGUSR1);
492         }
495 static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
496                                   int *previous, int *currentChunkSent,
497                                   MetadataChunk * currentChunk, int to)
499         while (cb->begin != to) {
500                 handleMetadata(cb, pc, previous, currentChunkSent,
501                                currentChunk);
502                 if (cb->begin + 1 >= buffered_chunks) {
503                         cb->begin = 0;
504                 }
505                 else cb->begin++;
506         }
509 static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb)
511         int pause = 0;
512         int quit = 0;
513         int bbp = buffered_before_play;
514         int doCrossFade = 0;
515         int crossFadeChunks = 0;
516         int fadePosition;
517         int nextChunk = -1;
518         int test;
519         int decodeWaitedOn = 0;
520         char silence[CHUNK_SIZE];
521         double sizeToTime = 0.0;
522         int previousMetadataChunk = -1;
523         MetadataChunk currentMetadataChunk;
524         int currentChunkSent = 1;
525         int end;
526         int next = -1;
528         memset(silence, 0, CHUNK_SIZE);
530         if (waitOnDecode(pc, dc, cb, &decodeWaitedOn) < 0)
531                 return;
533         pc->elapsedTime = 0;
534         pc->state = PLAYER_STATE_PLAY;
535         pc->play = 0;
536         kill(getppid(), SIGUSR1);
538         while (decode_pid > 0 && 
539                cb->end - cb->begin < bbp &&
540                cb->end != buffered_chunks - 1 &&
541                dc->state != DECODE_STATE_STOP) {
542                 processDecodeInput();
543                 my_usleep(1000);
544         }
546         while (!quit) {
547                 processDecodeInput();
548                 handleDecodeStart();
549                 handleMetadata(cb, pc, &previousMetadataChunk,
550                                &currentChunkSent, &currentMetadataChunk);
551                 if (dc->state == DECODE_STATE_STOP &&
552                     pc->queueState == PLAYER_QUEUE_FULL &&
553                     pc->queueLockState == PLAYER_QUEUE_UNLOCKED) {
554                         next = cb->end;
555                         dc->start = 1;
556                         pc->queueState = PLAYER_QUEUE_DECODE;
557                         kill(getppid(), SIGUSR1);
558                 }
559                 if (next >= 0 && doCrossFade == 0 && !dc->start &&
560                     dc->state != DECODE_STATE_START) {
561                         nextChunk = -1;
562                         if (isCurrentAudioFormat(&(cb->audioFormat))) {
563                                 doCrossFade = 1;
564                                 crossFadeChunks =
565                                     calculateCrossFadeChunks(pc,
566                                                              &(cb->
567                                                                audioFormat));
568                                 if (!crossFadeChunks
569                                     || pc->crossFade >= dc->totalTime) {
570                                         doCrossFade = -1;
571                                 }
572                         } else
573                                 doCrossFade = -1;
574                 }
576                 /* copy these to local variables to prevent any potential
577                    race conditions and weirdness */
578                 end = cb->end;
580                 if (pause)
581                         my_usleep(10000);
582                 else if (cb->begin != end && cb->begin != next) {
583                         if (doCrossFade == 1 && next >= 0 &&
584                             ((next > cb->begin &&
585                               (fadePosition = next - cb->begin)
586                               <= crossFadeChunks) ||
587                              (cb->begin > next &&
588                               (fadePosition = next - cb->begin +
589                                buffered_chunks) <= crossFadeChunks))) {
590                                 if (nextChunk < 0) {
591                                         crossFadeChunks = fadePosition;
592                                 }
593                                 test = end;
594                                 if (end < cb->begin)
595                                         test += buffered_chunks;
596                                 nextChunk = cb->begin + crossFadeChunks;
597                                 if (nextChunk < test) {
598                                         if (nextChunk >= buffered_chunks) {
599                                                 nextChunk -= buffered_chunks;
600                                         }
601                                         pcm_mix(cb->chunks +
602                                                 cb->begin * CHUNK_SIZE,
603                                                 cb->chunks +
604                                                 nextChunk * CHUNK_SIZE,
605                                                 cb->chunkSize[cb->begin],
606                                                 cb->chunkSize[nextChunk],
607                                                 &(cb->audioFormat),
608                                                 ((float)fadePosition) /
609                                                 crossFadeChunks);
610                                         if (cb->chunkSize[nextChunk] >
611                                             cb->chunkSize[cb->begin]
612                                             ) {
613                                                 cb->chunkSize[cb->begin]
614                                                     = cb->chunkSize[nextChunk];
615                                         }
616                                 } else {
617                                         if (dc->state == DECODE_STATE_STOP) {
618                                                 doCrossFade = -1;
619                                         } else
620                                                 continue;
621                                 }
622                         }
623                         pc->elapsedTime = cb->times[cb->begin];
624                         pc->bitRate = cb->bitRate[cb->begin];
625                         pcm_volumeChange(cb->chunks + cb->begin *
626                                          CHUNK_SIZE,
627                                          cb->chunkSize[cb->begin],
628                                          &(cb->audioFormat),
629                                          pc->softwareVolume);
630                         if (playAudio(cb->chunks + cb->begin * CHUNK_SIZE,
631                                       cb->chunkSize[cb->begin]) < 0) {
632                                 quit = 1;
633                         }
634                         pc->totalPlayTime +=
635                             sizeToTime * cb->chunkSize[cb->begin];
636                         if (cb->begin + 1 >= buffered_chunks) {
637                                 cb->begin = 0;
638                         } else
639                                 cb->begin++;
640                 } else if (cb->begin != end && cb->begin == next) {
641                         if (doCrossFade == 1 && nextChunk >= 0) {
642                                 nextChunk = cb->begin + crossFadeChunks;
643                                 test = end;
644                                 if (end < cb->begin)
645                                         test += buffered_chunks;
646                                 if (nextChunk < test) {
647                                         if (nextChunk >= buffered_chunks) {
648                                                 nextChunk -= buffered_chunks;
649                                         }
650                                         advanceOutputBufferTo(cb, pc,
651                                                               &previousMetadataChunk,
652                                                               &currentChunkSent,
653                                                               &currentMetadataChunk,
654                                                               nextChunk);
655                                 }
656                         }
657                         while (pc->queueState == PLAYER_QUEUE_DECODE ||
658                                pc->queueLockState == PLAYER_QUEUE_LOCKED) {
659                                 processDecodeInput();
660                                 my_usleep(10000);
661                         }
662                         if (pc->queueState != PLAYER_QUEUE_PLAY) {
663                                 quit = 1;
664                                 break;
665                         } else {
666                                 next = -1;
667                                 if (waitOnDecode(pc, dc, cb, &decodeWaitedOn) <
668                                     0) {
669                                         return;
670                                 }
671                                 nextChunk = -1;
672                                 doCrossFade = 0;
673                                 crossFadeChunks = 0;
674                                 pc->queueState = PLAYER_QUEUE_EMPTY;
675                                 kill(getppid(), SIGUSR1);
676                         }
677                 } else if (decode_pid <= 0 ||
678                            (dc->state == DECODE_STATE_STOP && !dc->start)) {
679                         quit = 1;
680                         break;
681                 } else {
682                         /*DEBUG("waiting for decoded audio, play silence\n");*/
683                         if (playAudio(silence, CHUNK_SIZE) < 0)
684                                 quit = 1;
685                 }
686         }
688         quitDecode(pc, dc);
691 /* decode w/ buffering
692  * this will fork another process
693  * child process does decoding
694  * parent process does playing audio
695  */
696 void decode(void)
698         OutputBuffer *cb;
699         PlayerControl *pc;
700         DecoderControl *dc;
702         cb = &(getPlayerData()->buffer);
704         clearAllMetaChunkSets(cb);
705         cb->begin = 0;
706         cb->end = 0;
707         pc = &(getPlayerData()->playerControl);
708         dc = &(getPlayerData()->decoderControl);
709         dc->error = 0;
710         dc->seek = 0;
711         dc->stop = 0;
712         dc->start = 1;
714         if (decoderInit(pc, cb, dc) < 0)
715                 return;
717         decodeParent(pc, dc, cb);