diff options
author | Jaromil <jaromil@dyne.org> | 2011-08-16 14:07:24 (GMT) |
---|---|---|
committer | Jaromil <jaromil@dyne.org> | 2011-08-16 14:07:24 (GMT) |
commit | 55158c93601ef8c7bbe0c44af2982e437682aa28 (patch) | |
tree | ae34e25393ae0867ce111cfb4c9012f647d2574f | |
parent | 96b122d705e188a52cbd1c90d85ded152c804394 (diff) |
updated to latest avremote 0.4 codebase
-rw-r--r-- | src/avremote.c | 32 | ||||
-rw-r--r-- | src/avremote.h | 13 | ||||
-rw-r--r-- | src/cmdline.c | 143 | ||||
-rw-r--r-- | src/discover.c | 43 | ||||
-rw-r--r-- | src/parsers.c | 1 |
5 files changed, 155 insertions, 77 deletions
diff --git a/src/avremote.c b/src/avremote.c index 808df8d..70360b1 100644 --- a/src/avremote.c +++ b/src/avremote.c @@ -49,13 +49,6 @@ #include <avremote.h> -/* Buffer Boundaries - the following defines set the maximum size we allow for buffers used */ -#define MAX_HOSTNAME_SIZE 256 -#define MAX_MSG_SIZE 2048 -#define MAX_HDR_SIZE 512 -#define MAX_RES_SIZE 1401 -#define MAX_META_SIZE 2048 upnp_t *create_upnp() { @@ -90,7 +83,7 @@ void free_upnp(upnp_t *upnp) { free(upnp); } -int connect_upnp(upnp_t *upnp, char *hostname, int port) { +int connect_upnp(upnp_t *upnp) { struct sockaddr_in serveraddr; // const struct sockaddr *serveraddr; struct hostent *host; @@ -109,9 +102,9 @@ int connect_upnp(upnp_t *upnp, char *hostname, int port) { } /* gethostbyname: get the server's DNS entry */ - host = gethostbyname(hostname); + host = gethostbyname(upnp->hostname); if (host == NULL) { - fprintf(stderr,"error: no such host as %s (%s)\n", hostname, strerror(errno)); + fprintf(stderr,"error: no such host as %s (%s)\n", upnp->hostname, strerror(errno)); return(-1); } @@ -120,7 +113,7 @@ int connect_upnp(upnp_t *upnp, char *hostname, int port) { serveraddr.sin_family = AF_INET; bcopy((char *)host->h_addr, (char *)&serveraddr.sin_addr.s_addr, host->h_length); - serveraddr.sin_port = htons(port); + serveraddr.sin_port = htons(upnp->port); /* connect: create a connection with the server */ if (connect(sockfd, (const struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) { @@ -128,8 +121,6 @@ int connect_upnp(upnp_t *upnp, char *hostname, int port) { return(-1); } - snprintf(upnp->hostname, 255, "%s",hostname); - upnp->port = port; upnp->sockfd = sockfd; return(sockfd); @@ -145,7 +136,7 @@ void render_uri_meta(upnp_t *upnp, char *path) { struct stat fs; if( stat(path,&fs) < 0 ) { - fprintf(stderr,"error: cannot load file %s (%s)\n", path, strerror(errno)); + // fprintf(stderr,"error: cannot load file %s (%s)\n", path, strerror(errno)); filesize = 0; } else filesize = fs.st_size; @@ -154,7 +145,12 @@ void render_uri_meta(upnp_t *upnp, char *path) { pdir = dirname(dir); strncpy(file,path,1023); pfile = basename(file); - snprintf(url,1023,"file://%s",path); + if( strncmp(path,"http://",7)==0 ) + snprintf(url,1023,"%s",path); + else if( strncmp(path,"ftp://",6)==0 ) + snprintf(url,1023,"%s",path); + else + snprintf(url,1023,"file://%s",path); snprintf(upnp->meta,MAX_META_SIZE-1,UPNP_META_FORMAT, url, @@ -220,7 +216,9 @@ int recv_upnp(upnp_t *upnp, int timeout) { } int print_upnp(upnp_t *upnp) { - fprintf(stderr,"header (%u bytes):\n\n%s\n\n",upnp->hdrlen, upnp->hdr); - fprintf(stderr,"message (%u bytes):\n\n%s\n\n",upnp->msglen, upnp->msg); + fprintf(stderr,"header (%u bytes):\n",upnp->hdrlen); + fprintf(stdout,"%s\n\n", upnp->hdr); + fprintf(stderr,"message (%u bytes):\n",upnp->msglen); + fprintf(stdout,"%s\n\n", upnp->msg); } diff --git a/src/avremote.h b/src/avremote.h index e1e80e6..cee5155 100644 --- a/src/avremote.h +++ b/src/avremote.h @@ -21,6 +21,14 @@ #ifndef __AVREMOTE_H__ #define __AVREMOTE_H__ +/* Buffer Boundaries + the following defines set the maximum size we allow for buffers used */ +#define MAX_HOSTNAME_SIZE 256 +#define MAX_MSG_SIZE 2048 +#define MAX_HDR_SIZE 512 +#define MAX_RES_SIZE 1401 +#define MAX_META_SIZE 2048 + // messages get rendered in this structure // allocated and freed with create/free_upnp typedef struct { @@ -72,7 +80,10 @@ typedef struct { upnp_t *create_upnp(); void free_upnp(upnp_t *upnp); -int connect_upnp(upnp_t *upnp, char *hostname, int port); +int upnp_discover(upnp_t *upnp); + +// should set upnp-> hostname and port before calling this +int connect_upnp(upnp_t *upnp); /* Available AVTransport actions: diff --git a/src/cmdline.c b/src/cmdline.c index 73c40ef..ab0211a 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -32,7 +32,6 @@ #include <errno.h> #include <avremote.h> -#include <discover.h> #include <parsers.h> // our exit codes are shell style: 1 is error, 0 is success @@ -47,6 +46,7 @@ char server[512]; int port = 0; int dry_run = 0; int discover = 0; +int pipe_stdin = 0; parser_f *parser = NULL; @@ -70,18 +70,20 @@ void cmdline(int argc, char **argv) { " This is free software: you are free to change and redistribute it.\n" " The latest AVTransport sourcecode is published on <%s>\n" "\n" - "Syntax: avremote [options] command [file]\n" + "Syntax: avremote [options] [command] [args...]\n" "\n" "Commands:\n" "\n" -#ifdef USE_UPNP - " discover search for upnp devices on the network\n" -#endif + " discover scan for upnp devices on the network\n" " load load a file and prepare it for playback\n" + " mode set playback mode (NORMAL or REPEAT_ONE)\n" " play start playing the selected file\n" " pause pause currently running playback\n" " stop stop playback and return to menu\n" " get get the current status of the device\n" + " jump seek to a position in time (00:00:00)\n" + "\n" + " none means load and play URL, or use - to read xml from stdin\n" "\n" "Options:\n" "\n" @@ -99,7 +101,7 @@ void cmdline(int argc, char **argv) { case 'v': fprintf(stderr,"%s - simple commandline tool to send AVTransport commands over UPNP\n" - "version %s (Apr/2011) by Jaromil - Netherlands Media Art Institute\n" + "version %s by Jaromil - Netherlands Media Art Institute\n" "Copyright (C) 2011 NIMk Artlab, License GNU AGPL v3+\n" "This is free software: you are free to change and redistribute it\n", PACKAGE, VERSION); @@ -139,47 +141,44 @@ void cmdline(int argc, char **argv) { discover = 1; } else if(!dry_run) { // check requires args - if(!command[0]) { - fprintf(stderr,"command not specified, see %s -h for help\n",argv[0]); - exit(1); - } - - - // not in dry run nor discovery, check for necessary options - if(!port) { - fprintf(stderr,"port not specified, use -p\n"); - exit(1); - } - - if(!server[0]) { - fprintf(stderr,"server not specified, using localhost\n"); - sprintf(server,"%s","localhost"); - } + if( command[0]=='-' && !command[1]) pipe_stdin++; + + } } int main(int argc, char **argv) { upnp_t *upnp; + int found; cmdline(argc, argv); + upnp = create_upnp(); + + // no server specified, force discovery + if(!server[0] || !port) discover = 1; -#ifdef USE_UPNP - if (discover) + if (discover && !dry_run) { - fprintf(stderr,"Performing upnp autodiscovery...\n"); - upnp_discover(); - exit(0); + fprintf(stderr,"Performing upnp discovery...\n"); + found = upnp_discover(upnp); + + if(found != 1) { + fprintf(stderr,"Please specify a target device host and port.\n"); + free_upnp(upnp); + exit(0); + } + } -#endif - - upnp = create_upnp(); + + // commandline or detection found explicit addresses + snprintf(upnp->hostname, MAX_HOSTNAME_SIZE-1,"%s",server); + upnp->port = port; if(!dry_run) { - - if ( connect_upnp (upnp, server, port) < 0 ) + if ( connect_upnp (upnp) < 0 ) { fprintf(stderr,"can't connect to %s:%u: operation aborted.\n", server, port); exit(ERR); @@ -193,15 +192,49 @@ int main(int argc, char **argv) { upnp->port = 0; } - - // command parsing is a cascade switch on single letters - // this is supposedly faster than strcmp + + // pipe raw xml commands from stdin + if(pipe_stdin) { + int res; + int in = 0; + char raw[8192]; + + while( !feof(stdin) ) + { + in = fread(raw,1,8191,stdin); + res = write(upnp->sockfd,raw,in); + if(res != in) + fprintf(stderr,"upnp pipe wrote only %u of %u bytes",res, in); + recv_upnp(upnp, 1000); + fprintf(stderr,"%s\n",upnp->res); + } + free_upnp(upnp); + exit(0); + } + + /* command parsing is a cascade switch on single letters + this is supposedly faster than strcmp. mapping: + + D iscovery + L oad + P lay + PA use + S top + G et + M ode + J ump + + */ switch(command[0]) { + case 'd': // discovery + // was processed earlier + break; + case 'l': // load url render_uri_meta(upnp,filename); render_upnp(upnp,"SetAVTransportURI", upnp->meta); - send_upnp(upnp); + // send_upnp(upnp); break; case 'p': @@ -230,12 +263,40 @@ int main(int argc, char **argv) { break; + case 'm': // set the playmode: + // "NORMAL", "REPEAT_ONE", "REPEAT_ALL", "RANDOM" + { + char tmp[256]; + snprintf(tmp,255,"<NewPlayMode>%s</NewPlayMode>",filename); + render_upnp(upnp,"SetPlayMode",tmp); + } + break; + + case 'j': // jump aka seek + // <SeekMode> and <SeekTarget> + { + char tmp[512]; + snprintf(tmp,511,"<Unit>REL_TIME</Unit><Target>%s</Target>",filename); + render_upnp(upnp,"Seek",tmp); + } + break; + default: - fprintf(stderr,"warning: command not recognized, sending anyway.\n"); - render_upnp(upnp,command,""); - - // free_upnp(upnp); - // exit(1); + if(!command[0]) break; + fprintf(stderr,"warning: command not recognized, loading and playing as url\n"); + + // load + render_uri_meta(upnp,command); + render_upnp(upnp,"SetAVTransportURI", upnp->meta); + send_upnp(upnp); + recv_upnp(upnp, 1000); + + // must re-connect socket between commands + close(upnp->sockfd); + upnp->sockfd = 0; + connect_upnp(upnp); + + render_upnp(upnp,"Play","<Speed>1</Speed>"); } if (dry_run) diff --git a/src/discover.c b/src/discover.c index 2da2ffa..ecce8d4 100644 --- a/src/discover.c +++ b/src/discover.c @@ -23,15 +23,15 @@ #include <stdio.h> #include <string.h> -#ifdef USE_UPNP - #include <miniwget.h> #include <miniupnpc.h> #include <upnpcommands.h> #include <upnperrors.h> +#include <avremote.h> + -int upnp_discover() +int upnp_discover(upnp_t *upnp) { const char * rootdescurl = 0; const char * multicastif = 0; @@ -41,10 +41,18 @@ int upnp_discover() struct UPNPDev *dev; struct UPNPUrls urls; struct IGDdatas data; - int r; + int r, err; + int num = 0; + + // damn programmers who change API prototypes in headers + // without versioning. + +/* #ifdef UPNPDISCOVER_SUCCESS */ + devlist = upnpDiscover(1000, multicastif, minissdpdpath, 0, 0, &err); +/* #else */ +/* devlist = upnpDiscover(1000, multicastif, minissdpdpath, 0); */ +/* #endif */ - devlist = upnpDiscover(1000, multicastif, minissdpdpath, 0); - r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); if (!r) { fprintf(stderr,"no valid UPnP devices found\n"); @@ -52,10 +60,10 @@ int upnp_discover() } else if (r == 3) { // 3 = an UPnP root device has been found (not an IGD) dev = devlist; - while(dev) { + for( dev = devlist; dev; dev = dev->pNext, num++) { // parse out ip and port from url - char ip[256]; + char ip[MAX_HOSTNAME_SIZE]; char port[64]; char tmp[512]; char *p, *pp; @@ -66,7 +74,7 @@ int upnp_discover() // ip do p+=2; while(*p != '/'); p++; pp = p; do pp++; while(*pp != ':'); *pp = 0; - snprintf(ip,255,"%s",p); + snprintf(ip,MAX_HOSTNAME_SIZE-1,"%s",p); // port p = pp+1; pp = p; @@ -74,20 +82,19 @@ int upnp_discover() snprintf(port,63,"%s",p); fprintf(stderr,"%s\t%s\t%s\t%s\n", dev->st, dev->descURL, ip, port); - dev = dev->pNext; + + if(!num) { // first found + sscanf(port, "%u", &upnp->port); + snprintf(upnp->hostname, MAX_HOSTNAME_SIZE-1, "%s", ip); + } + } - /* fprintf(stderr, - " controlURL: %s\n" - " ipcondescURL: %s\n" - " controlURL_CIF: %s\n", - urls.controlURL, urls.ipcondescURL, urls.controlURL_CIF); */ - FreeUPNPUrls(&urls); + } freeUPNPDevlist(devlist); devlist = 0; - return(r); + return(num); } -#endif diff --git a/src/parsers.c b/src/parsers.c index f37f0b0..0063c6f 100644 --- a/src/parsers.c +++ b/src/parsers.c @@ -70,6 +70,7 @@ void GetTransportInfo(char *res) { char status[MAX]; char speed[MAX]; char *p; + fprintf(stderr,"#\tstate\tstatus\tspeed\n"); p = extract_xml(state, res, "CurrentTransportState"); |