decode.c 17.1 KB
Newer Older
Warren Dukes's avatar
Warren Dukes committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* the Music Player Daemon (MPD)
 * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
 * 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 "decode.h"
20

Warren Dukes's avatar
Warren Dukes committed
21 22 23 24 25 26 27
#include "player.h"
#include "playerData.h"
#include "utils.h"
#include "pcm_utils.h"
#include "audio.h"
#include "path.h"
#include "log.h"
28
#include "sig_handlers.h"
29
#include "ls.h"
30
#include "utf8.h"
Warren Dukes's avatar
Warren Dukes committed
31 32 33 34 35 36 37 38 39

#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

Warren Dukes's avatar
Warren Dukes committed
40
volatile int * volatile decode_pid = NULL;
Warren Dukes's avatar
Warren Dukes committed
41 42 43 44

void decodeSigHandler(int sig) {
	if(sig==SIGCHLD) {
		int status;
45
		if(decode_pid && *decode_pid==wait3(&status,WNOHANG,NULL)) {
46 47 48 49
			if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
					WTERMSIG(status)!=SIGINT) 
			{
				ERROR("decode process died from signal: %i\n",
Warren Dukes's avatar
Warren Dukes committed
50 51
						WTERMSIG(status));
			}
52
			*decode_pid = 0;
Warren Dukes's avatar
Warren Dukes committed
53 54 55
		}
	}
	else if(sig==SIGTERM) {
56 57 58 59
		if(decode_pid) {
			int pid = *decode_pid;
			if(pid>0) kill(pid,SIGTERM);
		}
60
		exit(EXIT_SUCCESS);
Warren Dukes's avatar
Warren Dukes committed
61 62 63 64
	}
}

void stopDecode(DecoderControl * dc) {
65
	if(decode_pid && *decode_pid>0 && 
66
			(dc->start || dc->state!=DECODE_STATE_STOP)) 
67
	{
Warren Dukes's avatar
Warren Dukes committed
68
		dc->stop = 1;
69
		while(decode_pid && *decode_pid>0 && dc->stop) my_usleep(10000);
Warren Dukes's avatar
Warren Dukes committed
70 71 72 73 74
	}
}

void quitDecode(PlayerControl * pc, DecoderControl * dc) {
	stopDecode(dc);
75
        pc->metadataState = PLAYER_METADATA_STATE_READ;
Warren Dukes's avatar
Warren Dukes committed
76
	pc->state = PLAYER_STATE_STOP;
77
        dc->seek = 0;
Warren Dukes's avatar
Warren Dukes committed
78 79 80 81 82 83 84
	pc->play = 0;
	pc->stop = 0;
	pc->pause = 0;
	kill(getppid(),SIGUSR1);
}

int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
85
	long chunks;
Warren Dukes's avatar
Warren Dukes committed
86 87 88 89 90 91

	if(pc->crossFade<=0) return 0;

	chunks = (af->sampleRate*af->bits*af->channels/8.0/CHUNK_SIZE);
	chunks = (chunks*pc->crossFade+0.5);

Warren Dukes's avatar
Warren Dukes committed
92 93
	if(chunks>(buffered_chunks-buffered_before_play)) {
		chunks = buffered_chunks-buffered_before_play;
Warren Dukes's avatar
Warren Dukes committed
94 95
	}

Warren Dukes's avatar
Warren Dukes committed
96 97
	if(chunks<0) chunks = 0;

98
	return (int)chunks;
Warren Dukes's avatar
Warren Dukes committed
99 100
}

101 102 103 104 105 106
#define playSilenceOrSleep() \
	if(isAudioDeviceOpen()) { \
		playAudio(silence, CHUNK_SIZE); \
	} \
	else my_usleep(10000);

107
#define handleDecodeStart() \
108 109 110 111 112 113
        if(decodeWaitedOn) { \
                if(dc->state!=DECODE_STATE_START &&  *decode_pid > 0 && \
                                dc->error==DECODE_ERROR_NOERROR) \
                { \
                        decodeWaitedOn = 0; \
	                if(openAudioDevice(&(cb->audioFormat))<0) { \
114 115 116
		                strncpy(pc->erroredUrl, pc->utf8url, \
                                                MAXPATHLEN); \
		                pc->erroredUrl[MAXPATHLEN] = '\0'; \
117 118 119 120 121 122 123 124
		                pc->error = PLAYER_ERROR_AUDIO; \
		                quitDecode(pc,dc); \
		                return; \
	                } \
	                pc->totalTime = dc->totalTime; \
	                pc->sampleRate = dc->audioFormat.sampleRate; \
	                pc->bits = dc->audioFormat.bits; \
	                pc->channels = dc->audioFormat.channels; \
125 126 127
			sizeToTime = 8.0/cb->audioFormat.bits/ \
					cb->audioFormat.channels/ \
					cb->audioFormat.sampleRate; \
128 129
                } \
                else if(dc->state!=DECODE_STATE_START || *decode_pid <= 0) { \
130 131
		        strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN); \
		        pc->erroredUrl[MAXPATHLEN] = '\0'; \
132
		        pc->error = PLAYER_ERROR_FILE; \
133 134
		        quitDecode(pc,dc); \
		        return; \
135 136
                } \
                else { \
137
			my_usleep(10000); \
138 139
                        continue; \
                } \
140 141 142 143 144
        }

int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
                int * decodeWaitedOn) 
{
145 146 147
        strncpy(pc->currentUrl, pc->utf8url, MAXPATHLEN);
        pc->currentUrl[MAXPATHLEN] = '\0';

148
	while(decode_pid && *decode_pid>0 && dc->start) my_usleep(10000);
Warren Dukes's avatar
Warren Dukes committed
149 150

	if(dc->start || dc->error!=DECODE_ERROR_NOERROR) {
151 152
		strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
		pc->erroredUrl[MAXPATHLEN] = '\0';
Warren Dukes's avatar
Warren Dukes committed
153 154 155 156 157
		pc->error = PLAYER_ERROR_FILE;
		quitDecode(pc,dc);
		return -1;
	}

158 159 160 161 162 163 164
        pc->totalTime = pc->fileTime;
        pc->elapsedTime = 0;
        pc->bitRate = 0;
        pc->sampleRate = 0;
        pc->bits = 0;
        pc->channels = 0;
        *decodeWaitedOn = 1;
Warren Dukes's avatar
Warren Dukes committed
165 166 167 168

	return 0;
}

169
int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
Warren Dukes's avatar
Warren Dukes committed
170
                int * decodeWaitedOn, int * next) 
171 172 173
{
        int ret = -1;

174
	if(decode_pid && *decode_pid>0) {
175
		if(dc->state==DECODE_STATE_STOP || dc->error || 
176
				strcmp(dc->utf8url, pc->utf8url)!=0) 
Warren Dukes's avatar
Warren Dukes committed
177 178
		{
			stopDecode(dc);
Warren Dukes's avatar
Warren Dukes committed
179
			*next = -1;
180
			cb->begin = 0;
Warren Dukes's avatar
Warren Dukes committed
181 182 183
			cb->end = 0;
			dc->error = 0;
			dc->start = 1;
184
			waitOnDecode(pc,dc,cb,decodeWaitedOn);
Warren Dukes's avatar
Warren Dukes committed
185
		}
186 187 188
		if(*decode_pid>0 && dc->state!=DECODE_STATE_STOP && 
                                dc->seekable) 
                {
Warren Dukes's avatar
Warren Dukes committed
189
			*next = -1;
Warren Dukes's avatar
Warren Dukes committed
190 191 192 193
			dc->seekWhere = pc->seekWhere > pc->totalTime-0.1 ?
						pc->totalTime-0.1 : 
						pc->seekWhere;
			dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere;
194
                        dc->seekError = 0;
Warren Dukes's avatar
Warren Dukes committed
195
			dc->seek = 1;
196 197 198 199 200
                        while(*decode_pid>0 && dc->seek) my_usleep(10000);
                        if(!dc->seekError) {
                                pc->elapsedTime = dc->seekWhere;
                                ret = 0;
                        }
Warren Dukes's avatar
Warren Dukes committed
201 202 203
		}
	}
	pc->seek = 0;
204 205

        return ret;
Warren Dukes's avatar
Warren Dukes committed
206 207 208
}

#define processDecodeInput() \
209 210 211 212
        if(pc->cycleLogFiles) { \
                myfprintfCloseAndOpenLogFile(); \
                pc->cycleLogFiles = 0; \
        } \
Warren Dukes's avatar
Warren Dukes committed
213 214 215 216 217 218 219 220 221 222
	if(pc->lockQueue) { \
		pc->queueLockState = PLAYER_QUEUE_LOCKED; \
		pc->lockQueue = 0; \
	} \
	if(pc->unlockQueue) { \
		pc->queueLockState = PLAYER_QUEUE_UNLOCKED; \
		pc->unlockQueue = 0; \
	} \
	if(pc->pause) { \
		pause = !pause; \
223
		if(pause) pc->state = PLAYER_STATE_PAUSE; \
224
		else { \
225
			if(openAudioDevice(NULL)<0) { \
226 227 228
				strncpy(pc->erroredUrl, pc->utf8url, \
                                                MAXPATHLEN); \
				pc->erroredUrl[MAXPATHLEN] = '\0'; \
229 230 231 232 233 234
				pc->error = PLAYER_ERROR_AUDIO; \
				quitDecode(pc,dc); \
				return; \
			} \
			pc->state = PLAYER_STATE_PLAY; \
		} \
Warren Dukes's avatar
Warren Dukes committed
235 236
		pc->pause = 0; \
		kill(getppid(),SIGUSR1); \
237
		if(pause) closeAudioDevice(); \
Warren Dukes's avatar
Warren Dukes committed
238 239
	} \
	if(pc->seek) { \
Warren Dukes's avatar
Warren Dukes committed
240
		if(decodeSeek(pc,dc,cb,&decodeWaitedOn,&next) == 0) { \
241 242
		        doCrossFade = 0; \
		        nextChunk =  -1; \
243
                        bbp = 0; \
244
                } \
Warren Dukes's avatar
Warren Dukes committed
245 246 247 248 249 250
	} \
	if(pc->stop) { \
		quitDecode(pc,dc); \
		return; \
	}

251 252 253
void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
        int ret;
        InputStream inStream;
254
        InputPlugin * plugin = NULL;
255
        char * path;
256

257
        if(isRemoteUrl(pc->utf8url)) {
258
                path = utf8StrToLatin1Dup(pc->utf8url);
259
        }
260 261 262 263 264 265 266 267
	else path = strdup(rmp2amp(utf8ToFsCharset(pc->utf8url)));

	if(!path) {
		dc->error = DECODE_ERROR_FILE;
		dc->state = DECODE_STATE_STOP;
		dc->start = 0;
                return;
	}
268

269
	copyMpdTagToOutputBuffer(cb, NULL);
270 271 272

        strncpy(dc->utf8url, pc->utf8url, MAXPATHLEN);
	dc->utf8url[MAXPATHLEN] = '\0';
Warren Dukes's avatar
Warren Dukes committed
273

274
        if(openInputStream(&inStream, path) < 0) {
275 276
		dc->error = DECODE_ERROR_FILE;
		dc->state = DECODE_STATE_STOP;
277 278
		dc->start = 0;
		free(path);
279 280
                return;
        }
Warren Dukes's avatar
Warren Dukes committed
281

282
        dc->seekable = inStream.seekable;
283 284 285 286
        dc->state = DECODE_STATE_START;
	dc->start = 0;

        while(!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
287
                        && !dc->stop);
288 289 290 291

        if(dc->stop) {
                dc->state = DECODE_STATE_STOP;
                dc->stop = 0;
292
		free(path);
293 294
                return;
        }
295

Warren Dukes's avatar
Warren Dukes committed
296
        /*if(inStream.metaName) {
297
		MpdTag * tag = newMpdTag();
Warren Dukes's avatar
Warren Dukes committed
298
		tag->name = strdup(inStream.metaName);
299 300
		copyMpdTagToOutputBuffer(cb, tag);
		freeMpdTag(tag);
Warren Dukes's avatar
Warren Dukes committed
301
        }*/
302 303

	/* reset Metadata in OutputBuffer */
304

Warren Dukes's avatar
Warren Dukes committed
305
        ret = DECODE_ERROR_UNKTYPE;
306
	if(isRemoteUrl(dc->utf8url)) {
Warren Dukes's avatar
Warren Dukes committed
307
		cb->acceptMetadata = 1;
308
		plugin = getInputPluginFromMimeType(inStream.mime);
Warren Dukes's avatar
Warren Dukes committed
309
                if(plugin == NULL) {
310 311
                        plugin = getInputPluginFromSuffix(
                                        getSuffix(dc->utf8url));
312
                }
313 314 315 316 317
                /* this is needed for bastard streams that don't have a suffix
                                or set the mimeType */
                if(plugin == NULL) {
                        plugin = getInputPluginFromName("mp3");
                }
Warren Dukes's avatar
Warren Dukes committed
318 319
                if(plugin && (plugin->streamTypes & INPUT_PLUGIN_STREAM_URL) &&
                                plugin->streamDecodeFunc) 
320
                {
Warren Dukes's avatar
Warren Dukes committed
321
                        ret = plugin->streamDecodeFunc(cb, dc, &inStream);
322 323
                }
	}
Warren Dukes's avatar
Warren Dukes committed
324
        else {
Warren Dukes's avatar
Warren Dukes committed
325
		cb->acceptMetadata = 0;
326
                plugin = getInputPluginFromSuffix(getSuffix(dc->utf8url));
Warren Dukes's avatar
Warren Dukes committed
327 328 329 330 331 332 333 334
                if(plugin && (plugin->streamTypes && INPUT_PLUGIN_STREAM_FILE))
                {
                        if(plugin->streamDecodeFunc) {
                                ret = plugin->streamDecodeFunc(cb, dc, 
                                                &inStream);
                        }
                        else if(plugin->fileDecodeFunc) {
                                closeInputStream(&inStream);
335
                                ret = plugin->fileDecodeFunc(cb, dc, path);
Warren Dukes's avatar
Warren Dukes committed
336 337 338 339
                        }
                }
        }

340
	if(ret<0 || ret == DECODE_ERROR_UNKTYPE) {
341 342
		strncpy(pc->erroredUrl, dc->utf8url, MAXPATHLEN);
		pc->erroredUrl[MAXPATHLEN] = '\0';
343
		if(ret != DECODE_ERROR_UNKTYPE) dc->error = DECODE_ERROR_FILE;
344 345 346 347
                else {
                        dc->error = DECODE_ERROR_UNKTYPE;
                        closeInputStream(&inStream);
                }
348 349 350
		dc->stop = 0;
		dc->state = DECODE_STATE_STOP;
	}
351 352

	free(path);
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
}

int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
			
	int pid;
	decode_pid = &(pc->decode_pid);

	blockSignals();
	pid = fork();

	if(pid==0) {
		/* CHILD */
		unblockSignals();

		while(1) {
368 369 370 371
                        if(dc->cycleLogFiles) {
                                myfprintfCloseAndOpenLogFile();
                                dc->cycleLogFiles = 0;
                        }
372
			else if(dc->start || dc->seek) decodeStart(pc, cb, dc);
373 374 375 376
			else if(dc->stop) {
				dc->state = DECODE_STATE_STOP;
				dc->stop = 0;
			}
377
			else my_usleep(10000);
Warren Dukes's avatar
Warren Dukes committed
378 379
		}

380
		exit(EXIT_SUCCESS);
Warren Dukes's avatar
Warren Dukes committed
381 382
		/* END OF CHILD */
	}
383
	else if(pid<0) {
384
		unblockSignals();
385 386
		strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
		pc->erroredUrl[MAXPATHLEN] = '\0';
Warren Dukes's avatar
Warren Dukes committed
387 388 389
		pc->error = PLAYER_ERROR_SYSTEM;
		return -1;
	}
390 391 392

	*decode_pid = pid;
	unblockSignals();
Warren Dukes's avatar
Warren Dukes committed
393 394 395 396

	return 0;
}

397 398 399
void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int * previous,
		int * currentChunkSent, MetadataChunk * currentChunk) 
{
400
	if(cb->begin!=cb->end) {
401
		int meta = cb->metaChunk[cb->begin];
402
		if( meta != *previous ) {
403
			DEBUG("player: metadata change\n");
404
			if( meta >= 0 && cb->metaChunkSet[meta]) {
405
				DEBUG("player: new metadata from decoder!\n");
406
				memcpy(currentChunk, 
407 408
					cb->metadataChunks+meta,
					sizeof(MetadataChunk));
409
				*currentChunkSent = 0;
Warren Dukes's avatar
Warren Dukes committed
410
				cb->metaChunkSet[meta] = 0;
411 412
			}
		}
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
		*previous = meta;
	}
	if(!(*currentChunkSent) && pc->metadataState == 
			PLAYER_METADATA_STATE_WRITE)
	{
		*currentChunkSent = 1;
		memcpy(&(pc->metadataChunk), currentChunk, 
				sizeof(MetadataChunk));
		pc->metadataState = PLAYER_METADATA_STATE_READ;
		kill(getppid(), SIGUSR1);
	}
}

void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc, 
	int * previous, int * currentChunkSent, MetadataChunk * currentChunk,
	int to) 
{
	while(cb->begin!=to) {
		handleMetadata(cb, pc, previous, currentChunkSent, 
				currentChunk);
		cb->begin++;
		if(cb->begin>=buffered_chunks) {
			cb->begin = 0;
		}
437
	}
Warren Dukes's avatar
Warren Dukes committed
438 439
}

440 441 442 443 444 445 446 447 448 449 450
void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
	int pause = 0;
	int quit = 0;
	int bbp = buffered_before_play;
	int doCrossFade = 0;
	int crossFadeChunks = 0;
	int fadePosition;
	int nextChunk = -1;
	int test;
        int decodeWaitedOn = 0;
	char silence[CHUNK_SIZE];
451
	double sizeToTime = 0.0;
452 453 454
	int previousMetadataChunk = -1;
	MetadataChunk currentMetadataChunk;
	int currentChunkSent = 1;
Warren Dukes's avatar
Warren Dukes committed
455 456
	int end;
	int next = -1;
Warren Dukes's avatar
Warren Dukes committed
457

458
	memset(silence,0,CHUNK_SIZE);
Warren Dukes's avatar
Warren Dukes committed
459

460
	if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) return;
Warren Dukes's avatar
Warren Dukes committed
461

462 463 464
	pc->state = PLAYER_STATE_PLAY;
	pc->play = 0;
	kill(getppid(),SIGUSR1);
465

466 467
	while(*decode_pid>0 && cb->end-cb->begin<bbp && 
				cb->end!=buffered_chunks-1 &&
468 469 470 471
				dc->state!=DECODE_STATE_STOP) 
	{
		processDecodeInput();
		if(quit) return;
472
		playSilenceOrSleep();
Warren Dukes's avatar
Warren Dukes committed
473 474
	}

475 476 477
	while(!quit) {
		processDecodeInput();
                handleDecodeStart();
478 479
		handleMetadata(cb, pc, &previousMetadataChunk, 
				&currentChunkSent, &currentMetadataChunk);
480 481 482
		if(dc->state==DECODE_STATE_STOP && 
			pc->queueState==PLAYER_QUEUE_FULL &&
			pc->queueLockState==PLAYER_QUEUE_UNLOCKED) 
Warren Dukes's avatar
Warren Dukes committed
483
		{
Warren Dukes's avatar
Warren Dukes committed
484
			next = cb->end;
485 486 487
			dc->start = 1;
			pc->queueState = PLAYER_QUEUE_DECODE;
			kill(getppid(),SIGUSR1);
Warren Dukes's avatar
Warren Dukes committed
488
		}
489 490 491
		if(next>=0 && doCrossFade==0 && !dc->start && 
				dc->state!=DECODE_STATE_START) 
		{
492 493 494 495 496 497 498
			nextChunk = -1;
			if(isCurrentAudioFormat(&(cb->audioFormat))) {
				doCrossFade = 1;
				crossFadeChunks = 
				calculateCrossFadeChunks(pc,
                                        &(cb->audioFormat));
				if(!crossFadeChunks ||
499
						pc->crossFade>=dc->totalTime) 
500 501
				{
					doCrossFade = -1;
Warren Dukes's avatar
Warren Dukes committed
502 503
				}
			}
504 505
			else doCrossFade = -1;
		}
Warren Dukes's avatar
Warren Dukes committed
506 507 508 509 510

		/* copy thse to locale variables to prevent any potential
			race conditions and weirdness */
		end = cb->end;

511
		if(pause) my_usleep(10000);
Warren Dukes's avatar
Warren Dukes committed
512 513 514 515
		else if(cb->begin!=end && cb->begin!=next) {
			if(doCrossFade==1 && next>=0 &&
					((next>cb->begin && 
					(fadePosition=next-cb->begin)
Warren Dukes's avatar
Warren Dukes committed
516
					<=crossFadeChunks) || 
Warren Dukes's avatar
Warren Dukes committed
517 518
					(cb->begin>next &&
					(fadePosition=next-cb->begin+
Warren Dukes's avatar
Warren Dukes committed
519
					buffered_chunks)<=crossFadeChunks)))
520 521 522 523
			{
				if(nextChunk<0) {
					crossFadeChunks = fadePosition;
				}
Warren Dukes's avatar
Warren Dukes committed
524 525
				test = end;
				if(end < cb->begin) test+=buffered_chunks;
526 527 528 529 530
				nextChunk = cb->begin+crossFadeChunks;
				if(nextChunk<test) {
					if(nextChunk>=buffered_chunks)
					{
						nextChunk -=  buffered_chunks;  
Warren Dukes's avatar
Warren Dukes committed
531
					}
532
					pcm_mix(cb->chunks+cb->begin*CHUNK_SIZE,
Warren Dukes's avatar
Warren Dukes committed
533 534 535 536 537 538
							cb->chunks+nextChunk*
							CHUNK_SIZE,
							cb->chunkSize[
								cb->begin],
							cb->chunkSize[
								nextChunk],
539
							&(cb->audioFormat),
Warren Dukes's avatar
Warren Dukes committed
540 541
							((float)fadePosition)/
							crossFadeChunks);
542
					if(cb->chunkSize[nextChunk]>
Warren Dukes's avatar
Warren Dukes committed
543 544
							cb->chunkSize[cb->begin]
							)
545 546
					{
						cb->chunkSize[cb->begin]
Warren Dukes's avatar
Warren Dukes committed
547 548 549
								= cb->chunkSize
								[nextChunk];
					}
Warren Dukes's avatar
Warren Dukes committed
550
				}
551 552 553 554 555 556
				else {
					if(dc->state==DECODE_STATE_STOP)
					{
						doCrossFade = -1;
					}
					else continue;
Warren Dukes's avatar
Warren Dukes committed
557 558
				}
			}
559
			pc->elapsedTime = cb->times[cb->begin];
560 561 562 563 564 565 566 567 568 569 570
			pc->bitRate = cb->bitRate[cb->begin];
			pcm_volumeChange(cb->chunks+cb->begin*
				CHUNK_SIZE,
				cb->chunkSize[cb->begin],
				&(cb->audioFormat),
				pc->softwareVolume);
			if(playAudio(cb->chunks+cb->begin*CHUNK_SIZE,
				cb->chunkSize[cb->begin])<0) 
			{
				quit = 1;
			}
571
			pc->totalPlayTime+= sizeToTime*cb->chunkSize[cb->begin];
Warren Dukes's avatar
Warren Dukes committed
572
			if( cb->begin+1 >= buffered_chunks ) {
573 574
				cb->begin = 0;
			}
Warren Dukes's avatar
Warren Dukes committed
575
			else cb->begin++;
576
		}
Warren Dukes's avatar
Warren Dukes committed
577
		else if(next==cb->begin) {
578 579 580
			if(doCrossFade==1 && nextChunk>=0) {
				nextChunk = cb->begin+crossFadeChunks;
				test = cb->end;
Warren Dukes's avatar
Warren Dukes committed
581
				if(end < cb->begin) test+=buffered_chunks;
582 583 584 585
				if(nextChunk<test) {
					if(nextChunk>=buffered_chunks)
					{
						nextChunk -= buffered_chunks;
Warren Dukes's avatar
Warren Dukes committed
586
					}
587 588 589 590 591
					advanceOutputBufferTo(cb, pc, 
						&previousMetadataChunk,
						&currentChunkSent, 
						&currentMetadataChunk, 
						nextChunk);
592
				}	
Warren Dukes's avatar
Warren Dukes committed
593
			}
594 595
			while(pc->queueState==PLAYER_QUEUE_DECODE ||
					pc->queueLockState==PLAYER_QUEUE_LOCKED)
Warren Dukes's avatar
Warren Dukes committed
596
			{
597 598 599 600 601
				processDecodeInput();
				if(quit) {
					quitDecode(pc,dc);
					return;
				}
602
				my_usleep(10000);
603 604
			}
			if(pc->queueState!=PLAYER_QUEUE_PLAY) {
Warren Dukes's avatar
Warren Dukes committed
605 606 607
				quit = 1;
				break;
			}
608
			else {
Warren Dukes's avatar
Warren Dukes committed
609
				next = -1;
610 611 612 613 614 615 616 617
				if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) {
                                        return;
                                }
				nextChunk = -1;
				doCrossFade = 0;
				crossFadeChunks = 0;
				pc->queueState = PLAYER_QUEUE_EMPTY;
				kill(getppid(),SIGUSR1);
618
			}
619 620 621 622 623 624
		}
		else if(*decode_pid<=0 || 
				(dc->state==DECODE_STATE_STOP && !dc->start)) 
		{
			quit = 1;
			break;
Warren Dukes's avatar
Warren Dukes committed
625
		}
626 627 628 629
		else {
			if(playAudio(silence, CHUNK_SIZE) < 0) quit = 1;
		}
	}
Warren Dukes's avatar
Warren Dukes committed
630

631 632 633 634 635 636 637 638 639 640 641 642 643 644
	quitDecode(pc,dc);
}

/* decode w/ buffering
 * this will fork another process
 * child process does decoding
 * parent process does playing audio
 */
void decode() {
	OutputBuffer * cb;
	PlayerControl * pc;
	DecoderControl * dc;

	cb = &(getPlayerData()->buffer);
Warren Dukes's avatar
Warren Dukes committed
645

646
	clearAllMetaChunkSets(cb);
647 648 649 650 651
	cb->begin = 0;
	cb->end = 0;
	pc = &(getPlayerData()->playerControl);
	dc = &(getPlayerData()->decoderControl);
	dc->error = 0;
652 653 654
        dc->seek = 0;
        dc->stop = 0;
	dc->start = 1;
655
        
656 657
	if(decode_pid==NULL || *decode_pid<=0) {
		if(decoderInit(pc,cb,dc)<0) return;
Warren Dukes's avatar
Warren Dukes committed
658 659
	}

660
        decodeParent(pc, dc, cb);
Warren Dukes's avatar
Warren Dukes committed
661
}