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
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.
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
22 #include "playerData.h"
24 #include "pcm_utils.h"
28 #include "sig_handlers.h"
33 #include <sys/types.h>
35 #include <sys/resource.h>
40 static int decode_pid
;
42 void decodeSigHandler(int sig
, siginfo_t
* si
, void *v
)
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
));
54 getPlayerData()->playerControl
.decode_pid
= 0;
56 } else if (sig
== SIGTERM
) {
59 DEBUG("player (or child) got SIGTERM\n");
63 DEBUG("decoder (or child) got SIGTERM\n");
68 static void stopDecode(DecoderControl
* dc
)
70 if (decode_pid
> 0 && (dc
->start
|| dc
->state
!= DECODE_STATE_STOP
)) {
72 while (decode_pid
> 0 && dc
->stop
)
77 static void quitDecode(PlayerControl
* pc
, DecoderControl
* dc
)
82 pc
->state
= PLAYER_STATE_STOP
;
92 kill(getppid(), SIGUSR1
);
95 static int calculateCrossFadeChunks(PlayerControl
* pc
, AudioFormat
* af
)
99 if (pc
->crossFade
<= 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
;
115 #define handleDecodeStart() \
116 if(decodeWaitedOn) { \
117 if(dc->state!=DECODE_STATE_START && decode_pid > 0 && \
118 dc->error==DECODE_ERROR_NOERROR) \
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); \
129 dropBufferedAudio(); \
130 closeAudioDevice(); \
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; \
140 else if(dc->state!=DECODE_STATE_START || decode_pid <= 0) { \
141 pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
142 pc->error = PLAYER_ERROR_FILE; \
152 static int waitOnDecode(PlayerControl
* pc
, DecoderControl
* dc
,
153 OutputBuffer
* cb
, int *decodeWaitedOn
)
156 pathcpy_trunc(pc
->currentUrl
, pc
->utf8url
);
158 while (decode_pid
> 0 && dc
->start
)
161 if (dc
->start
|| dc
->error
!= DECODE_ERROR_NOERROR
) {
162 pathcpy_trunc(pc
->erroredUrl
, pc
->utf8url
);
163 pc
->error
= PLAYER_ERROR_FILE
;
168 if ((tag
= metadataChunkToMpdTagDup(&(pc
->fileMetadataChunk
)))) {
169 sendMetadataToAudioDevice(tag
);
173 pc
->totalTime
= pc
->fileTime
;
183 static int decodeSeek(PlayerControl
* pc
, DecoderControl
* dc
,
184 OutputBuffer
* cb
, int *decodeWaitedOn
, int *next
)
188 if (decode_pid
> 0) {
189 if (dc
->state
== DECODE_STATE_STOP
|| dc
->error
||
190 strcmp(dc
->utf8url
, pc
->utf8url
) != 0) {
197 waitOnDecode(pc
, dc
, cb
, decodeWaitedOn
);
199 if (decode_pid
> 0 && dc
->state
!= DECODE_STATE_STOP
&&
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
;
207 while (decode_pid
> 0 && dc
->seek
)
209 if (!dc
->seekError
) {
210 pc
->elapsedTime
= dc
->seekWhere
;
220 #define processDecodeInput() \
221 if(pc->cycleLogFiles) { \
223 pc->cycleLogFiles = 0; \
225 if(pc->lockQueue) { \
226 pc->queueLockState = PLAYER_QUEUE_LOCKED; \
229 if(pc->unlockQueue) { \
230 pc->queueLockState = PLAYER_QUEUE_UNLOCKED; \
231 pc->unlockQueue = 0; \
236 pc->state = PLAYER_STATE_PAUSE; \
238 if (openAudioDevice(NULL) >= 0) { \
239 pc->state = PLAYER_STATE_PLAY; \
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); \
248 kill(getppid(), SIGUSR1); \
251 } else if (pause) { \
252 dropBufferedAudio(); \
253 closeAudioDevice(); \
257 dropBufferedAudio(); \
258 if(decodeSeek(pc,dc,cb,&decodeWaitedOn,&next) == 0) { \
265 dropBufferedAudio(); \
270 static void decodeStart(PlayerControl
* pc
, OutputBuffer
* cb
,
274 InputStream inStream
;
275 InputPlugin
*plugin
= NULL
;
278 if (isRemoteUrl(pc
->utf8url
))
279 path
= utf8StrToLatin1Dup(pc
->utf8url
);
281 path
= xstrdup(rmp2amp(utf8ToFsCharset(pc
->utf8url
)));
284 dc
->error
= DECODE_ERROR_FILE
;
285 dc
->state
= DECODE_STATE_STOP
;
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
;
302 dc
->state
= DECODE_STATE_START
;
304 #if 0 /* this code is moved to the http stuff */
305 while (!inputStreamAtEOF(&inStream
) && bufferInputStream(&inStream
) < 0
307 /* sleep so we don't consume 100% of the cpu */
311 /* for http streams, seekable is determined in bufferInputStream */
312 dc
->seekable
= inStream
.seekable
;
315 dc
->state
= DECODE_STATE_STOP
;
321 /*if(inStream.metaName) {
322 MpdTag * tag = newMpdTag();
323 tag->name = xstrdup(inStream.metaName);
324 copyMpdTagToOutputBuffer(cb, tag);
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
)
339 if (!(plugin
->streamTypes
& INPUT_PLUGIN_STREAM_URL
))
341 if (plugin
->tryDecodeFunc
342 && !plugin
->tryDecodeFunc(&inStream
))
344 ret
= plugin
->streamDecodeFunc(cb
, dc
, &inStream
);
348 /* if that fails, try suffix matching the URL: */
349 if (plugin
== NULL
) {
350 char *s
= getSuffix(dc
->utf8url
);
352 while (ret
&& (plugin
= getInputPluginFromSuffix(s
, next
++))) {
353 if (!plugin
->streamDecodeFunc
)
355 if (!(plugin
->streamTypes
&
356 INPUT_PLUGIN_STREAM_URL
))
358 if (plugin
->tryDecodeFunc
&&
359 !plugin
->tryDecodeFunc(&inStream
))
361 ret
= plugin
->streamDecodeFunc(cb
, dc
, &inStream
);
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
);
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
)
382 if (plugin
->tryDecodeFunc
&&
383 !plugin
->tryDecodeFunc(&inStream
))
386 if (plugin
->fileDecodeFunc
) {
387 closeInputStream(&inStream
);
388 ret
= plugin
->fileDecodeFunc(cb
, dc
, path
);
390 } else if (plugin
->streamDecodeFunc
) {
391 ret
= plugin
->streamDecodeFunc(cb
, dc
, &inStream
);
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
;
402 dc
->error
= DECODE_ERROR_UNKTYPE
;
403 closeInputStream(&inStream
);
406 dc
->state
= DECODE_STATE_STOP
;
412 static int decoderInit(PlayerControl
* pc
, OutputBuffer
* cb
,
424 getPlayerData()->playerControl
.decode_pid
= 0;
427 if (decode_pid
== 0) {
432 if (dc
->cycleLogFiles
) {
434 dc
->cycleLogFiles
= 0;
435 } else if (dc
->start
|| dc
->seek
)
436 decodeStart(pc
, cb
, dc
);
438 dc
->state
= DECODE_STATE_STOP
;
446 } else if (decode_pid
< 0) {
448 pathcpy_trunc(pc
->erroredUrl
, pc
->utf8url
);
449 pc
->error
= PLAYER_ERROR_SYSTEM
;
452 DEBUG("decoder PID: %d\n", decode_pid
);
453 getPlayerData()->playerControl
.decode_pid
= decode_pid
;
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");
469 cb
->metadataChunks
+ meta
,
470 sizeof(MetadataChunk
));
471 *currentChunkSent
= 0;
472 cb
->metaChunkSet
[meta
] = 0;
477 if (!(*currentChunkSent
) && pc
->metadataState
==
478 PLAYER_METADATA_STATE_WRITE
) {
481 *currentChunkSent
= 1;
483 if ((tag
= metadataChunkToMpdTagDup(currentChunk
))) {
484 sendMetadataToAudioDevice(tag
);
488 memcpy(&(pc
->metadataChunk
), currentChunk
,
489 sizeof(MetadataChunk
));
490 pc
->metadataState
= PLAYER_METADATA_STATE_READ
;
491 kill(getppid(), SIGUSR1
);
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
,
502 if (cb
->begin
+ 1 >= buffered_chunks
) {
509 static void decodeParent(PlayerControl
* pc
, DecoderControl
* dc
, OutputBuffer
* cb
)
513 int bbp
= buffered_before_play
;
515 int crossFadeChunks
= 0;
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;
528 memset(silence
, 0, CHUNK_SIZE
);
530 if (waitOnDecode(pc
, dc
, cb
, &decodeWaitedOn
) < 0)
534 pc
->state
= PLAYER_STATE_PLAY
;
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();
547 processDecodeInput();
549 handleMetadata(cb
, pc
, &previousMetadataChunk
,
550 ¤tChunkSent
, ¤tMetadataChunk
);
551 if (dc
->state
== DECODE_STATE_STOP
&&
552 pc
->queueState
== PLAYER_QUEUE_FULL
&&
553 pc
->queueLockState
== PLAYER_QUEUE_UNLOCKED
) {
556 pc
->queueState
= PLAYER_QUEUE_DECODE
;
557 kill(getppid(), SIGUSR1
);
559 if (next
>= 0 && doCrossFade
== 0 && !dc
->start
&&
560 dc
->state
!= DECODE_STATE_START
) {
562 if (isCurrentAudioFormat(&(cb
->audioFormat
))) {
565 calculateCrossFadeChunks(pc
,
569 || pc
->crossFade
>= dc
->totalTime
) {
576 /* copy these to local variables to prevent any potential
577 race conditions and weirdness */
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
) ||
588 (fadePosition
= next
- cb
->begin
+
589 buffered_chunks
) <= crossFadeChunks
))) {
591 crossFadeChunks
= fadePosition
;
595 test
+= buffered_chunks
;
596 nextChunk
= cb
->begin
+ crossFadeChunks
;
597 if (nextChunk
< test
) {
598 if (nextChunk
>= buffered_chunks
) {
599 nextChunk
-= buffered_chunks
;
602 cb
->begin
* CHUNK_SIZE
,
604 nextChunk
* CHUNK_SIZE
,
605 cb
->chunkSize
[cb
->begin
],
606 cb
->chunkSize
[nextChunk
],
608 ((float)fadePosition
) /
610 if (cb
->chunkSize
[nextChunk
] >
611 cb
->chunkSize
[cb
->begin
]
613 cb
->chunkSize
[cb
->begin
]
614 = cb
->chunkSize
[nextChunk
];
617 if (dc
->state
== DECODE_STATE_STOP
) {
623 pc
->elapsedTime
= cb
->times
[cb
->begin
];
624 pc
->bitRate
= cb
->bitRate
[cb
->begin
];
625 pcm_volumeChange(cb
->chunks
+ cb
->begin
*
627 cb
->chunkSize
[cb
->begin
],
630 if (playAudio(cb
->chunks
+ cb
->begin
* CHUNK_SIZE
,
631 cb
->chunkSize
[cb
->begin
]) < 0) {
635 sizeToTime
* cb
->chunkSize
[cb
->begin
];
636 if (cb
->begin
+ 1 >= buffered_chunks
) {
640 } else if (cb
->begin
!= end
&& cb
->begin
== next
) {
641 if (doCrossFade
== 1 && nextChunk
>= 0) {
642 nextChunk
= cb
->begin
+ crossFadeChunks
;
645 test
+= buffered_chunks
;
646 if (nextChunk
< test
) {
647 if (nextChunk
>= buffered_chunks
) {
648 nextChunk
-= buffered_chunks
;
650 advanceOutputBufferTo(cb
, pc
,
651 &previousMetadataChunk
,
653 ¤tMetadataChunk
,
657 while (pc
->queueState
== PLAYER_QUEUE_DECODE
||
658 pc
->queueLockState
== PLAYER_QUEUE_LOCKED
) {
659 processDecodeInput();
662 if (pc
->queueState
!= PLAYER_QUEUE_PLAY
) {
667 if (waitOnDecode(pc
, dc
, cb
, &decodeWaitedOn
) <
674 pc
->queueState
= PLAYER_QUEUE_EMPTY
;
675 kill(getppid(), SIGUSR1
);
677 } else if (decode_pid
<= 0 ||
678 (dc
->state
== DECODE_STATE_STOP
&& !dc
->start
)) {
682 /*DEBUG("waiting for decoded audio, play silence\n");*/
683 if (playAudio(silence
, CHUNK_SIZE
) < 0)
691 /* decode w/ buffering
692 * this will fork another process
693 * child process does decoding
694 * parent process does playing audio
702 cb
= &(getPlayerData()->buffer
);
704 clearAllMetaChunkSets(cb
);
707 pc
= &(getPlayerData()->playerControl
);
708 dc
= &(getPlayerData()->decoderControl
);
714 if (decoderInit(pc
, cb
, dc
) < 0)
717 decodeParent(pc
, dc
, cb
);