/***************************************************************************
mpg_interface.c - description
-------------------
begin : Tue Feb 3 2004
copyright : (C) 2004 by Andy Clews
email : andy clews blueyonder co uk
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// #include "get_songs.h"
#include "mpg_interface.h"
#include "log.h"
#include "tools.h"
/***************************************************************************
* *
* Start of Procedures *
* *
***************************************************************************/
// Catch signal of exiting player...
void mpg123_child(pid_t pid, int status)
{
if (pid == mpg123_pid)
{
log_printf(LOG_NORMAL, "mpg123_child(): player %d exited with code %d\n", pid, WEXITSTATUS(status));
mpg123_pid = 0;
}
}
void SignalHandler(int sig)
{
sig = sig;
log_printf(LOG_NORMAL, "Caught CTRL-C, exiting\n");
mpg123_quit();
// terminate = 1;
// endwin();
exit(0);
}
void SignalHandler1(int sig)
{
sig = sig;
log_printf(LOG_NORMAL, "Caught Segmentation Fault, exiting\n");
mpg123_quit();
// terminate = 1;
// endwin();
printf("Caught Segmentation Fault - Exiting!\n");
exit(0);
}
void mpg123_quit(void)
{
int retval;
retval = sendmesg(mpg123_fdsend, "QUIT\n");
if (retval < 0)
{
log_printf(LOG_NORMAL, "mpg123_quit ; send error : %s\n", strerror(errno));
}
else
{
log_printf(LOG_NORMAL, "mpg123 Shutdown\n");
}
kill (mpg123_pid, SIGKILL);
// sleep(1);
}
// Start of player process...
int mpg123_start(void)
{
int fd_send[2], fd_recv[2];
int i;
char *args[50];
// Check that mpg123 is not already running...
if (mpg123_pid)
return 0;
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd_send) < 0)
return -1;
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd_recv) < 0)
return -1;
// Handle signals...
signal(SIGPIPE, SIG_IGN);
// Get additional options...
if ((args[0] = (char *)calloc(0, 4)) == NULL)
perror("Calloc failed");
strcpy(args[0], "mpg123");
// start mpg123 in remote
if ((args[1] = (char *)calloc(0, 3)) == NULL)
perror("Calloc failed");
strcpy(args[1], "-R");
// set an output buffer of 0 Mb
if ((args[2] = (char *)calloc(0, 4)) == NULL)
perror("Calloc failed");
strcpy(args[2], "-b 0");
i = 3;
while (args[i])
args[++i] = strtok(NULL, " ");
args[i] = "-";
args[++i] = NULL;
// fork child process
mpg123_pid = fork();
if (mpg123_pid == 0)
{
// pipe in/ out though socket to parent
dup2(fd_send[0], STDIN_FILENO);
close(fd_send[1]);
dup2(fd_recv[0], STDOUT_FILENO);
dup2(fd_recv[0], STDERR_FILENO);
close(fd_recv[0]);
close(fd_recv[1]);
//spawn player
execvp("mpg123", args);
// this is never reached if exec was OK...
log_printf(LOG_NORMAL, "oops...\n");
exit(-10);
}
// Parent continues here...
free(args[0]);
free(args[1]);
close(fd_send[0]);
mpg123_fdsend = fd_send[1];
close(fd_recv[0]);
mpg123_fdrecv = fd_recv[1];
// check if player is running
sleep(1);
if (!mpg123_pid)
{
log_printf(LOG_NORMAL, "mpg123_start : Player_process didn't start\n");
return -1;
}
else
{
log_printf(LOG_NORMAL, "mpg123_start : Player spawned on PID %d, piped on fd %d and %d\n", mpg123_pid, mpg123_fdsend, mpg123_fdrecv);
return 0;
}
}
// Load song & start playing
int mpg123_load(char *filename)
{
int retval;
char buf[132];
sprintf(buf, "LOAD %s\n", filename);
retval = sendmesg(mpg123_fdsend, buf);
if (retval < 0)
log_printf(LOG_NORMAL, "mpg123_load() : send error : %s\n", strerror(errno));
return retval;
}
// Pause / unpause player.
int mpg123_pause(void)
{
int retval;
retval = sendmesg(mpg123_fdsend, "PAUSE\n");
if (retval < 0)
log_printf(LOG_NORMAL, "mpg123_pause() : send error : %s\n", strerror(errno));
return retval;
}
// Stop playing a track, without killing mpg123.
int mpg123_stop(void)
{
int retval;
retval = sendmesg(mpg123_fdsend, "STOP\n");
if (retval < 0)
log_printf(LOG_NORMAL, "mpg123_stop() : send error : %s\n", strerror(errno));
return retval;
}
// Jump forwards / backwards
int mpg123_jump(char *dir)
{
int retval;
char buf[10];
log_printf(LOG_NOISY_DEBUG, "%s\n", dir);
if (dir == "0")
sprintf(buf, "JUMP %s\n", dir);
else
sprintf(buf, "JUMP %s500\n", dir);
retval = sendmesg(mpg123_fdsend, buf);
if (retval < 0)
log_printf(LOG_NORMAL, "mpg123_jump() : send error : %s\n", strerror(errno));
return retval;
}
int mpg123_big_jump(char *dir)
{
int retval;
char buf[10];
log_printf(LOG_NOISY_DEBUG, "%s\n", dir);
if (dir == "0")
sprintf(buf, "JUMP %s\n", dir);
else
sprintf(buf, "JUMP %s2000\n", dir);
retval = sendmesg(mpg123_fdsend, buf);
if (retval < 0)
log_printf(LOG_NORMAL, "mpg123_jump() : send error : %s\n", strerror(errno));
return retval;
}
int mpg123_position(int framepos)
{
int retval;
char buf[10];
log_printf(LOG_DEBUG, "mpg123_position() : Jump to %i\n", framepos);
sprintf(buf, "JUMP %i\n", framepos);
retval = sendmesg(mpg123_fdsend, buf);
if (retval < 0)
log_printf(LOG_NORMAL, "mpg123_position() : send error : %s\n", strerror(errno));
return retval;
}
// Read mpg123 input stream.
int mpg123_read(void)
{
static int lastframeremain;
static int lastsecpos, lastsecremain;
char s[512], *c1, *c2, *c3, *c4, *c5;
int rc, secpos, secremain;
// read the response from the player.
rc = readline(mpg123_fdrecv, s, sizeof(s));
if (rc < 0)
{
log_printf(LOG_NORMAL, "mpg123 closed the connection!!\n");
return -10;
}
if (!s || !*s) {
// log_printf(LOG_NOISY_DEBUG, "No data from mpg123 pipe\n");
return -2;
}
c1 = s ? strtok(s, " \t") : NULL;
if (c1 && !strcasecmp(c1, "@R"))
{
// player version received
c2 = c1 ? strtok(NULL, "") : NULL;
log_printf(LOG_NORMAL, "Version : %s\n", c2);
return PLAYER_VERSION;
}
else if (c1 && !strcasecmp(c1, "@P"))
{
// playing status received
c2 = c1 ? strtok(NULL, " \t") : NULL;
c3 = c2 ? strtok(NULL, " \t") : NULL;
if (atoi(c2) == 0)
{
// EOF can be flagged many ways. "@P 0 EOF" should be the norm
if ((c3 && !strcasecmp(c3, "EOF")) || (lastframepos > 10 && lastframeremain < 10 ))
{
log_printf(LOG_NORMAL, "End of song.\n");
return SONG_END;
}
else
{
log_printf(LOG_NORMAL, "Song stopped.\n");
//return SONG_STOP; // commented out to replace with a simpler SONG_END
return SONG_END;
}
}
else if (atoi(c2) == 1)
{
log_printf(LOG_NORMAL, "Player paused\n");
return SONG_PAUSE;
}
else if (atoi(c2) == 2)
{
log_printf(LOG_NORMAL, "Player unpaused.\n");
return SONG_PLAY;
}
else if (atoi(c2) == 3)
{
log_printf(LOG_NORMAL, "End of song.\n");
return SONG_END;
}
}
else if (c1 && !strcasecmp(c1, "@I"))
{
// TAG data received.
c2 = c1 ? strtok(NULL, "") : NULL;
if (!strncasecmp(c2, "ID3:", 4))
{
// ID3 tag
return SONG_INFO;
}
else
{
log_printf(LOG_NORMAL, "No Tag Data...\n");
}
}
else if (c1 && !strcasecmp(c1, "@S"))
{
// Status message after loading a song (stream info)
}
else if (c1 && !strcasecmp(c1, "@F"))
{
// Frame info
//log_printf(LOG_NOISY_DEBUG, "Frame info message : %s %s \n", c1, c2);
c2 = c1 ? strtok(NULL, " \t") : NULL;
c3 = c2 ? strtok(NULL, " \t") : NULL;
c4 = c3 ? strtok(NULL, " \t") : NULL;
c5 = c4 ? strtok(NULL, " \t") : NULL;
lastframepos = atoi(c2);
lastframeremain = atoi(c3);
secpos = (int)atof(c4);
secremain = (int)atof(c5);
play_time = secpos;
play_time_remaining = secremain;
log_printf(LOG_NOISY_DEBUG, "Play times: lastframepos-> %i lastframeremain-> %i secpos-> %i secremain-> %i\n", lastframepos, lastframeremain, secpos, secremain);
return SONG_TIME;
}
else
{
// Unknown message - probably an error or noise...
c2 = c1 ? strtok(NULL, "") : NULL;
log_printf(LOG_DEBUG, "unknown message ; \" %s %s \"\n", c1, c2);
return PLAYER_ERROR;
}
return -1;
}