2 Copyright 2004-2005 Chris Tallon, Andreas Vogel
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "medialauncher.h"
25 #include <sys/types.h>
37 MediaLauncher::MediaLauncher(Config *c) {
45 MediaLauncher::~MediaLauncher(){
47 for (int i=0;i<numcommands;i++)
53 MediaLauncher::MCommand::MCommand(const char *n,ULONG t,const char *ext) {
54 command=new char[strlen(n)+1];
57 extension=new char[strlen(ext)+1];
58 strcpy(extension,ext);
60 MediaLauncher::MCommand::~MCommand() {
68 const char* mtypename;
71 {"PICTURE",MEDIA_TYPE_PICTURE},
72 {"AUDIO",MEDIA_TYPE_AUDIO},
73 {"VIDEO",MEDIA_TYPE_VIDEO},
74 {"LIST",MEDIA_TYPE_DIR}
77 static ULONG typeIdFromName(const char *name) {
78 for(int i=0;i<NUMTYPES;i++){
79 if (strcasecmp(mediatypes[i].mtypename,name) == 0) return mediatypes[i].mtypeid;
81 return MEDIA_TYPE_UNKNOWN;
84 int MediaLauncher::init() {
85 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"init");
87 commands=new Pcmd[MAXCMD];
89 for(int i=1;i<=MAXCMD;i++){
90 sprintf(buf,"Command.Name.%d",i);
91 const char *cmname=cfg->getValueString("Media",buf);
92 if (!cmname) continue;
93 sprintf(buf,"Command.Extension.%d",i);
94 const char *cmext=cfg->getValueString("Media",buf);
96 sprintf(buf,"Command.Type.%d",i);
97 const char *cmtype=cfg->getValueString("Media",buf);
98 if (! cmtype) continue;
99 ULONG cmtypeid=typeIdFromName(cmtype);
100 if (cmtypeid == MEDIA_TYPE_UNKNOWN) {
101 Log::getInstance()->log("MediaLauncher",Log::ERR,"unknown media type %s",cmtype);
104 commands[numcommands]=new MCommand(cmname,cmtypeid,cmext);
105 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found command %s for ext %s, type %s",cmname,cmext,cmtype);
107 char cbuf[strlen(cmname)+40];
108 sprintf(cbuf,"%s check",cmname);
111 Log::getInstance()->log("MediaLauncher",Log::ERR,"testting command %s failed, ignore",cmname);
117 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found %d commands",numcommands);
121 int MediaLauncher::init(MediaLauncher *cp) {
122 commands=new Pcmd[MAXCMD];
123 for (int i=0;i<cp->numcommands;i++) {
124 commands[i]=new MCommand(cp->commands[i]->command,cp->commands[i]->mediaType,cp->commands[i]->extension);
126 numcommands=cp->numcommands;
132 int MediaLauncher::findCommand(const char *name){
133 const char *ext=name+strlen(name);
134 while (*ext != '.' && ext > name) ext--;
135 if (*ext == '.') ext++;
136 //Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found extension %s for name %s",ext,name);
137 for (int i=0;i<numcommands;i++) {
138 if (strcasecmp(ext,commands[i]->extension) == 0) {
139 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found command %s to handle name %s",commands[i]->command,name);
146 ULONG MediaLauncher::getTypeForName(const char *name) {
147 int rt=findCommand(name);
148 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"getTypeForName %s entry %d",name,rt);
149 if (rt>=0) return commands[rt]->mediaType;
150 return MEDIA_TYPE_UNKNOWN;
153 int MediaLauncher::openStream(const char *fname,ULONG xsize,ULONG ysize,const char * command) {
154 if (command == NULL) command="play";
155 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"open stream for %s command %s",fname,command);
156 int cmnum=findCommand(fname);
158 Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to find command for %s",fname);
161 if (pnum >= 0) closeStream();
163 if (pipe(pfd) == -1) {
164 Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to create pipe");
170 Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to fork");
176 dup2(pfd[1],fileno(stdout));
177 close(fileno(stdin));
178 dup2(pfd[1],fileno(stderr));
179 //try to close all open FDs
180 for (int i=0;i<=sysconf(_SC_OPEN_MAX);i++) {
181 if (i != fileno(stderr) && i != fileno(stdout)) close(i);
185 sprintf(buf1,"%u",xsize);
186 sprintf(buf2,"%u",ysize);
187 execlp(commands[cmnum]->command,commands[cmnum]->command,command,fname,buf1,buf2,NULL);
188 //no chance for logging here after close... Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to execlp %s",commands[cmnum]->command);
191 if (fcntl(pnum,F_SETFL,fcntl(pnum,F_GETFL)|O_NONBLOCK) != 0) {
192 Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to set to nonblocking");
201 int MediaLauncher::closeStream() {
202 if (child <= 0) return -1;
203 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"close stream for child %d",child);
205 if (kill(child,0) == 0) {
206 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"trying to kill child %d",child);
209 waitpid(child,NULL,WNOHANG);
210 for (int i=0;i< 150;i++) {
211 if (kill(child,0) == 0) {
213 waitpid(child,NULL,WNOHANG);
216 if (kill(child,0) == 0) {
217 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"child %d aktive after wait, kill -9",child);
220 for (int i=0;i< 100;i++) {
221 if (kill(child,0) == 0) {
225 waitpid(child,NULL,WNOHANG);
231 int MediaLauncher::getNextBlock(ULONG size,unsigned char **buffer,ULONG *readLen) {
232 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"get Block buf %p, len %lu",*buffer,size);
234 Log::getInstance()->log("MediaLauncher",Log::ERR,"stream not open in getnextBlock");
240 to.tv_usec=100000; //100ms
243 FD_SET(pnum,&readfds);
244 int rt=select(pnum+1,&readfds,NULL,NULL,&to);
246 Log::getInstance()->log("MediaLauncher",Log::ERR,"error in select");
250 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"read 0 bytes (no data within 100ms)");
251 waitpid(child,NULL,WNOHANG);
252 if (kill(child,0) != 0) {
253 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"child is dead, returning EOF");
258 if (! FD_ISSET(pnum,&readfds)) {
259 Log::getInstance()->log("MediaLauncher",Log::ERR,"error in select - nothing read");
263 *buffer=(UCHAR *)malloc(size);
266 Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to allocate buffer");
269 ssize_t rdsz=read(pnum,*buffer,size);
270 *readLen=(ULONG)rdsz;
271 Log::getInstance()->log("MediaLauncher",Log::DEBUG,"read %lu bytes",*readLen);
272 if (rdsz == 0) return 1; //EOF
276 bool MediaLauncher::isOpen() {