- fix build
[oweals/gnunet.git] / src / conversation / gnunet-helper-audio-playback.c
index 74571e5387ec39a09b5571515a4f04ee628dc1fe..97abd443070410cf9e4c57cccc2f0a2fda33a6de 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,26 +94,15 @@ 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
  */
 static int
-stdin_receiver (void *cls, 
+stdin_receiver (void *cls,
                void *client,
                const struct GNUNET_MessageHeader *msg)
 {
@@ -129,7 +113,7 @@ stdin_receiver (void *cls,
   {
   case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO:
     audio = (struct AudioMessage *) msg;
-    
+
     ret = opus_decode_float (dec,
                             (const unsigned char *) &audio[1],
                             ntohs (audio->header.size) - sizeof (struct AudioMessage),
@@ -143,16 +127,17 @@ 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,
                  _("pa_stream_write() failed: %s\n"),
                  pa_strerror (pa_context_errno (context)));
       return GNUNET_OK;
-    }    
+    }
     break;
   default:
     break;
@@ -173,59 +158,23 @@ quit (int ret)
 
 
 /**
- * Write some data to the stream 
+ * Callback when data is there for playback
  */
 static void
-do_stream_write (size_t length)
+stream_write_callback (pa_stream * s,
+                      size_t length,
+                      void *userdata)
 {
-  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))
+  /* unblock 'main' */
+  if (-1 != ready_pipe[1])
   {
     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;
+               "Unblocking main loop!\n");
+    write (ready_pipe[1], "r", 1);
   }
 }
 
 
-/**
- * Callback when data is there for playback
- */
-static void
-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);
-}
-
-
 /**
  * Exit callback for SIGTERM and SIGINT
  */
@@ -243,7 +192,7 @@ exit_signal_callback (pa_mainloop_api * m, pa_signal_event * e, int sig,
  * Pulseaudio stream state callback
  */
 static void
-context_state_callback (pa_context * c, 
+context_state_callback (pa_context * c,
                        void *userdata)
 {
   int p;
@@ -254,7 +203,7 @@ context_state_callback (pa_context * c,
   case PA_CONTEXT_CONNECTING:
   case PA_CONTEXT_AUTHORIZING:
   case PA_CONTEXT_SETTING_NAME:
-    break;    
+    break;
   case PA_CONTEXT_READY:
   {
     GNUNET_assert (!stream_out);
@@ -267,33 +216,35 @@ context_state_callback (pa_context * c,
                  _("pa_stream_new() failed: %s\n"),
                  pa_strerror (pa_context_errno (c)));
       goto fail;
-    }    
-    pa_stream_set_write_callback (stream_out, 
-                                 stream_write_callback,
+    }
+    pa_stream_set_write_callback (stream_out,
+                                 &stream_write_callback,
                                  NULL);
     if ((p =
-        pa_stream_connect_playback (stream_out, NULL, NULL, 0, NULL,
-                                    NULL)) < 0)
+        pa_stream_connect_playback (stream_out, NULL,
+                                    NULL,
+                                    PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
+                                    NULL,  NULL)) < 0)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("pa_stream_connect_playback() failed: %s\n"),
                  pa_strerror (pa_context_errno (c)));
       goto fail;
-    }    
+    }
     break;
-  }  
+  }
   case PA_CONTEXT_TERMINATED:
     quit (0);
     break;
-    
+
   case PA_CONTEXT_FAILED:
   default:
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Connection failure: %s\n"),
                pa_strerror (pa_context_errno (c)));
     goto fail;
-  }  
-  return;  
+  }
+  return;
  fail:
   quit (1);
 }
@@ -309,13 +260,13 @@ pa_init ()
 
   if (!pa_sample_spec_valid (&sample_spec))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                _("Wrong Spec\n"));
-  }  
-  /* set up threaded playback mainloop */  
+  }
+  /* set up threaded playback mainloop */
   if (!(m = pa_threaded_mainloop_new ()))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("pa_mainloop_new() failed.\n"));
   }
   mainloop_api = pa_threaded_mainloop_get_api (m);
@@ -329,9 +280,9 @@ pa_init ()
   /* connect to the main pulseaudio context */
   if (!(context = pa_context_new (mainloop_api, "GNUnet VoIP")))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("pa_context_new() failed.\n"));
-  }  
+  }
   pa_context_set_state_callback (context, context_state_callback, NULL);
 
   if (pa_context_connect (context, NULL, 0, NULL) < 0)
@@ -339,10 +290,10 @@ pa_init ()
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("pa_context_connect() failed: %s\n"),
                pa_strerror (pa_context_errno (context)));
-  }  
+  }
   if (pa_threaded_mainloop_start (m) < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("pa_mainloop_run() failed.\n"));
   }
 }
@@ -379,17 +330,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",
@@ -398,10 +363,10 @@ main (int argc, char *argv[])
     if (0 > ret)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Read error from STDIN: %s\n"), 
+                 _("Read error from STDIN: %s\n"),
                  strerror (errno));
       break;
-    }    
+    }
     if (0 == ret)
       break;
     GNUNET_SERVER_mst_receive (stdin_mst, NULL,