Define variable allow_playlist_parsing globally.
[mplayer.git] / udp_sync.c
index 8f12ccc..1b338ba 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define _BSD_SOURCE
+
 #include "config.h"
 
 #if !HAVE_WINSOCK2_H
 #include <errno.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -43,6 +46,7 @@
 #include "mp_msg.h"
 #include "help_mp.h"
 #include "udp_sync.h"
+#include "osdep/timer.h"
 
 
 // config options for UDP sync
@@ -53,17 +57,26 @@ const char *udp_ip = "127.0.0.1"; // where the master sends datagrams
                                   // (can be a broadcast address)
 float udp_seek_threshold = 1.0;   // how far off before we seek
 
-// remember where the master is in the file
-static double udp_master_position = -1.0;
-
 // how far off is still considered equal
 #define UDP_TIMING_TOLERANCE 0.02
 
+static void startup(void)
+{
+#if HAVE_WINSOCK2_H
+    static int wsa_started;
+    if (!wsa_started) {
+        WSADATA wd;
+        WSAStartup(0x0202, &wd);
+        wsa_started = 1;
+    }
+#endif
+}
+
 static void set_blocking(int fd, int blocking)
 {
     long sock_flags;
 #if HAVE_WINSOCK2_H
-    sock_flags = blocking;
+    sock_flags = !blocking;
     ioctlsocket(fd, FIONBIO, &sock_flags);
 #else
     sock_flags = fcntl(fd, F_GETFL, 0);
@@ -74,7 +87,7 @@ static void set_blocking(int fd, int blocking)
 
 // gets a datagram from the master with or without blocking.  updates
 // master_position if successful.  if the master has exited, returns 1.
-// returns -1 on error.
+// returns -1 on error or if no message received.
 // otherwise, returns 0.
 static int get_udp(int blocking, double *master_position)
 {
@@ -85,9 +98,14 @@ static int get_udp(int blocking, double *master_position)
 
     static int sockfd = -1;
     if (sockfd == -1) {
+#if HAVE_WINSOCK2_H
+        DWORD tv = 30000;
+#else
         struct timeval tv = { .tv_sec = 30 };
+#endif
         struct sockaddr_in servaddr = { 0 };
 
+        startup();
         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
         if (sockfd == -1)
             return -1;
@@ -95,7 +113,11 @@ static int get_udp(int blocking, double *master_position)
         servaddr.sin_family      = AF_INET;
         servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
         servaddr.sin_port        = htons(udp_port);
-        bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
+        if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
+            closesocket(sockfd);
+            sockfd = -1;
+            return -1;
+        }
 
         setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
 
@@ -105,6 +127,7 @@ static int get_udp(int blocking, double *master_position)
 
     while (-1 != (n = recvfrom(sockfd, mesg, sizeof(mesg)-1, 0,
                                NULL, NULL))) {
+        char *end;
         // flush out any further messages so we don't get behind
         if (chars_received == -1)
             set_blocking(sockfd, 0);
@@ -113,8 +136,14 @@ static int get_udp(int blocking, double *master_position)
         mesg[chars_received] = 0;
         if (strcmp(mesg, "bye") == 0)
             return 1;
-        sscanf(mesg, "%lf", master_position);
+        *master_position = strtod(mesg, &end);
+        if (*end) {
+            mp_msg(MSGT_CPLAYER, MSGL_WARN, "Could not parse udp string!\n");
+            return -1;
+        }
     }
+    if (chars_received == -1)
+        return -1;
 
     return 0;
 }
@@ -128,6 +157,7 @@ void send_udp(const char *send_to_ip, int port, char *mesg)
         static const int one = 1;
         int ip_valid = 0;
 
+        startup();
         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
         if (sockfd == -1)
             exit_player(EXIT_ERROR);
@@ -156,13 +186,29 @@ void send_udp(const char *send_to_ip, int port, char *mesg)
 }
 
 // this function makes sure we stay as close as possible to the master's
-// position.  returns 1 if the master tells us to exit, 0 otherwise.
+// position.  returns 1 if the master tells us to exit,
+// -1 on error and normal timing should be used again, 0 otherwise.
 int udp_slave_sync(MPContext *mpctx)
 {
+    // remember where the master is in the file
+    static double udp_master_position;
+    // whether we timed out before waiting for a master message
+    static int timed_out = -1;
+    // last time we received a valid master message
+    static unsigned last_success;
+    int master_exited;
+
+    if (timed_out < 0) {
+        // initialize
+        udp_master_position = mpctx->sh_video->pts - udp_seek_threshold / 2;
+        timed_out = 0;
+        last_success = GetTimerMS();
+    }
+
     // grab any waiting datagrams without blocking
-    int master_exited = get_udp(0, &udp_master_position);
+    master_exited = get_udp(0, &udp_master_position);
 
-    while (!master_exited) {
+    while (!master_exited || (!timed_out && master_exited < 0)) {
         double my_position = mpctx->sh_video->pts;
 
         // if we're way off, seek to catch up
@@ -188,7 +234,17 @@ int udp_slave_sync(MPContext *mpctx)
         // arrived.  call get_udp again, but this time block until we receive
         // a datagram.
         master_exited = get_udp(1, &udp_master_position);
+        if (master_exited < 0)
+            timed_out = 1;
+    }
+
+    if (master_exited >= 0) {
+        last_success = GetTimerMS();
+        timed_out = 0;
+    } else {
+        master_exited = 0;
+        timed_out |= GetTimerMS() - last_success > 30000;
     }
 
-    return master_exited;
+    return timed_out ? -1 : master_exited;
 }