decode.c 17.2 KB
Newer Older
Warren Dukes's avatar
Warren Dukes committed
1
/* the Music Player Daemon (MPD)
2
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
Warren Dukes's avatar
Warren Dukes committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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>

40
static int decode_pid;
Warren Dukes's avatar
Warren Dukes committed
41

Avuton Olrich's avatar
Avuton Olrich committed
42 43 44
void decodeSigHandler(int sig, siginfo_t * si, void *v)
{
	if (sig == SIGCHLD) {
Warren Dukes's avatar
Warren Dukes committed
45
		int status;
Avuton Olrich's avatar
Avuton Olrich committed
46 47 48
		if (decode_pid == wait3(&status, WNOHANG, NULL)) {
			if (WIFSIGNALED(status)) {
				if (WTERMSIG(status) != SIGTERM) {
49
					ERROR("decode process died from "
Avuton Olrich's avatar
Avuton Olrich committed
50
					      "signal: %i\n", WTERMSIG(status));
51
				}
Warren Dukes's avatar
Warren Dukes committed
52
			}
53 54
			decode_pid = 0;
			getPlayerData()->playerControl.decode_pid = 0;
Warren Dukes's avatar
Warren Dukes committed
55
		}
Avuton Olrich's avatar
Avuton Olrich committed
56
	} else if (sig == SIGTERM) {
57
		int pid = decode_pid;
Avuton Olrich's avatar
Avuton Olrich committed
58
		if (pid > 0) {
59
			DEBUG("player (or child) got SIGTERM\n");
Avuton Olrich's avatar
Avuton Olrich committed
60 61 62
			kill(pid, SIGTERM);
		} else
			DEBUG("decoder (or child) got SIGTERM\n");
63
		exit(EXIT_SUCCESS);
Warren Dukes's avatar
Warren Dukes committed
64 65 66
	}
}

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

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

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

Avuton Olrich's avatar
Avuton Olrich committed
91 92
	if (pc->crossFade <= 0)
		return 0;
Warren Dukes's avatar
Warren Dukes committed
93

Avuton Olrich's avatar
Avuton Olrich committed
94 95
	chunks = (af->sampleRate * af->bits * af->channels / 8.0 / CHUNK_SIZE);
	chunks = (chunks * pc->crossFade + 0.5);
Warren Dukes's avatar
Warren Dukes committed
96

Avuton Olrich's avatar
Avuton Olrich committed
97 98
	if (chunks > (buffered_chunks - buffered_before_play)) {
		chunks = buffered_chunks - buffered_before_play;
Warren Dukes's avatar
Warren Dukes committed
99 100
	}

Avuton Olrich's avatar
Avuton Olrich committed
101 102
	if (chunks < 0)
		chunks = 0;
Warren Dukes's avatar
Warren Dukes committed
103

104
	return (int)chunks;
Warren Dukes's avatar
Warren Dukes committed
105 106
}

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) { \
Eric Wong's avatar
Eric Wong committed
114
				pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
115
				pc->error = PLAYER_ERROR_AUDIO; \
116
				ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
117 118
				quitDecode(pc,dc); \
				return; \
119
	                } \
120 121 122 123
			pc->totalTime = dc->totalTime; \
			pc->sampleRate = dc->audioFormat.sampleRate; \
			pc->bits = dc->audioFormat.bits; \
			pc->channels = dc->audioFormat.channels; \
124 125 126
			sizeToTime = 8.0/cb->audioFormat.bits/ \
					cb->audioFormat.channels/ \
					cb->audioFormat.sampleRate; \
127
                } \
128
                else if(dc->state!=DECODE_STATE_START || decode_pid <= 0) { \
Eric Wong's avatar
Eric Wong committed
129
			pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
130
		        pc->error = PLAYER_ERROR_FILE; \
131 132
		        quitDecode(pc,dc); \
		        return; \
133 134
                } \
                else { \
135
			my_usleep(10000); \
136
                        continue; \
137 138
		} \
	}
139

Avuton Olrich's avatar
Avuton Olrich committed
140 141
static int waitOnDecode(PlayerControl * pc, DecoderControl * dc,
			OutputBuffer * cb, int *decodeWaitedOn)
142
{
Avuton Olrich's avatar
Avuton Olrich committed
143
	MpdTag *tag = NULL;
Eric Wong's avatar
Eric Wong committed
144
	pathcpy_trunc(pc->currentUrl, pc->utf8url);
145

Avuton Olrich's avatar
Avuton Olrich committed
146 147
	while (decode_pid > 0 && dc->start)
		my_usleep(10000);
Warren Dukes's avatar
Warren Dukes committed
148

Avuton Olrich's avatar
Avuton Olrich committed
149
	if (dc->start || dc->error != DECODE_ERROR_NOERROR) {
Eric Wong's avatar
Eric Wong committed
150
		pathcpy_trunc(pc->erroredUrl, pc->utf8url);
Warren Dukes's avatar
Warren Dukes committed
151
		pc->error = PLAYER_ERROR_FILE;
Avuton Olrich's avatar
Avuton Olrich committed
152
		quitDecode(pc, dc);
Warren Dukes's avatar
Warren Dukes committed
153 154 155
		return -1;
	}

Avuton Olrich's avatar
Avuton Olrich committed
156
	if ((tag = metadataChunkToMpdTagDup(&(pc->fileMetadataChunk)))) {
Warren Dukes's avatar
Warren Dukes committed
157 158 159
		sendMetadataToAudioDevice(tag);
		freeMpdTag(tag);
	}
160

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

	return 0;
}

Avuton Olrich's avatar
Avuton Olrich committed
171 172
static int decodeSeek(PlayerControl * pc, DecoderControl * dc,
		      OutputBuffer * cb, int *decodeWaitedOn, int *next)
173
{
174
	int ret = -1;
175

Avuton Olrich's avatar
Avuton Olrich committed
176 177 178
	if (decode_pid > 0) {
		if (dc->state == DECODE_STATE_STOP || dc->error ||
		    strcmp(dc->utf8url, pc->utf8url) != 0) {
Warren Dukes's avatar
Warren Dukes committed
179
			stopDecode(dc);
Warren Dukes's avatar
Warren Dukes committed
180
			*next = -1;
181
			cb->begin = 0;
Warren Dukes's avatar
Warren Dukes committed
182 183 184
			cb->end = 0;
			dc->error = 0;
			dc->start = 1;
Avuton Olrich's avatar
Avuton Olrich committed
185
			waitOnDecode(pc, dc, cb, decodeWaitedOn);
Warren Dukes's avatar
Warren Dukes committed
186
		}
Avuton Olrich's avatar
Avuton Olrich committed
187 188
		if (decode_pid > 0 && dc->state != DECODE_STATE_STOP &&
		    dc->seekable) {
Warren Dukes's avatar
Warren Dukes committed
189
			*next = -1;
Avuton Olrich's avatar
Avuton Olrich committed
190 191
			dc->seekWhere = pc->seekWhere > pc->totalTime - 0.1 ?
			    pc->totalTime - 0.1 : pc->seekWhere;
Warren Dukes's avatar
Warren Dukes committed
192
			dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere;
193
			dc->seekError = 0;
Warren Dukes's avatar
Warren Dukes committed
194
			dc->seek = 1;
Avuton Olrich's avatar
Avuton Olrich committed
195 196 197
			while (decode_pid > 0 && dc->seek)
				my_usleep(10000);
			if (!dc->seekError) {
198 199 200
				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
        if(pc->cycleLogFiles) { \
Eric Wong's avatar
Eric Wong committed
210
                cycle_log_files(); \
211 212
                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 226
			if (openAudioDevice(NULL) >= 0) pc->state = PLAYER_STATE_PLAY; \
			else { \
Eric Wong's avatar
Eric Wong committed
227
				pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
228
				pc->error = PLAYER_ERROR_AUDIO; \
229
				ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
230
				pause = -1; \
231 232
			} \
		} \
Warren Dukes's avatar
Warren Dukes committed
233
		pc->pause = 0; \
234
		kill(getppid(), SIGUSR1); \
235 236
		if (pause == -1) pause = 1; \
		else if (pause) { \
237 238 239
			dropBufferedAudio(); \
			closeAudioDevice(); \
		} \
Warren Dukes's avatar
Warren Dukes committed
240 241
	} \
	if(pc->seek) { \
242
		dropBufferedAudio(); \
Warren Dukes's avatar
Warren Dukes committed
243
		if(decodeSeek(pc,dc,cb,&decodeWaitedOn,&next) == 0) { \
244 245
		        doCrossFade = 0; \
		        nextChunk =  -1; \
246
                        bbp = 0; \
247
                } \
Warren Dukes's avatar
Warren Dukes committed
248 249
	} \
	if(pc->stop) { \
250
		dropBufferedAudio(); \
Warren Dukes's avatar
Warren Dukes committed
251 252 253 254
		quitDecode(pc,dc); \
		return; \
	}

Avuton Olrich's avatar
Avuton Olrich committed
255 256 257
static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
			DecoderControl * dc)
{
258 259
	int ret;
	InputStream inStream;
Avuton Olrich's avatar
Avuton Olrich committed
260 261
	InputPlugin *plugin = NULL;
	char *path;
262

263
	if (isRemoteUrl(pc->utf8url))
264
		path = utf8StrToLatin1Dup(pc->utf8url);
265
	else
266
		path = xstrdup(rmp2amp(utf8ToFsCharset(pc->utf8url)));
267

Avuton Olrich's avatar
Avuton Olrich committed
268
	if (!path) {
269 270 271
		dc->error = DECODE_ERROR_FILE;
		dc->state = DECODE_STATE_STOP;
		dc->start = 0;
272
		return;
273
	}
274

275
	copyMpdTagToOutputBuffer(cb, NULL);
276

Eric Wong's avatar
Eric Wong committed
277
	pathcpy_trunc(dc->utf8url, pc->utf8url);
Warren Dukes's avatar
Warren Dukes committed
278

Avuton Olrich's avatar
Avuton Olrich committed
279
	if (openInputStream(&inStream, path) < 0) {
280 281
		dc->error = DECODE_ERROR_FILE;
		dc->state = DECODE_STATE_STOP;
282 283
		dc->start = 0;
		free(path);
284 285
		return;
	}
Warren Dukes's avatar
Warren Dukes committed
286

287
	dc->state = DECODE_STATE_START;
288 289
	dc->start = 0;

Avuton Olrich's avatar
Avuton Olrich committed
290 291
	while (!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
	       && !dc->stop) {
292 293 294
		/* sleep so we don't consume 100% of the cpu */
		my_usleep(1000);
	}
295

296 297 298
	/* for http streams, seekable is determined in bufferInputStream */
	dc->seekable = inStream.seekable;
        
Avuton Olrich's avatar
Avuton Olrich committed
299
	if (dc->stop) {
300 301
		dc->state = DECODE_STATE_STOP;
		dc->stop = 0;
302
		free(path);
303 304
		return;
	}
305

Avuton Olrich's avatar
Avuton Olrich committed
306 307
	/*if(inStream.metaName) {
	   MpdTag * tag = newMpdTag();
308
	   tag->name = xstrdup(inStream.metaName);
Avuton Olrich's avatar
Avuton Olrich committed
309 310 311
	   copyMpdTagToOutputBuffer(cb, tag);
	   freeMpdTag(tag);
	   } */
312 313

	/* reset Metadata in OutputBuffer */
314

Avuton Olrich's avatar
Avuton Olrich committed
315 316
	ret = DECODE_ERROR_UNKTYPE;
	if (isRemoteUrl(dc->utf8url)) {
317
		unsigned int next = 0;
Warren Dukes's avatar
Warren Dukes committed
318
		cb->acceptMetadata = 1;
319 320

		/* first we try mime types: */
Avuton Olrich's avatar
Avuton Olrich committed
321 322 323
		while (ret
		       && (plugin =
			   getInputPluginFromMimeType(inStream.mime, next++))) {
324 325 326 327
			if (!plugin->streamDecodeFunc)
				continue;
			if (!(plugin->streamTypes & INPUT_PLUGIN_STREAM_URL))
				continue;
Avuton Olrich's avatar
Avuton Olrich committed
328 329
			if (plugin->tryDecodeFunc
			    && !plugin->tryDecodeFunc(&inStream))
330 331 332 333 334 335
				continue;
			ret = plugin->streamDecodeFunc(cb, dc, &inStream);
			break;
		}

		/* if that fails, try suffix matching the URL: */
Avuton Olrich's avatar
Avuton Olrich committed
336 337
		if (plugin == NULL) {
			char *s = getSuffix(dc->utf8url);
338
			next = 0;
Avuton Olrich's avatar
Avuton Olrich committed
339 340 341
			while (ret
			       && (plugin =
				   getInputPluginFromSuffix(s, next++))) {
342 343
				if (!plugin->streamDecodeFunc)
					continue;
Avuton Olrich's avatar
Avuton Olrich committed
344 345
				if (!(plugin->streamTypes &
				      INPUT_PLUGIN_STREAM_URL))
346
					continue;
Avuton Olrich's avatar
Avuton Olrich committed
347 348
				if (plugin->tryDecodeFunc &&
				    !plugin->tryDecodeFunc(&inStream))
349
					continue;
Avuton Olrich's avatar
Avuton Olrich committed
350 351
				ret =
				    plugin->streamDecodeFunc(cb, dc, &inStream);
352 353
				break;
			}
354
		}
355
		/* fallback to mp3: */
356
		/* this is needed for bastard streams that don't have a suffix
Avuton Olrich's avatar
Avuton Olrich committed
357 358
		   or set the mimeType */
		if (plugin == NULL) {
359 360
			/* we already know our mp3Plugin supports streams, no
			 * need to check for stream{Types,DecodeFunc} */
361
			if ((plugin = getInputPluginFromName("mp3")))
362
				ret = plugin->streamDecodeFunc(cb, dc,
Avuton Olrich's avatar
Avuton Olrich committed
363
							       &inStream);
364
		}
Avuton Olrich's avatar
Avuton Olrich committed
365
	} else {
366
		unsigned int next = 0;
Avuton Olrich's avatar
Avuton Olrich committed
367
		char *s = getSuffix(dc->utf8url);
Warren Dukes's avatar
Warren Dukes committed
368
		cb->acceptMetadata = 0;
369
		while (ret && (plugin = getInputPluginFromSuffix(s, next++))) {
Avuton Olrich's avatar
Avuton Olrich committed
370
			if (!plugin->streamTypes & INPUT_PLUGIN_STREAM_FILE)
371
				continue;
Avuton Olrich's avatar
Avuton Olrich committed
372 373
			if (plugin->tryDecodeFunc
			    && !plugin->tryDecodeFunc(&inStream))
374
				continue;
Avuton Olrich's avatar
Avuton Olrich committed
375 376 377 378

			if (plugin->streamDecodeFunc) {
				ret =
				    plugin->streamDecodeFunc(cb, dc, &inStream);
379
				break;
Avuton Olrich's avatar
Avuton Olrich committed
380
			} else if (plugin->fileDecodeFunc) {
381
				closeInputStream(&inStream);
Avuton Olrich's avatar
Avuton Olrich committed
382
				ret = plugin->fileDecodeFunc(cb, dc, path);
383 384
			}
		}
Avuton Olrich's avatar
Avuton Olrich committed
385
	}
Warren Dukes's avatar
Warren Dukes committed
386

Avuton Olrich's avatar
Avuton Olrich committed
387
	if (ret < 0 || ret == DECODE_ERROR_UNKTYPE) {
Eric Wong's avatar
Eric Wong committed
388
		pathcpy_trunc(pc->erroredUrl, dc->utf8url);
Avuton Olrich's avatar
Avuton Olrich committed
389 390
		if (ret != DECODE_ERROR_UNKTYPE)
			dc->error = DECODE_ERROR_FILE;
391 392 393 394
		else {
			dc->error = DECODE_ERROR_UNKTYPE;
			closeInputStream(&inStream);
		}
395 396 397
		dc->stop = 0;
		dc->state = DECODE_STATE_STOP;
	}
398 399

	free(path);
400 401
}

Avuton Olrich's avatar
Avuton Olrich committed
402 403 404
static int decoderInit(PlayerControl * pc, OutputBuffer * cb,
		       DecoderControl * dc)
{
405
	blockSignals();
406 407
	getPlayerData()->playerControl.decode_pid = 0;
	decode_pid = fork();
408

Avuton Olrich's avatar
Avuton Olrich committed
409
	if (decode_pid == 0) {
410 411 412
		/* CHILD */
		unblockSignals();

Avuton Olrich's avatar
Avuton Olrich committed
413 414
		while (1) {
			if (dc->cycleLogFiles) {
Eric Wong's avatar
Eric Wong committed
415
				cycle_log_files();
416
				dc->cycleLogFiles = 0;
Avuton Olrich's avatar
Avuton Olrich committed
417 418 419
			} else if (dc->start || dc->seek)
				decodeStart(pc, cb, dc);
			else if (dc->stop) {
420 421
				dc->state = DECODE_STATE_STOP;
				dc->stop = 0;
Avuton Olrich's avatar
Avuton Olrich committed
422 423
			} else
				my_usleep(10000);
Warren Dukes's avatar
Warren Dukes committed
424 425
		}

426
		exit(EXIT_SUCCESS);
Warren Dukes's avatar
Warren Dukes committed
427
		/* END OF CHILD */
Avuton Olrich's avatar
Avuton Olrich committed
428
	} else if (decode_pid < 0) {
429
		unblockSignals();
Eric Wong's avatar
Eric Wong committed
430
		pathcpy_trunc(pc->erroredUrl, pc->utf8url);
Warren Dukes's avatar
Warren Dukes committed
431 432 433
		pc->error = PLAYER_ERROR_SYSTEM;
		return -1;
	}
434
	DEBUG("decoder PID: %d\n", decode_pid);
435
	getPlayerData()->playerControl.decode_pid = decode_pid;
436
	unblockSignals();
Warren Dukes's avatar
Warren Dukes committed
437 438 439 440

	return 0;
}

Avuton Olrich's avatar
Avuton Olrich committed
441 442
static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int *previous,
			   int *currentChunkSent, MetadataChunk * currentChunk)
443
{
Avuton Olrich's avatar
Avuton Olrich committed
444
	if (cb->begin != cb->end) {
445
		int meta = cb->metaChunk[cb->begin];
Avuton Olrich's avatar
Avuton Olrich committed
446
		if (meta != *previous) {
447
			DEBUG("player: metadata change\n");
Avuton Olrich's avatar
Avuton Olrich committed
448
			if (meta >= 0 && cb->metaChunkSet[meta]) {
449
				DEBUG("player: new metadata from decoder!\n");
Avuton Olrich's avatar
Avuton Olrich committed
450 451 452
				memcpy(currentChunk,
				       cb->metadataChunks + meta,
				       sizeof(MetadataChunk));
453
				*currentChunkSent = 0;
Warren Dukes's avatar
Warren Dukes committed
454
				cb->metaChunkSet[meta] = 0;
455 456
			}
		}
457 458
		*previous = meta;
	}
Avuton Olrich's avatar
Avuton Olrich committed
459 460 461
	if (!(*currentChunkSent) && pc->metadataState ==
	    PLAYER_METADATA_STATE_WRITE) {
		MpdTag *tag = NULL;
462

463
		*currentChunkSent = 1;
Avuton Olrich's avatar
Avuton Olrich committed
464 465

		if ((tag = metadataChunkToMpdTagDup(currentChunk))) {
466
			sendMetadataToAudioDevice(tag);
467 468 469
			freeMpdTag(tag);
		}

Avuton Olrich's avatar
Avuton Olrich committed
470 471
		memcpy(&(pc->metadataChunk), currentChunk,
		       sizeof(MetadataChunk));
472 473 474 475 476
		pc->metadataState = PLAYER_METADATA_STATE_READ;
		kill(getppid(), SIGUSR1);
	}
}

Avuton Olrich's avatar
Avuton Olrich committed
477 478 479
static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
				  int *previous, int *currentChunkSent,
				  MetadataChunk * currentChunk, int to)
480
{
Avuton Olrich's avatar
Avuton Olrich committed
481 482 483
	while (cb->begin != to) {
		handleMetadata(cb, pc, previous, currentChunkSent,
			       currentChunk);
484
		if (cb->begin + 1 >= buffered_chunks) {
485 486
			cb->begin = 0;
		}
487
		else cb->begin++;
488
	}
Warren Dukes's avatar
Warren Dukes committed
489 490
}

491
static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb)
Avuton Olrich's avatar
Avuton Olrich committed
492
{
493 494 495 496 497 498 499 500
	int pause = 0;
	int quit = 0;
	int bbp = buffered_before_play;
	int doCrossFade = 0;
	int crossFadeChunks = 0;
	int fadePosition;
	int nextChunk = -1;
	int test;
Avuton Olrich's avatar
Avuton Olrich committed
501
	int decodeWaitedOn = 0;
502
	char silence[CHUNK_SIZE];
503
	double sizeToTime = 0.0;
504 505 506
	int previousMetadataChunk = -1;
	MetadataChunk currentMetadataChunk;
	int currentChunkSent = 1;
Warren Dukes's avatar
Warren Dukes committed
507 508
	int end;
	int next = -1;
Warren Dukes's avatar
Warren Dukes committed
509

Avuton Olrich's avatar
Avuton Olrich committed
510
	memset(silence, 0, CHUNK_SIZE);
Warren Dukes's avatar
Warren Dukes committed
511

Avuton Olrich's avatar
Avuton Olrich committed
512 513
	if (waitOnDecode(pc, dc, cb, &decodeWaitedOn) < 0)
		return;
Warren Dukes's avatar
Warren Dukes committed
514

Avuton Olrich's avatar
Avuton Olrich committed
515
	pc->elapsedTime = 0;
516 517
	pc->state = PLAYER_STATE_PLAY;
	pc->play = 0;
Avuton Olrich's avatar
Avuton Olrich committed
518
	kill(getppid(), SIGUSR1);
519

520 521
	while (decode_pid > 0 && 
	       cb->end - cb->begin < bbp &&
Avuton Olrich's avatar
Avuton Olrich committed
522 523
	       cb->end != buffered_chunks - 1 &&
	       dc->state != DECODE_STATE_STOP) {
524
		processDecodeInput();
525
		my_usleep(1000);
Warren Dukes's avatar
Warren Dukes committed
526 527
	}

Avuton Olrich's avatar
Avuton Olrich committed
528
	while (!quit) {
529
		processDecodeInput();
Avuton Olrich's avatar
Avuton Olrich committed
530 531 532 533 534 535
		handleDecodeStart();
		handleMetadata(cb, pc, &previousMetadataChunk,
			       &currentChunkSent, &currentMetadataChunk);
		if (dc->state == DECODE_STATE_STOP &&
		    pc->queueState == PLAYER_QUEUE_FULL &&
		    pc->queueLockState == PLAYER_QUEUE_UNLOCKED) {
Warren Dukes's avatar
Warren Dukes committed
536
			next = cb->end;
537 538
			dc->start = 1;
			pc->queueState = PLAYER_QUEUE_DECODE;
Avuton Olrich's avatar
Avuton Olrich committed
539
			kill(getppid(), SIGUSR1);
Warren Dukes's avatar
Warren Dukes committed
540
		}
Avuton Olrich's avatar
Avuton Olrich committed
541 542
		if (next >= 0 && doCrossFade == 0 && !dc->start &&
		    dc->state != DECODE_STATE_START) {
543
			nextChunk = -1;
Avuton Olrich's avatar
Avuton Olrich committed
544
			if (isCurrentAudioFormat(&(cb->audioFormat))) {
545
				doCrossFade = 1;
Avuton Olrich's avatar
Avuton Olrich committed
546 547 548 549 550 551
				crossFadeChunks =
				    calculateCrossFadeChunks(pc,
							     &(cb->
							       audioFormat));
				if (!crossFadeChunks
				    || pc->crossFade >= dc->totalTime) {
552
					doCrossFade = -1;
Warren Dukes's avatar
Warren Dukes committed
553
				}
Avuton Olrich's avatar
Avuton Olrich committed
554 555
			} else
				doCrossFade = -1;
556
		}
Warren Dukes's avatar
Warren Dukes committed
557

558
		/* copy these to local variables to prevent any potential
Avuton Olrich's avatar
Avuton Olrich committed
559
		   race conditions and weirdness */
Warren Dukes's avatar
Warren Dukes committed
560 561
		end = cb->end;

Avuton Olrich's avatar
Avuton Olrich committed
562 563 564 565 566 567 568 569 570 571 572
		if (pause)
			my_usleep(10000);
		else if (cb->begin != end && cb->begin != next) {
			if (doCrossFade == 1 && next >= 0 &&
			    ((next > cb->begin &&
			      (fadePosition = next - cb->begin)
			      <= crossFadeChunks) ||
			     (cb->begin > next &&
			      (fadePosition = next - cb->begin +
			       buffered_chunks) <= crossFadeChunks))) {
				if (nextChunk < 0) {
573 574
					crossFadeChunks = fadePosition;
				}
Warren Dukes's avatar
Warren Dukes committed
575
				test = end;
Avuton Olrich's avatar
Avuton Olrich committed
576 577 578 579 580 581
				if (end < cb->begin)
					test += buffered_chunks;
				nextChunk = cb->begin + crossFadeChunks;
				if (nextChunk < test) {
					if (nextChunk >= buffered_chunks) {
						nextChunk -= buffered_chunks;
Warren Dukes's avatar
Warren Dukes committed
582
					}
Avuton Olrich's avatar
Avuton Olrich committed
583 584 585 586 587 588 589 590 591 592 593 594
					pcm_mix(cb->chunks +
						cb->begin * CHUNK_SIZE,
						cb->chunks +
						nextChunk * CHUNK_SIZE,
						cb->chunkSize[cb->begin],
						cb->chunkSize[nextChunk],
						&(cb->audioFormat),
						((float)fadePosition) /
						crossFadeChunks);
					if (cb->chunkSize[nextChunk] >
					    cb->chunkSize[cb->begin]
					    ) {
595
						cb->chunkSize[cb->begin]
Avuton Olrich's avatar
Avuton Olrich committed
596
						    = cb->chunkSize[nextChunk];
Warren Dukes's avatar
Warren Dukes committed
597
					}
Avuton Olrich's avatar
Avuton Olrich committed
598 599
				} else {
					if (dc->state == DECODE_STATE_STOP) {
600
						doCrossFade = -1;
Avuton Olrich's avatar
Avuton Olrich committed
601 602
					} else
						continue;
Warren Dukes's avatar
Warren Dukes committed
603 604
				}
			}
605
			pc->elapsedTime = cb->times[cb->begin];
606
			pc->bitRate = cb->bitRate[cb->begin];
Avuton Olrich's avatar
Avuton Olrich committed
607 608 609 610 611 612 613
			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) {
614 615
				quit = 1;
			}
Avuton Olrich's avatar
Avuton Olrich committed
616 617 618
			pc->totalPlayTime +=
			    sizeToTime * cb->chunkSize[cb->begin];
			if (cb->begin + 1 >= buffered_chunks) {
619
				cb->begin = 0;
Avuton Olrich's avatar
Avuton Olrich committed
620 621
			} else
				cb->begin++;
622
		} else if (cb->begin != end && cb->begin == next) {
Avuton Olrich's avatar
Avuton Olrich committed
623 624
			if (doCrossFade == 1 && nextChunk >= 0) {
				nextChunk = cb->begin + crossFadeChunks;
625
				test = end;
Avuton Olrich's avatar
Avuton Olrich committed
626 627 628 629
				if (end < cb->begin)
					test += buffered_chunks;
				if (nextChunk < test) {
					if (nextChunk >= buffered_chunks) {
630
						nextChunk -= buffered_chunks;
Warren Dukes's avatar
Warren Dukes committed
631
					}
Avuton Olrich's avatar
Avuton Olrich committed
632 633 634 635 636 637
					advanceOutputBufferTo(cb, pc,
							      &previousMetadataChunk,
							      &currentChunkSent,
							      &currentMetadataChunk,
							      nextChunk);
				}
Warren Dukes's avatar
Warren Dukes committed
638
			}
Avuton Olrich's avatar
Avuton Olrich committed
639 640
			while (pc->queueState == PLAYER_QUEUE_DECODE ||
			       pc->queueLockState == PLAYER_QUEUE_LOCKED) {
641
				processDecodeInput();
Avuton Olrich's avatar
Avuton Olrich committed
642 643
				if (quit) {
					quitDecode(pc, dc);
644 645
					return;
				}
646
				my_usleep(10000);
647
			}
Avuton Olrich's avatar
Avuton Olrich committed
648
			if (pc->queueState != PLAYER_QUEUE_PLAY) {
Warren Dukes's avatar
Warren Dukes committed
649 650
				quit = 1;
				break;
Avuton Olrich's avatar
Avuton Olrich committed
651
			} else {
Warren Dukes's avatar
Warren Dukes committed
652
				next = -1;
Avuton Olrich's avatar
Avuton Olrich committed
653 654
				if (waitOnDecode(pc, dc, cb, &decodeWaitedOn) <
				    0) {
655 656
					return;
				}
657 658 659 660
				nextChunk = -1;
				doCrossFade = 0;
				crossFadeChunks = 0;
				pc->queueState = PLAYER_QUEUE_EMPTY;
Avuton Olrich's avatar
Avuton Olrich committed
661
				kill(getppid(), SIGUSR1);
662
			}
Avuton Olrich's avatar
Avuton Olrich committed
663 664
		} else if (decode_pid <= 0 ||
			   (dc->state == DECODE_STATE_STOP && !dc->start)) {
665 666
			quit = 1;
			break;
Avuton Olrich's avatar
Avuton Olrich committed
667
		} else {
668
			/*DEBUG("waiting for decoded audio, play silence\n");*/
Avuton Olrich's avatar
Avuton Olrich committed
669 670
			if (playAudio(silence, CHUNK_SIZE) < 0)
				quit = 1;
671 672
		}
	}
Warren Dukes's avatar
Warren Dukes committed
673

Avuton Olrich's avatar
Avuton Olrich committed
674
	quitDecode(pc, dc);
675 676 677 678 679 680 681
}

/* decode w/ buffering
 * this will fork another process
 * child process does decoding
 * parent process does playing audio
 */
Eric Wong's avatar
Eric Wong committed
682
void decode(void)
Avuton Olrich's avatar
Avuton Olrich committed
683 684 685 686
{
	OutputBuffer *cb;
	PlayerControl *pc;
	DecoderControl *dc;
687 688

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

690
	clearAllMetaChunkSets(cb);
691 692 693 694 695
	cb->begin = 0;
	cb->end = 0;
	pc = &(getPlayerData()->playerControl);
	dc = &(getPlayerData()->decoderControl);
	dc->error = 0;
696 697
	dc->seek = 0;
	dc->stop = 0;
698
	dc->start = 1;
699

Avuton Olrich's avatar
Avuton Olrich committed
700 701 702
	if (decode_pid <= 0) {
		if (decoderInit(pc, cb, dc) < 0)
			return;
Warren Dukes's avatar
Warren Dukes committed
703 704
	}

705
	decodeParent(pc, dc, cb);
Warren Dukes's avatar
Warren Dukes committed
706
}