/* $Id: mplayerd.c,v 1.4 2006/01/31 23:14:38 tnn Exp $ */ /* control mplayer by submitting slave commands over tcp/ip */ #define PORT 1234 #define MPLAYER_COMMAND "DISPLAY=:0 mplayer -quiet -slave silent.mp3" /* uncomment this if it doesn't work */ /* #define DEBUG */ /* * * usage example: * * server$ cc -o mplayerd mplayerd.c * server$ ./mplayerd & * * client$ echo 'loadfile /path/to/video.mpeg' | telnet server:1234 * client$ sleep 10 * client$ echo 'osd_show_text Hello\ World.' | telnet server:1234 * client$ sleep 10 * client$ echo 'seek 0 1' | telnet server:1234 * * * NOTE: You must set MPLAYER_COMMAND to point to a default video or audio * file that will be played until the first loadfile command * has been processed. Also note that no security checks are done, * other than that the "run" command is disabled. * * Read slave.txt in the mplayer distribution for command syntax. **/ /** * (c) 2006 Tobias Nygren * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #ifdef MAX #undef MAX #endif #define MAX(a,b) (((a)>(b))?(a):(b)) static void die (char *format, ...) { va_list ap; va_start (ap, format); fprintf (stderr, "fatal error: "); vfprintf (stderr, format, ap); fprintf (stderr, "\n"); va_end (ap); exit (1); } void dbg (char *format, ...) { #ifdef DEBUG va_list ap; va_start (ap, format); fprintf (stderr, "debug: "); vfprintf (stderr, format, ap); fprintf (stderr, "\n"); va_end (ap); #endif } int main (int argc, char **argv) { int mpfd[2]; int listenfd, clientfd, nfds, connected, mplayer, len, status; pid_t pid; struct sockaddr_in listensa, clientsa; char buf[256]; socklen_t socklen; fd_set rs, ws, es; /* listen on server socket */ listenfd = socket (AF_INET, SOCK_STREAM, 0); if (listenfd < 0) die ("socket"); listensa.sin_family = AF_INET; listensa.sin_addr.s_addr = htonl (INADDR_ANY); listensa.sin_port = htons (PORT); if (bind (listenfd, (struct sockaddr*)&listensa, sizeof(listensa)) < 0) die ("bind"); if (listen (listenfd, 5) < 0) die ("listen"); connected = 0; /* no client connected */ mplayer = 0; /* no mplayer running */ /* mainloop */ dbg ("listening"); for(;;) { FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); FD_SET (listenfd, &rs); nfds = 0; nfds = MAX (nfds, listenfd); if (connected) { FD_SET (clientfd, &rs); FD_SET (clientfd, &es); nfds = MAX (nfds, clientfd); } if (mplayer) { FD_SET (mpfd[0], &rs); FD_SET (mpfd[0], &es); nfds = MAX (nfds, mpfd[0]); } nfds++; if (select (nfds, &rs, &ws, &es, NULL) == -1) die ("select"); if (mplayer) { if (FD_ISSET (mpfd[0], &rs)) { /* sink characters from mplayer */ /* detect shutdown by magic character 0 */ recv (mpfd[0], buf, 1, 0); if (buf[0] == 0) { dbg ("mplayer shutdown ..."); if( wait(&status) < 0) die("wait"); close (mpfd[0]); close (mpfd[1]); dbg ("... completed"); mplayer = 0; } fprintf (stderr, "%c", buf[0]); } if (FD_ISSET (mpfd[0], &es)) { die ("exception from mplayer"); } } if (FD_ISSET (listenfd, &rs)) { /* new connection */ dbg ("incoming connection"); if (connected) { /* kick out previous client */ dbg ("kicking out old client"); shutdown (clientfd, SHUT_RDWR); close (clientfd); } clientfd = accept (listenfd, (struct sockaddr *)&clientsa, &socklen); if (clientfd < 0) die("accept"); dbg ("connected"); connected = 1; } if (connected) { if (FD_ISSET (clientfd, &rs)) { /* incoming command, read it and disconnect */ dbg ("read command"); len=recv (clientfd, &buf, 254, 0); if(len == -1) die("recv(client)"); buf[len]=0; strtok(buf, "\r"); strtok(buf, "\n"); shutdown (clientfd, SHUT_RDWR); close (clientfd); connected = 0; dbg ("disconnected"); if (!mplayer) { /* mplayer not running, start it */ dbg ("starting mplayer ..."); if (socketpair (AF_UNIX, SOCK_STREAM, 0, mpfd) < 0) die("socketpair"); pid = fork(); if (pid == -1) die("fork"); if (pid == 0) { dup2 (mpfd[1], 0); dup2 (mpfd[1], 1); dup2 (mpfd[1], 2); system (MPLAYER_COMMAND); /* magic */ send (mpfd[1],"\000", 1, 0); _exit(0); } mplayer = 1; dbg ("... started"); } /* send command to mplayer */ dbg ("command '%s'", buf); strcat(buf, "\n"); if (strncmp (buf, "run", 3)) send (mpfd[0], buf, strlen(buf), 0); } if (FD_ISSET (clientfd, &es)) { /* client error, disconnect it */ dbg ("client error"); shutdown (clientfd, SHUT_RDWR); close (clientfd); connected = 0; } } } }