chiark / gitweb /
disorder-playrtp --monitor option to keep track of how far off
[disorder] / clients / playrtp.c
index a5542dbd51fbc3ce5d5f09a9264a3cd20be24137..fe750b2f47d0692a7e8a5c9cb26e8e03dd727e20 100644 (file)
@@ -64,6 +64,7 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <fcntl.h>
+#include <math.h>
 
 #include "log.h"
 #include "mem.h"
@@ -94,14 +95,13 @@ static FILE *logfp;
 
 /** @brief Output device */
 
-/** @brief Minimum low watermark
- *
- * We'll stop playing if there's only this many samples in the buffer. */
-unsigned minbuffer = 2 * 44100 / 10;  /* 0.2 seconds */
+/** @brief Buffer low watermark in samples */
+unsigned minbuffer = 4 * (2 * 44100) / 10;  /* 0.4 seconds */
 
-/** @brief Maximum buffer size
+/** @brief Maximum buffer size in samples
  *
- * We'll stop reading from the network if we have this many samples. */
+ * We'll stop reading from the network if we have this many samples.
+ */
 static unsigned maxbuffer;
 
 /** @brief Received packets
@@ -212,6 +212,7 @@ static const struct option options[] = {
   { "pause-mode", required_argument, 0, 'P' },
   { "socket", required_argument, 0, 's' },
   { "config", required_argument, 0, 'C' },
+  { "monitor", no_argument, 0, 'M' },
   { 0, 0, 0, 0 }
 };
 
@@ -433,11 +434,14 @@ static void *listen_thread(void attribute((unused)) *arg) {
  */
 void playrtp_fill_buffer(void) {
   /* Discard current buffer contents */
-  while(nsamples)
+  while(nsamples) {
+    //fprintf(stderr, "%8u/%u (%u) DROPPING\n", nsamples, maxbuffer, minbuffer);
     drop_first_packet();
+  }
   info("Buffering...");
   /* Wait until there's at least minbuffer samples available */
   while(nsamples < minbuffer) {
+    //fprintf(stderr, "%8u/%u (%u) FILLING\n", nsamples, maxbuffer, minbuffer);
     pthread_cond_wait(&cond, &lock);
   }
   /* Start from whatever is earliest */
@@ -531,8 +535,6 @@ static size_t playrtp_callback(void *buffer,
       *bufptr++ = (int16_t)ntohs(*ptr++);
       --i;
     }
-    /* We don't junk the packet here; a subsequent call to
-     * playrtp_next_packet() will dispose of it (if it's actually done with). */
   } else {
     /* There is no suitable packet.  We introduce 0s up to the next packet, or
      * to fill the buffer if there's no next packet or that's too many.  The
@@ -553,6 +555,8 @@ static size_t playrtp_callback(void *buffer,
   }
   /* Advance timestamp */
   next_timestamp += samples;
+  /* Junk obsolete packets */
+  playrtp_next_packet();
   pthread_mutex_unlock(&lock);
   return samples;
 }
@@ -577,6 +581,7 @@ int main(int argc, char **argv) {
   union any_sockaddr mgroup;
   const char *dumpfile = 0;
   pthread_t ltid;
+  int monitor = 0;
   static const int one = 1;
 
   static const struct addrinfo prefs = {
@@ -592,7 +597,7 @@ int main(int argc, char **argv) {
   mem_init();
   if(!setlocale(LC_CTYPE, "")) fatal(errno, "error calling setlocale");
   backend = uaudio_apis[0];
-  while((n = getopt_long(argc, argv, "hVdD:m:x:L:R:M:aocC:re:P:", options, 0)) >= 0) {
+  while((n = getopt_long(argc, argv, "hVdD:m:x:L:R:aocC:re:P:M", options, 0)) >= 0) {
     switch(n) {
     case 'h': help();
     case 'V': version("disorder-playrtp");
@@ -616,10 +621,11 @@ int main(int argc, char **argv) {
     case 'r': dumpfile = optarg; break;
     case 'e': backend = &uaudio_command; uaudio_set("command", optarg); break;
     case 'P': uaudio_set("pause-mode", optarg); break;
+    case 'M': monitor = 1; break;
     default: fatal(0, "invalid option");
     }
   }
-  if(config_read(0)) fatal(0, "cannot read configuration");
+  if(config_read(0, NULL)) fatal(0, "cannot read configuration");
   if(!maxbuffer)
     maxbuffer = 2 * minbuffer;
   argc -= optind;
@@ -736,6 +742,7 @@ int main(int argc, char **argv) {
            rcvbuf, target_rcvbuf);
   } else
     info("default socket receive buffer %d", rcvbuf);
+  //info("minbuffer %u maxbuffer %u", minbuffer, maxbuffer);
   if(logfp)
     info("WARNING: -L option can impact performance");
   if(control_socket) {
@@ -777,6 +784,7 @@ int main(int argc, char **argv) {
   if((err = pthread_create(&ltid, 0, queue_thread, 0)))
     fatal(err, "pthread_create queue_thread");
   pthread_mutex_lock(&lock);
+  time_t lastlog = 0;
   for(;;) {
     /* Wait for the buffer to fill up a bit */
     playrtp_fill_buffer();
@@ -799,8 +807,30 @@ int main(int argc, char **argv) {
     while(nsamples >= minbuffer
          || (nsamples > 0
              && contains(pheap_first(&packets), next_timestamp))) {
+      if(monitor) {
+        time_t now = time(0);
+
+        if(now >= lastlog + 60) {
+          int offset = nsamples - minbuffer;
+          double offtime = (double)offset / (uaudio_rate * uaudio_channels);
+          info("%+d samples off (%d.%02ds, %d bytes)",
+               offset,
+               (int)fabs(offtime) * (offtime < 0 ? -1 : 1),
+               (int)(fabs(offtime) * 100) % 100,
+               offset * uaudio_bits / CHAR_BIT);
+          lastlog = now;
+        }
+      }
+      //fprintf(stderr, "%8u/%u (%u) PLAYING\n", nsamples, maxbuffer, minbuffer);
       pthread_cond_wait(&cond, &lock);
     }
+#if 0
+    if(nsamples) {
+      struct packet *p = pheap_first(&packets);
+      fprintf(stderr, "nsamples=%u (%u) next_timestamp=%"PRIx32", first packet is [%"PRIx32",%"PRIx32")\n",
+              nsamples, minbuffer, next_timestamp,p->timestamp,p->timestamp+p->nsamples);
+    }
+#endif
     /* Stop playing for a bit until the buffer re-fills */
     pthread_mutex_unlock(&lock);
     backend->deactivate();