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();