summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaromil <jaromil@dyne.org>2011-08-16 14:07:24 (GMT)
committer Jaromil <jaromil@dyne.org>2011-08-16 14:07:24 (GMT)
commit55158c93601ef8c7bbe0c44af2982e437682aa28 (patch)
treeae34e25393ae0867ce111cfb4c9012f647d2574f
parent96b122d705e188a52cbd1c90d85ded152c804394 (diff)
updated to latest avremote 0.4 codebase
-rw-r--r--src/avremote.c32
-rw-r--r--src/avremote.h13
-rw-r--r--src/cmdline.c143
-rw-r--r--src/discover.c43
-rw-r--r--src/parsers.c1
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");