summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaromil <jaromil@dyne.org>2012-05-31 10:16:34 (GMT)
committer Jaromil <jaromil@dyne.org>2012-05-31 10:16:34 (GMT)
commit4a903f314b44a1d6be5048f4aed3ba39f055ac0a (patch)
tree329a794c17a09f3916b5a724673c2396a46343a0
parente659ab7911bd3a8ad087e189c8747a3d84a715b7 (diff)
calculate length with ffmpeg and force stop+stop after movie length expires
this should be the final fix for the 4h freeze, which in 1.0 was occurring less regularly, but still present
-rw-r--r--scripts/S88hdsync38
-rw-r--r--src/hdsync_cli.cpp138
2 files changed, 110 insertions, 66 deletions
diff --git a/scripts/S88hdsync b/scripts/S88hdsync
index f6b1333..158e33c 100644
--- a/scripts/S88hdsync
+++ b/scripts/S88hdsync
@@ -4,7 +4,7 @@
#
# 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 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@@ -65,8 +65,6 @@ export TOTAL_CHANNELS
# retrieve network details
get_ip
-# retrieve application details
-get_bins $APPROOT
UPNPPORT="`lsof -a -i4 -sTCP:LISTEN -c DMARender -F n | awk -v FS=':' '/^n/ {print $2}'`"
export UPNPPORT
@@ -91,7 +89,7 @@ killall smbtree
# if test $WATCHDOGTIMER -gt 0; then
# #start watchdog timer
-# echo "starting watchdog, movielenght is $WATCHDOGTIMER"
+# echo "starting watchdog, movielenght is $WATCHDOGTIMER"
# ps | grep watchdog | grep -v grep
# if [ $? -ne 0 ]; then
# rm -f /tmp/hdsync.error
@@ -101,6 +99,21 @@ killall smbtree
# fi
file=`ls $USBROOT/video`
+seconds=0
+if [ -r /apps/ffmpeg/bin/ffmpeg ]; then
+ echo "FFMpeg found, detecting video length"
+ /apps/ffmpeg/bin/ffmpeg -i "$USBROOT/video/$file" 2>&1 \
+ | awk '/Duration/ {print $2}' \
+ | sed 's/\./:/g' > /tmp/hdsync.timecode
+ hours=`cat /tmp/hdsync.timecode | cut -d: -f1`
+ minutes=`cat /tmp/hdsync.timecode | cut -d: -f2`
+ seconds=`cat /tmp/hdsync.timecode | cut -d: -f3`
+ hours=`expr $hours \* 3600`
+ minutes=`expr $minutes \* 60`
+ seconds=`expr $seconds + $minutes`
+ seconds=`expr $seconds + $hours`
+ echo "Video file length in seconds: $seconds"
+fi
cat <<EOF >> /tmp/hdsync.log
Launching hdsync for channel $HDSYNC_CHANNEL of $TOTAL_CHANNELS
@@ -114,13 +127,20 @@ $APPROOT/bin/hdsync -p $UPNPPORT -s localhost \
EOF
while true; do
-
# loop infinitely
- $APPROOT/bin/hdsync -p $UPNPPORT -s localhost \
- $HDSYNC_CHANNEL $TOTAL_CHANNELS \
- "$USBROOT/video/$file" >> /tmp/hdsync.log
-done
+ if [ $seconds = 0 ]; then
+ $APPROOT/bin/hdsync -p $UPNPPORT -s localhost -i eth0 \
+ $HDSYNC_CHANNEL $TOTAL_CHANNELS \
+ "$USBROOT/video/$file" 2>&1 >> /tmp/hdsync.log
+ else
+ $APPROOT/bin/hdsync -p $UPNPPORT -s localhost -i eth0 -l $seconds \
+ $HDSYNC_CHANNEL $TOTAL_CHANNELS \
+ "$USBROOT/video/$file" 2>&1 >> /tmp/hdsync.log
+
+ fi
+
+done
diff --git a/src/hdsync_cli.cpp b/src/hdsync_cli.cpp
index d597cc8..db504a0 100644
--- a/src/hdsync_cli.cpp
+++ b/src/hdsync_cli.cpp
@@ -1,5 +1,5 @@
/* HDSync
-
+
(c) 2011-2012 Montevideo / Time Based Arts (aka NIMk.nl)
2011-2012 Denis Roio <jaromil@dyne.org>
@@ -7,12 +7,12 @@
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
@@ -33,7 +33,7 @@
#include <sys/types.h>
#include <ifaddrs.h>
-#include <netinet/in.h>
+#include <netinet/in.h>
#include <arpa/inet.h>
#include <avremote.h>
@@ -58,6 +58,7 @@ int port = 0;
int dryrun = 0;
int chanID = 0;
int chanTOT = 0;
+int videolen = 0;
char ethiface[64];
@@ -76,7 +77,7 @@ char pgmaddr[256];
zmq_msg_t request;
// we use only getopt, no _long
-static const char *short_options = "-hvta:i:s:p:";
+static const char *short_options = "-hvta:i:s:p:l:";
void cmdline(int argc, char **argv);
@@ -102,7 +103,7 @@ int shout(const char *message, int flags) {
// extract a string from a message received:
// PREFIX;MESSAGE;
-// message should be a char of 512 bytes
+// message should be a char of 512 bytes
int expect(const char *prefix, char *message, int flags) {
zmq_msg_t reply;
char res[512];
@@ -117,19 +118,19 @@ int expect(const char *prefix, char *message, int flags) {
// printf ("Received response\n");
snprintf(res,511,"%s",(char*)zmq_msg_data(&reply));
zmq_msg_close (&reply);
-
+
// parse the response and if ACK insert it in uniq list
if( strncmp(res,prefix,pfxlen) == 0) {
// quick and secure string parsing
p = res; while(*p != ';') p++; p++;
pp = p; while(*pp != ';') pp++; *pp='\0';
-
+
// *p has the ip string
snprintf(message,511,"%s",p);
// printf("Expected prefix %s found %s\n",prefix,message);
return(0);
}
-
+
return(1);
}
@@ -158,7 +159,7 @@ int handshake() {
// somehow listening to ACK only doesn't works
snprintf(message,255,"OFFER;%s;",IPv4);
while(1) {
-
+
shout(message, 0);
if( expect("ACK",res, 0) == 0) {
@@ -175,20 +176,20 @@ int handshake() {
printf("New listener: %s : %u\n",peers[c]->hostname, peers[c]->port);
listindex++;
}
-
+
if(listindex==listmax) { // goal reached
printf("Sending ready signals to listeners\n");
///////////////////////////////////////////////
shout("READY", 0);
break; // break offer loop
} // if listmax reached
-
+
} // if ACK response
zmq_sleep(1);
} // offer while loop
-
+
} else { // all other channels listen
/////////
@@ -201,19 +202,19 @@ int handshake() {
while (1) {
- // Wait for offer
+ // Wait for offer
while( expect("OFFER", res, 0) !=0); // blocking
// reply with ACK
shout(message, 0);
-
+
while( expect("READY", res, 0) !=0); // blocking
printf ("Received ready signal\n");
break; // quit loop on ready signal
-
+
}
}
-
+
return(1);
}
@@ -227,15 +228,15 @@ int main(int argc, char **argv) {
cmdline(argc, argv);
if(!filename[0]) {
- fprintf(stderr,"not enough args specified on commandline, see help.\n");
+ printf("not enough args specified on commandline, see help.\n");
exit(ERR);
}
- fprintf(stderr,"HDSync starting for channel %u of %u\n",chanID, chanTOT);
- fprintf(stderr,"will sync and play video: %s\n", filename);
+ printf("HDSync starting for channel %u of %u\n",chanID, chanTOT);
+ printf("will sync and play video: %s\n", filename);
if( ! get_address() ) {
- fprintf(stderr,"Error getting own address.\n");
+ printf("Error getting own address.\n");
exit(ERR);
}
@@ -247,13 +248,13 @@ int main(int argc, char **argv) {
if(!dryrun) {
if ( connect_upnp (peers[0]) < 0 ) {
- fprintf(stderr,"can't connect to local UPNP: operation aborted.\n");
+ printf("can't connect to local UPNP: operation aborted.\n");
// free all peers array
for(c=0; c<chanTOT; c++)
free_upnp(peers[c]);
exit(ERR);
} else {
- fprintf(stderr,"UPNP connected to %s:%u\n",
+ printf("UPNP connected to %s:%u\n",
peers[0]->hostname, peers[0]->port);
close(peers[0]->sockfd);
peers[0]->sockfd = 0;
@@ -275,13 +276,13 @@ int main(int argc, char **argv) {
/// END OF INIT
- ////////////////
+ ////////////////
////////////////////
if(! handshake()) {
// no error return so far, just running endless untill contact is established
- fprintf(stderr,"error establishing contact with all desired channels, aborting.\n");
+ printf("error establishing contact with all desired channels, aborting.\n");
exit(ERR);
}
@@ -290,14 +291,14 @@ int main(int argc, char **argv) {
//////////////////////
if(dryrun) { // DRYRUN
printf("Dry run\n");
-
+
// testing sync with no real playback
zmq_sleep(1);
if(chanID==1) { // offer should send sync
printf("Prepare to offer sync\n");
-
+
zmq_sleep(3);
shout("SYNC;;", 0);
@@ -308,16 +309,16 @@ int main(int argc, char **argv) {
while( expect("SYNC", tmp, 0) !=0); // blocking
}
-
+
//////////////////////
} else { // RUN FOR REAL, FUN FOR REAL
//////////////////////
-
+
// load, play and pause in sequence
// break and reopen connection in between
-
+
// stop player
connect_upnp(peers[0]);
@@ -337,7 +338,7 @@ int main(int argc, char **argv) {
recv_upnp(peers[0], 1000);
close(peers[0]->sockfd);
peers[0]->sockfd = 0;
-
+
zmq_sleep(1);
// play
@@ -354,7 +355,7 @@ int main(int argc, char **argv) {
// while(playing < listmax)
zmq_sleep(5);
-
+
connect_upnp(peers[0]);
snprintf(tmp,511,"<Unit>REL_TIME</Unit><Target>%s</Target>",filename);
render_upnp(peers[0],"Seek","<Unit>REL_TIME</Unit><Target>00:00:00</Target>");
@@ -370,11 +371,11 @@ int main(int argc, char **argv) {
recv_upnp(peers[0], 1000);
close(peers[0]->sockfd);
peers[0]->sockfd = 0;
-
+
// prepare upnp play message
connect_upnp(peers[0]);
render_upnp(peers[0],"Play","<Speed>1</Speed>");
-
+
if(chanID==1) { // offer should send sync
zmq_sleep(2);
@@ -382,7 +383,7 @@ int main(int argc, char **argv) {
shout("SYNC", 0); // send sync signal
} else {
-
+
// wait for sync
while( expect("SYNC", tmp, 0) !=0); // blocking
@@ -398,12 +399,33 @@ int main(int argc, char **argv) {
close(peers[0]->sockfd);
peers[0]->sockfd = 0;
-
+
} // if(test|real)
- while( ! get_state("STOPPED") ) zmq_sleep(1);
+ if(!videolen)
+ while( ! get_state("STOPPED") ) zmq_sleep(1);
+ else { // we know the videolen
+ printf("video length specified, waiting %u seconds then forcing loop\n",videolen);
- fprintf(stderr,"Software shutdown\n");
+ zmq_sleep(videolen);
+
+ // stop player twice, to fix the infamous 4h freeze
+ connect_upnp(peers[0]);
+ render_upnp(peers[0],"Stop","");
+ send_upnp(peers[0]);
+ recv_upnp(peers[0], 1000);
+ close(peers[0]->sockfd);
+ peers[0]->sockfd = 0;
+ zmq_sleep(1);
+ connect_upnp(peers[0]);
+ render_upnp(peers[0],"Stop","");
+ send_upnp(peers[0]);
+ recv_upnp(peers[0], 1000);
+ close(peers[0]->sockfd);
+ peers[0]->sockfd = 0;
+ }
+
+ printf("Software shutdown\n");
zmq_close (sock_shout);
@@ -421,7 +443,7 @@ int main(int argc, char **argv) {
}
free(peers);
- fprintf(stderr,"Done.\n");
+ printf("Done.\n");
exit(0);
}
@@ -436,7 +458,7 @@ void cmdline(int argc, char **argv) {
res = getopt(argc, argv, short_options);
switch(res) {
case 'h':
- fprintf(stderr,
+ printf(
"%s %s - prepare and start synced playback of video across devices\n"
"\n"
" Copyright (C) 2011-2012 Jaromil @ Dyne.org , License GNU AGPL v3+\n"
@@ -452,6 +474,7 @@ void cmdline(int argc, char **argv) {
" -t dry run to test without a server (print out rendered xml)\n"
" -a manually specified pgm:// address for broadcast range\n"
" -i network interface to use (default: eth0)\n"
+ " -l length of the video in seconds (gives long term stability)\n"
"\n"
" -h print this help\n"
" -v version information for this tool\n"
@@ -462,13 +485,13 @@ void cmdline(int argc, char **argv) {
exit(0);
case 'v':
- fprintf(stderr,"%s - simple commandline tool to send AVTransport commands over UPNP\n"
+ printf("%s - simple commandline tool to send AVTransport commands over UPNP\n"
"version %s distributed by Montevideo/NIMk\n"
"Copyright (C) 2011-2012 Jaromil @ Dyne.org, License GNU AGPL v3+\n"
"This is free software: you are free to change and redistribute it\n",
PACKAGE, VERSION);
exit(0);
-
+
case 's':
snprintf(server,511,"%s",optarg);
break;
@@ -489,11 +512,14 @@ void cmdline(int argc, char **argv) {
dryrun = 1;
break;
+ case 'l':
+ sscanf (optarg, "%u", &videolen);
+ break;
case '?':
- fprintf(stderr,"unrecognized option: %s\n",optarg);
+ printf("unrecognized option: %s\n",optarg);
break;
-
+
case 1:
if(!chanID) {
sscanf(optarg,"%u",&chanID);
@@ -523,12 +549,12 @@ int get_address() {
pgmaddr[0] = NULL; // zero if iface not found
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
- // is a valid IP4 Address
- tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
- char addressBuffer[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
- // printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
+ if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
+ // is a valid IP4 Address
+ tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+ char addressBuffer[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
+ // printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
if( strcmp(ifa->ifa_name, ethiface) == 0) {
strncpy(IPv4, addressBuffer, 16);
if( pgmstatic[0] != 0 )
@@ -539,7 +565,7 @@ int get_address() {
}
}
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
-
+
if(!pgmaddr[0]) {
printf("Error: ethernet interface %s is not configured\n",ethiface);
return(0);
@@ -557,7 +583,7 @@ char *extract_xml(char *dest, char *haystack, const char *needle) {
p = strstr(haystack, needle);
if (!p) {
- fprintf(stderr, "parser cannot find \"%s\" in:\n%s\n",needle, haystack);
+ printf( "parser cannot find \"%s\" in:\n%s\n",needle, haystack);
return NULL;
}
// as you can see, i had a lot of fun with pointers when i was a kid
@@ -586,12 +612,10 @@ int get_state(const char *match) {
p = extract_xml(status, p, "CurrentTransportStatus");
p = extract_xml(speed, p, "CurrentSpeed");
- // fprintf(stderr,"#\tstate\tstatus\tspeed\n");
- // fprintf(stderr,"TInfo:\t%s\t%s\t%s\n", state, status, speed);
+ // printf("#\tstate\tstatus\tspeed\n");
+ // printf("TInfo:\t%s\t%s\t%s\n", state, status, speed);
if( strcmp(match, state) == 0) return(1);
-
+
return(0);
}
-
-