-much better latency
authorChristian Grothoff <christian@grothoff.org>
Thu, 3 Oct 2013 00:05:47 +0000 (00:05 +0000)
committerChristian Grothoff <christian@grothoff.org>
Thu, 3 Oct 2013 00:05:47 +0000 (00:05 +0000)
src/conversation/gnunet-conversation-test.c
src/conversation/gnunet-helper-audio-playback.c
src/conversation/gnunet-helper-audio-record.c

index 7f8c522285898399ce61cf6b95c261306376439f..c55f9f951b919cbd3d86acb938e660f071c49324 100644 (file)
@@ -147,7 +147,9 @@ switch_to_speaker (void *cls,
   fprintf (stderr, "\nPlaying...");
   for (rec=rec_head; NULL != rec; rec = rec->next)
   {
-    fprintf (stderr, "<-%u\n", (unsigned int) rec->size);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Replaying %u bytes\n",
+               (unsigned int) rec->size);
     speaker->play (speaker->cls,
                   rec->size,
                   &rec[1]);
@@ -173,7 +175,9 @@ record (void *cls,
 {
   struct Recording *rec;
 
-  fprintf (stderr, "->%u\n", (unsigned int) data_size);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Recorded %u bytes\n",
+             (unsigned int) data_size);
   rec = GNUNET_malloc (sizeof (struct Recording) + data_size);
   rec->size = data_size;
   memcpy (&rec[1], data, data_size);
index 74571e5387ec39a09b5571515a4f04ee628dc1fe..6b2a3df6ddede77f79c07479d8dd0c1855481cff 100644 (file)
@@ -73,11 +73,6 @@ static pa_context *context;
  */
 static pa_stream *stream_out;
 
-/**
- * Pulseaudio io events
- */
-static pa_io_event *stdio_event;
-
 /**
  * OPUS decoder
  */
@@ -99,20 +94,9 @@ static int pcm_length;
 static int frame_size;
 
 /**
- * Audio buffer
- */
-static void *buffer;
-
-/**
- * Length of audio buffer
+ * Pipe we use to signal the main loop that we are ready to receive.
  */
-static size_t buffer_length;
-
-/**
- * Read index for transmit buffer
- */
-static size_t buffer_index;
-
+static int ready_pipe[2];
 
 /**
  * Message callback
@@ -143,9 +127,10 @@ stdin_receiver (void *cls,
       return GNUNET_OK;
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-               "Decoded frame\n");
+               "Decoded frame with %u bytes\n",
+               ntohs (audio->header.size));
     if (pa_stream_write
-       (stream_out, (uint8_t *) pcm_buffer, pcm_length, NULL, 0,
+       (stream_out, pcm_buffer, pcm_length, NULL, 0,
         PA_SEEK_RELATIVE) < 0)
     {      
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -172,44 +157,6 @@ quit (int ret)
 }
 
 
-/**
- * Write some data to the stream 
- */
-static void
-do_stream_write (size_t length)
-{
-  size_t l;
-
-  GNUNET_assert (0 != length);
-  if ( (! buffer) || (! buffer_length) )
-    return;    
-
-  l = length;
-  if (l > buffer_length)
-    l = buffer_length;
-  if (0 > pa_stream_write (stream_out, 
-                          (uint8_t *) buffer + buffer_index, 
-                          l, 
-                          NULL, 0,
-                          PA_SEEK_RELATIVE))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               _("pa_stream_write() failed: %s\n"),
-               pa_strerror (pa_context_errno (context)));
-    quit (1);
-    return;
-  }  
-  buffer_length -= l;
-  buffer_index += l;
-  if (! buffer_length)
-  {
-    pa_xfree (buffer);
-    buffer = NULL;
-    buffer_index = buffer_length = 0;
-  }
-}
-
-
 /**
  * Callback when data is there for playback
  */
@@ -218,11 +165,13 @@ stream_write_callback (pa_stream * s,
                       size_t length, 
                       void *userdata)
 {
-  if (stdio_event)
-    mainloop_api->io_enable (stdio_event, PA_IO_EVENT_INPUT);
-  if (!buffer)
-    return;
-  do_stream_write (length);
+  /* unblock 'main' */
+  if (-1 != ready_pipe[1])
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               "Unblocking main loop!\n");
+    write (ready_pipe[1], "r", 1);
+  }
 }
 
 
@@ -269,7 +218,7 @@ context_state_callback (pa_context * c,
       goto fail;
     }    
     pa_stream_set_write_callback (stream_out, 
-                                 stream_write_callback,
+                                 &stream_write_callback,
                                  NULL);
     if ((p =
         pa_stream_connect_playback (stream_out, NULL, NULL, 0, NULL,
@@ -279,7 +228,7 @@ context_state_callback (pa_context * c,
                  _("pa_stream_connect_playback() failed: %s\n"),
                  pa_strerror (pa_context_errno (c)));
       goto fail;
-    }    
+    }
     break;
   }  
   case PA_CONTEXT_TERMINATED:
@@ -379,17 +328,31 @@ main (int argc, char *argv[])
 
   char readbuf[MAXLINE];
   struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst;
+  char c;
+  ssize_t ret;
 
   GNUNET_assert (GNUNET_OK ==
                 GNUNET_log_setup ("gnunet-helper-audio-playback",
                                   "DEBUG",
                                   "/tmp/helper-audio-playback"));
+  if (0 != pipe (ready_pipe))
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
+    return 1;
+  }
   stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, NULL);
   opus_init ();
   pa_init ();
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+             "Waiting for PulseAudio to be ready.\n");
+  GNUNET_assert (1 == read (ready_pipe[0], &c, 1));
+  close (ready_pipe[0]);
+  close (ready_pipe[1]);
+  ready_pipe[0] = -1;
+  ready_pipe[1] = -1;
   while (1)
   {
-    ssize_t ret = read (0, readbuf, sizeof (readbuf));   
+    ret = read (0, readbuf, sizeof (readbuf));   
     toff += ret;
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Received %d bytes of audio data (total: %llu)\n",
index c14b35fe6ad8bf0307ea44090688e9c6762b9d42..b3828498f1e108bab443643d21d2244013f802b5 100644 (file)
@@ -221,6 +221,11 @@ stream_read_callback (pa_stream * s,
 {
   const void *data;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Got %u/%u bytes of PCM data\n",
+             length,
+             pcm_length);
+
   GNUNET_assert (NULL != s);
   GNUNET_assert (length > 0);
   if (stdio_event)
@@ -288,6 +293,7 @@ stream_state_callback (pa_stream * s, void *userdata)
   case PA_STREAM_READY:
     {
       const pa_buffer_attr *a;
+
       char cmt[PA_CHANNEL_MAP_SNPRINT_MAX],
        sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
       
@@ -307,7 +313,7 @@ stream_state_callback (pa_stream * s, void *userdata)
        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                    _("Buffer metrics: maxlength=%u, fragsize=%u\n"),
                    a->maxlength, a->fragsize);
-      }      
+      }       
       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                  _("Using sample spec '%s', channel map '%s'.\n"),
                  pa_sample_spec_snprint (sst, sizeof (sst),
@@ -321,7 +327,7 @@ stream_state_callback (pa_stream * s, void *userdata)
                  pa_stream_get_device_index (s),
                  pa_stream_is_suspended (s) ? "" : "not ");
     }    
-    break;    
+    break;
   case PA_STREAM_FAILED:
   default:
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
@@ -350,6 +356,7 @@ context_state_callback (pa_context * c,
   case PA_CONTEXT_READY:
   {
     int r;
+    pa_buffer_attr na;
     
     GNUNET_assert (!stream_in);    
     GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
@@ -362,9 +369,13 @@ context_state_callback (pa_context * c,
                  pa_strerror (pa_context_errno (c)));
       goto fail;
     }
-    pa_stream_set_state_callback (stream_in, stream_state_callback, NULL);
-    pa_stream_set_read_callback (stream_in, stream_read_callback, NULL);
-    if ((r = pa_stream_connect_record (stream_in, NULL, NULL, 0)) < 0)
+    pa_stream_set_state_callback (stream_in, &stream_state_callback, NULL);
+    pa_stream_set_read_callback (stream_in, &stream_read_callback, NULL);
+    memset (&na, 0, sizeof (na));
+    na.maxlength = UINT32_MAX;
+    na.fragsize = pcm_length;
+    if ((r = pa_stream_connect_record (stream_in, NULL, &na, 
+                                      PA_STREAM_EARLY_REQUESTS)) < 0)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("pa_stream_connect_record() failed: %s\n"),
@@ -416,8 +427,8 @@ pa_init ()
   /* listen to signals */
   r = pa_signal_init (mainloop_api);
   GNUNET_assert (r == 0);
-  pa_signal_new (SIGINT, exit_signal_callback, NULL);
-  pa_signal_new (SIGTERM, exit_signal_callback, NULL);
+  pa_signal_new (SIGINT, &exit_signal_callback, NULL);
+  pa_signal_new (SIGTERM, &exit_signal_callback, NULL);
 
   /* connect to the main pulseaudio context */
 
@@ -426,7 +437,7 @@ pa_init ()
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
                _("pa_context_new() failed.\n"));
   }  
-  pa_context_set_state_callback (context, context_state_callback, NULL);
+  pa_context_set_state_callback (context, &context_state_callback, NULL);
   if (pa_context_connect (context, NULL, 0, NULL) < 0)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -475,6 +486,8 @@ main (int argc, char *argv[])
                 GNUNET_log_setup ("gnunet-helper-audio-record",
                                   "DEBUG",
                                   "/tmp/helper-audio-record"));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Audio source starts\n");
   audio_message = GNUNET_malloc (UINT16_MAX);
   audio_message->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
   opus_init ();