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
23 #include "interface.h"
29 #include "directory.h"
31 #include "playerData.h"
32 #include "permission.h"
33 #include "sig_handlers.h"
36 #include <sys/types.h>
47 volatile int player_pid
= 0;
49 void clearPlayerPid(void)
54 static void resetPlayerMetadata(void)
56 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
58 if (pc
->metadataState
== PLAYER_METADATA_STATE_READ
) {
59 pc
->metadataState
= PLAYER_METADATA_STATE_WRITE
;
63 static void resetPlayer(void)
68 getPlayerData()->playerControl
.stop
= 0;
69 getPlayerData()->playerControl
.play
= 0;
70 getPlayerData()->playerControl
.pause
= 0;
71 getPlayerData()->playerControl
.lockQueue
= 0;
72 getPlayerData()->playerControl
.unlockQueue
= 0;
73 getPlayerData()->playerControl
.state
= PLAYER_STATE_STOP
;
74 getPlayerData()->playerControl
.queueState
= PLAYER_QUEUE_UNLOCKED
;
75 getPlayerData()->playerControl
.seek
= 0;
76 getPlayerData()->playerControl
.metadataState
=
77 PLAYER_METADATA_STATE_WRITE
;
78 pid
= getPlayerData()->playerControl
.decode_pid
;
81 getPlayerData()->playerControl
.decode_pid
= 0;
84 void player_sigChldHandler(int pid
, int status
)
86 if (player_pid
== pid
)
88 DEBUG("SIGCHLD caused by player process\n");
89 if (WIFSIGNALED(status
) &&
90 WTERMSIG(status
) != SIGTERM
&&
91 WTERMSIG(status
) != SIGINT
)
93 ERROR("player process died from signal: %i\n",
98 else if (pid
== getPlayerData()->playerControl
.decode_pid
&&
101 if (WIFSIGNALED(status
) && WTERMSIG(status
) != SIGTERM
)
103 ERROR("(caught by master parent) "
104 "decode process died from a "
105 "non-TERM signal: %i\n", WTERMSIG(status
));
107 getPlayerData()->playerControl
.decode_pid
= 0;
113 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
127 clock_t start
= clock();
131 setSigHandlersForDecoder();
133 closeAllListenSockets();
141 DEBUG("took %f to init player\n",
142 (float)(clock()-start
)/CLOCKS_PER_SEC
);
153 else if (pc
->closeAudio
) {
156 kill(getppid(), SIGUSR1
);
157 } else if (pc
->lockQueue
) {
158 pc
->queueLockState
= PLAYER_QUEUE_LOCKED
;
160 } else if (pc
->unlockQueue
) {
161 pc
->queueLockState
= PLAYER_QUEUE_UNLOCKED
;
163 } else if (pc
->cycleLogFiles
) {
165 pc
->cycleLogFiles
= 0;
172 else if (player_pid
< 0)
175 ERROR("player Problems fork()'ing\n");
185 int playerWait(int fd
)
187 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
193 if (playerStop(fd
) < 0)
207 int playerPlay(int fd
, Song
* song
)
209 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
211 if (playerStop(fd
) < 0)
215 pc
->fileTime
= song
->tag
->time
;
219 copyMpdTagToMetadataChunk(song
->tag
, &(pc
->fileMetadataChunk
));
221 pathcpy_trunc(pc
->utf8url
, getSongUrl(song
));
224 if (playerInit() < 0) {
229 resetPlayerMetadata();
230 while (player_pid
> 0 && pc
->play
)
236 int playerStop(int fd
)
238 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
240 if (player_pid
> 0 && pc
->state
!= PLAYER_STATE_STOP
) {
242 while (player_pid
> 0 && pc
->stop
)
246 pc
->queueState
= PLAYER_QUEUE_BLANK
;
252 void playerKill(void)
263 int playerPause(int fd
)
265 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
267 if (player_pid
> 0 && pc
->state
!= PLAYER_STATE_STOP
) {
269 while (player_pid
> 0 && pc
->pause
)
276 int playerSetPause(int fd
, int pause
)
278 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
284 case PLAYER_STATE_PLAY
:
288 case PLAYER_STATE_PAUSE
:
297 int getPlayerElapsedTime(void)
299 return (int)(getPlayerData()->playerControl
.elapsedTime
+ 0.5);
302 unsigned long getPlayerBitRate(void)
304 return getPlayerData()->playerControl
.bitRate
;
307 int getPlayerTotalTime(void)
309 return (int)(getPlayerData()->playerControl
.totalTime
+ 0.5);
312 int getPlayerState(void)
314 return getPlayerData()->playerControl
.state
;
317 void clearPlayerError(void)
319 getPlayerData()->playerControl
.error
= 0;
322 int getPlayerError(void)
324 return getPlayerData()->playerControl
.error
;
327 char *getPlayerErrorStr(void)
330 int errorlen
= MAXPATHLEN
+ 1024;
331 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
333 error
= xrealloc(error
, errorlen
);
337 case PLAYER_ERROR_FILENOTFOUND
:
338 snprintf(error
, errorlen
,
339 "file \"%s\" does not exist or is inaccessible",
342 case PLAYER_ERROR_FILE
:
343 snprintf(error
, errorlen
, "problems decoding \"%s\"",
346 case PLAYER_ERROR_AUDIO
:
347 snprintf(error
, errorlen
, "problems opening audio device");
349 case PLAYER_ERROR_SYSTEM
:
350 snprintf(error
, errorlen
, "system error occured");
352 case PLAYER_ERROR_UNKTYPE
:
353 snprintf(error
, errorlen
, "file type of \"%s\" is unknown",
359 errorlen
= strlen(error
);
360 error
= xrealloc(error
, errorlen
+ 1);
368 void playerCloseAudio(void)
370 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
372 if (player_pid
> 0) {
373 if (playerStop(STDERR_FILENO
) < 0)
376 while (player_pid
> 0 && pc
->closeAudio
)
381 int queueSong(Song
* song
)
383 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
385 if (pc
->queueState
== PLAYER_QUEUE_BLANK
) {
386 pathcpy_trunc(pc
->utf8url
, getSongUrl(song
));
389 pc
->fileTime
= song
->tag
->time
;
393 copyMpdTagToMetadataChunk(song
->tag
, &(pc
->fileMetadataChunk
));
395 pc
->queueState
= PLAYER_QUEUE_FULL
;
402 int getPlayerQueueState(void)
404 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
406 return pc
->queueState
;
409 void setQueueState(int queueState
)
411 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
413 pc
->queueState
= queueState
;
416 void playerQueueLock(void)
418 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
420 if (player_pid
> 0 && pc
->queueLockState
== PLAYER_QUEUE_UNLOCKED
) {
422 while (player_pid
> 0 && pc
->lockQueue
)
427 void playerQueueUnlock(void)
429 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
431 if (player_pid
> 0 && pc
->queueLockState
== PLAYER_QUEUE_LOCKED
) {
433 while (player_pid
> 0 && pc
->unlockQueue
)
438 int playerSeek(int fd
, Song
* song
, float time
)
440 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
442 if (pc
->state
== PLAYER_STATE_STOP
) {
443 commandError(fd
, ACK_ERROR_PLAYER_SYNC
,
444 "player not currently playing");
448 if (strcmp(pc
->utf8url
, getSongUrl(song
)) != 0) {
450 pc
->fileTime
= song
->tag
->time
;
454 copyMpdTagToMetadataChunk(song
->tag
, &(pc
->fileMetadataChunk
));
456 pathcpy_trunc(pc
->utf8url
, getSongUrl(song
));
459 if (pc
->error
== PLAYER_ERROR_NOERROR
) {
460 resetPlayerMetadata();
461 pc
->seekWhere
= time
;
463 while (player_pid
> 0 && pc
->seek
)
470 float getPlayerCrossFade(void)
472 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
474 return pc
->crossFade
;
477 void setPlayerCrossFade(float crossFadeInSeconds
)
480 if (crossFadeInSeconds
< 0)
481 crossFadeInSeconds
= 0;
483 pc
= &(getPlayerData()->playerControl
);
485 pc
->crossFade
= crossFadeInSeconds
;
488 void setPlayerSoftwareVolume(int volume
)
491 volume
= (volume
> 1000) ? 1000 : (volume
< 0 ? 0 : volume
);
493 pc
= &(getPlayerData()->playerControl
);
495 pc
->softwareVolume
= volume
;
498 double getPlayerTotalPlayTime(void)
500 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
502 return pc
->totalPlayTime
;
505 unsigned int getPlayerSampleRate(void)
507 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
509 return pc
->sampleRate
;
512 int getPlayerBits(void)
514 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
519 int getPlayerChannels(void)
521 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
526 void playerCycleLogFiles(void)
528 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
529 DecoderControl
*dc
= &(getPlayerData()->decoderControl
);
531 pc
->cycleLogFiles
= 1;
532 dc
->cycleLogFiles
= 1;
535 /* this actually creates a dupe of the current metadata */
536 Song
*playerCurrentDecodeSong(void)
539 static MetadataChunk
*prev
;
541 PlayerControl
*pc
= &(getPlayerData()->playerControl
);
543 if (pc
->metadataState
== PLAYER_METADATA_STATE_READ
) {
544 DEBUG("playerCurrentDecodeSong: caught new metadata!\n");
547 prev
= xmalloc(sizeof(MetadataChunk
));
548 memcpy(prev
, &(pc
->metadataChunk
), sizeof(MetadataChunk
));
551 song
= newNullSong();
552 song
->url
= xstrdup(pc
->currentUrl
);
553 song
->tag
= metadataChunkToMpdTagDup(prev
);
555 resetPlayerMetadata();