GNUnet  0.10.x
gnunet_gst.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2016 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
25 #include "gnunet_gst_def.h"
26 
31 
32 
33 void
34 dump_buffer(unsigned n, const unsigned char* buf)
35 {
36  const unsigned char *p, *end;
37  unsigned i, j;
38 
39  end = buf + n;
40 
41  for (i = 0; ; i += 16) {
42  p = buf + i;
43  for (j = 0; j < 16; j++) {
44  fprintf(stderr, "%02X ", p[j]);
45  if (p + j >= end)
46  goto BREAKOUT;
47  }
48  fprintf(stderr, " ");
49  p = buf + i;
50  for (j = 0; j < 16; j++) {
51  fprintf(stderr, "%c", isprint(p[j]) ? p[j] :
52  '.');
53  if (p + j >= end)
54  goto BREAKOUT;
55  }
56  fprintf(stderr, "\n");
57  }
58 BREAKOUT:
59  return;
60 }
61 
62 /***
63  * load gnunet configuration
64  */
65 void
67 {
68  char *audiobackend_string;
70  GNUNET_CONFIGURATION_load(cfg, "mediahelper.conf");
71 
72  GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "JACK_PP_IN", &d->jack_pp_in);
73  GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "JACK_PP_OUT", &d->jack_pp_out);
74 
75  GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "AUDIOBACKEND", &audiobackend_string);
76 
77  // printf("abstring: %s \n", audiobackend_string);
78 
79  if (0 == strcasecmp (audiobackend_string, "AUTO"))
80  {
81  d->audiobackend = AUTO;
82  } else if (0 == strcasecmp (audiobackend_string, "JACK"))
83  {
84  d->audiobackend = JACK;
85  } else if (0 == strcasecmp (audiobackend_string, "ALSA"))
86  {
87  d->audiobackend = ALSA;
88  } else if (0 == strcasecmp (audiobackend_string, "FAKE"))
89  {
90  d->audiobackend = FAKE;
91  } else if (0 == strcasecmp (audiobackend_string, "TEST"))
92  {
93  d->audiobackend = TEST;
94  } else
95  {
96  d->audiobackend = AUTO;
97  }
98 
99  if (GNUNET_CONFIGURATION_get_value_yesno(cfg, "MEDIAHELPER", "REMOVESILENCE") == GNUNET_YES)
100  {
101  d->dropsilence = TRUE;
102  } else {
103  d->dropsilence = FALSE;
104  }
105 
106  if (GNUNET_CONFIGURATION_get_value_yesno(cfg, "MEDIAHELPER", "NO_GN_HEADERS") == GNUNET_YES)
107  {
108  d->pure_ogg = TRUE;
109  } else {
110  d->pure_ogg = FALSE;
111  }
112 
113 
114  if (GNUNET_CONFIGURATION_get_value_yesno(cfg, "MEDIAHELPER", "USERTP") == GNUNET_YES)
115  {
116  d->usertp = TRUE;
117  } else {
118  d->usertp = FALSE;
119  }
120 
121 // GNUNET_CONFIGURATION_write(cfg, "mediahelper.conf");
122 
123 }
124 
125 static void
126 write_data (const char *ptr, size_t msg_size)
127 {
128  ssize_t ret;
129  size_t off;
130  off = 0;
131  while (off < msg_size)
132  {
133  ret = write (1, &ptr[off], msg_size - off);
134  if (0 >= ret)
135  {
136  if (-1 == ret)
138 // quit (2);
139  }
140  off += ret;
141  }
142 }
143 
144 
145 
146 extern GstFlowReturn
147 on_appsink_new_sample (GstElement * element, GNUNET_gstData * d)
148 {
149  //size of message including gnunet header
150  size_t msg_size;
151 
152  GstSample *s;
153  GstBuffer *b;
154  GstMapInfo map;
155 /*
156  const GstStructure *si;
157  char *si_str;
158  GstCaps *s_caps;
159  char *caps_str;
160 */
161 
162  if (gst_app_sink_is_eos(GST_APP_SINK(element)))
163  return GST_FLOW_OK;
164 
165  //pull sample from appsink
166  s = gst_app_sink_pull_sample (GST_APP_SINK(element));
167 
168  if (s == NULL)
169  return GST_FLOW_OK;
170 
171  if (!GST_IS_SAMPLE (s))
172  return GST_FLOW_OK;
173 
174  b = gst_sample_get_buffer(s);
175 
176  GST_WARNING ("caps are %" GST_PTR_FORMAT, gst_sample_get_caps(s));
177 
178 
179 
180  gst_buffer_map (b, &map, GST_MAP_READ);
181 
182  size_t len;
183  len = map.size;
184  if (len > UINT16_MAX - sizeof (struct AudioMessage))
185  {
186  // this should never happen?
187  printf("GSTREAMER sample too big! \n");
188  exit(20);
189  len = UINT16_MAX - sizeof (struct AudioMessage);
190  }
191 
192  msg_size = sizeof (struct AudioMessage) + len;
193 
194  // copy the data into audio_message
195  GNUNET_memcpy (((char *) &(d->audio_message)[1]), map.data, len);
196  (d->audio_message)->header.size = htons ((uint16_t) msg_size);
197  if (d->pure_ogg)
198  // write the audio_message without the gnunet headers
199  write_data ((const char *) &(d->audio_message)[1], len);
200  else
201  write_data ((const char *) d->audio_message, msg_size);
202 
203  gst_sample_unref(s);
204  return GST_FLOW_OK;
205 }
206 
207 /***
208  * Dump a pipeline graph
209  */
210  extern void
211 pl_graph(GstElement * pipeline)
212 {
213 
214 #ifdef IS_SPEAKER
215  gst_debug_bin_to_dot_file_with_ts(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "playback_helper.dot");
216 
217 #endif
218 #ifdef IS_MIC
219  gst_debug_bin_to_dot_file_with_ts(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "record_helper.dot");
220 
221 #endif
222 
223 
224  // load_configuration();
225 }
226 
227 
228 
229 extern gboolean
230 gnunet_gst_bus_call (GstBus *bus, GstMessage *msg, gpointer data)
231 {
233  "Bus message\n");
234  switch (GST_MESSAGE_TYPE (msg))
235  {
236  case GST_MESSAGE_EOS:
238  "End of stream\n");
239  exit (10);
240  break;
241 
242  case GST_MESSAGE_ERROR:
243  {
244  gchar *debug;
245  GError *error;
246 
247  gst_message_parse_error (msg, &error, &debug);
248  g_free (debug);
249 
251  "Error: %s\n",
252  error->message);
253  g_error_free (error);
254 
255  exit (10);
256  break;
257  }
258  default:
259  break;
260  }
261 
262  return TRUE;
263 }
264 
265 /* called when pipeline changes state */
266  extern void
267 state_changed_cb (GstBus * bus, GstMessage * msg, GNUNET_gstData * d)
268 {
269  GstState old_state, new_state, pending_state;
270 
271  gst_message_parse_state_changed (msg, &old_state, &new_state,
272  &pending_state);
273  switch (new_state)
274  {
275 
276  case GST_STATE_READY:
277 // printf("ready.... \n");
278  //pl_graph(GST_ELEMENT(d->pipeline));
279  break;
280  case GST_STATE_PLAYING:
281 
282  //GST_LOG ("caps are %" GST_PTR_FORMAT, caps);
283 
284  // printf("Playing.... \n");
285  pl_graph(GST_ELEMENT(d->pipeline));
286  break;
287  case GST_STATE_VOID_PENDING:
288  // printf("void_pending.... \n");
289  //pl_graph(GST_ELEMENT(d->pipeline));
290  break;
291  case GST_STATE_NULL:
292  // printf("null.... \n");
293  //pl_graph(GST_ELEMENT(d->pipeline));
294  break;
295 
296  case GST_STATE_PAUSED:
297  // printf("paused.... \n");
298  //pl_graph(GST_ELEMENT(d->pipeline));
299  break;
300  }
301 }
302 
303  static void
304  application_cb (GstBus * bus, GstMessage * msg, GNUNET_gstData * data)
305 {
306  // printf("application cb");
307  return;
308 }
309 
310  static void
311  error_cb (GstBus * bus, GstMessage * msg, GNUNET_gstData * data)
312 {
313  // printf("error cb");
314  return;
315 }
316 
317  static void
318  eos_cb (GstBus * bus, GstMessage * msg, GNUNET_gstData * data)
319 {
320  // printf("eos cb");
321  return;
322 }
323 
324 extern void
326 {
327  GstBus *bus;
328  bus = gst_element_get_bus (GST_ELEMENT(d->pipeline));
329  gst_bus_add_signal_watch (bus);
330  g_signal_connect (G_OBJECT (bus), "message::error", (GCallback) error_cb,
331  d);
332  g_signal_connect (G_OBJECT (bus), "message::eos", (GCallback) eos_cb,
333  d);
334  g_signal_connect (G_OBJECT (bus), "message::state-changed",
335  (GCallback) state_changed_cb, d);
336  g_signal_connect (G_OBJECT (bus), "message::application",
337  (GCallback) application_cb, d);
338  g_signal_connect (G_OBJECT (bus), "message::about-to-finish",
339  (GCallback) application_cb, d);
340  gst_object_unref (bus);
341 
342 }
343 
344 /*
345  * take buffer from gstreamer and feed it to gnunet
346  */
347 /*
348  extern int
349 feed_buffer_to_gnunet (GNUNET_gstData * d)
350 {
351  GstSample *s;
352  GstBuffer *b;
353  GstMapInfo m;
354  size_t len, msg_size;
355  const char *ptr;
356  int phase;
357 
358  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulling...\n");
359  s = gst_app_sink_pull_sample (GST_APP_SINK(d->appsink));
360  if (NULL == s)
361  {
362  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulled NULL\n");
363  return OK;
364  }
365  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "...pulled!\n");
366 
367  const GstStructure *si;
368  char *si_str;
369  GstCaps *s_caps;
370  char *caps_str;
371  si = gst_sample_get_info (s);
372  if (si)
373  {
374  si_str = gst_structure_to_string (si);
375  if (si_str)
376  {
377  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample %s\n", si_str);
378  g_free (si_str);
379  }
380  }
381  else
382  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no info\n");
383  s_caps = gst_sample_get_caps (s);
384  if (s_caps)
385  {
386  caps_str = gst_caps_to_string (s_caps);
387  if (caps_str)
388  {
389  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with caps %s\n", caps_str);
390  g_free (caps_str);
391  }
392  }
393  else
394  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no caps\n");
395 
396  b = gst_sample_get_buffer (s);
397  if (NULL == b || !gst_buffer_map (b, &m, GST_MAP_READ))
398  {
399  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got NULL buffer %p or failed to map the buffer\n", b);
400  gst_sample_unref (s);
401  return FAIL;
402  }
403 
404  len = m.size;
405  if (len > UINT16_MAX - sizeof (struct AudioMessage))
406  {
407  GNUNET_break (0);
408  len = UINT16_MAX - sizeof (struct AudioMessage);
409  }
410  msg_size = sizeof (struct AudioMessage) + len;
411  audio_message.header.size = htons ((uint16_t) msg_size);
412 
413 
414  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415  "Sending %u bytes of audio data\n", (unsigned int) msg_size);
416  for (phase = 0; phase < 2; phase++)
417  {
418  size_t offset;
419  size_t to_send;
420  ssize_t ret;
421  if (0 == phase && !d->pure_ogg)
422  {
423 //#ifdef DEBUG_RECORD_PURE_OGG
424 
425 // if (d->pure_ogg)
426 // break;
427 
428 //#endif
429  ptr = (const char *) &audio_message;
430  to_send = sizeof (audio_message);
431  }
432  else
433  {
434  ptr = (const char *) m.data;
435  to_send = len;
436  }
437  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438  "Sending %u bytes on phase %d\n", (unsigned int) to_send, phase);
439  for (offset = 0; offset < to_send; offset += ret)
440  {
441  ret = write (1, &ptr[offset], to_send - offset);
442  if (0 >= ret)
443  {
444  if (-1 == ret)
445  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446  "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n",
447  (unsigned int) to_send - offset, (unsigned int) offset,
448  (unsigned int) (to_send + offset), phase, strerror (errno));
449  // abort_send = 1;
450  return FAIL;
451  }
452  }
453 
454  // if (abort_send)
455  // break;
456 
457  }
458  gst_buffer_unmap (b, &m);
459  gst_sample_unref (s);
460 }
461 */
462 
463 
464  extern int
465 feed_buffer_to_gst (const char *audio, size_t b_len, GNUNET_gstData * d)
466 {
467  GstBuffer *b;
468  gchar *bufspace;
469  GstFlowReturn flow;
470 
472  "Feeding %u bytes to GStreamer\n",
473  (unsigned int) b_len);
474 
475  bufspace = g_memdup (audio, b_len);
476  b = gst_buffer_new_wrapped (bufspace, b_len);
477  if (NULL == b)
478  {
480  "Failed to wrap a buffer\n");
481  g_free (bufspace);
482  return GNUNET_SYSERR;
483  }
484  if (GST_APP_SRC(d->appsrc) == NULL)
485  exit(10);
486  flow = gst_app_src_push_buffer (GST_APP_SRC(d->appsrc), b);
487  /* They all return GNUNET_OK, because currently player stops when
488  * data stops coming. This might need to be changed for the player
489  * to also stop when pipeline breaks.
490  */
491  switch (flow)
492  {
493  case GST_FLOW_OK:
495  "Fed %u bytes to the pipeline\n",
496  (unsigned int) b_len);
497  break;
498  case GST_FLOW_FLUSHING:
499  /* buffer was dropped, because pipeline state is not PAUSED or PLAYING */
501  "Dropped a buffer\n");
502  break;
503  case GST_FLOW_EOS:
504  /* end of stream */
506  "EOS\n");
507  break;
508  default:
510  "Unexpected push result\n");
511  break;
512  }
513  return GNUNET_OK;
514 }
515 
516 
517 
521  extern GstElement *
522 gst_element_factory_make_debug( gchar *factoryname, gchar *name)
523 {
524  GstElement *element;
525 
526  element = gst_element_factory_make(factoryname,name);
527 
528  if (element == NULL) {
529 
530  printf ("\n Failed to create element - type: %s name: %s \n", factoryname, name);
531  exit(10);
532  return element;
533  } else {
534  return element;
535  }
536 }
537 
538 /*
539  static gboolean
540 gst_element_link_many_debug(...)
541 {
542  va_list arguments;
543  gst_element_link_many(argptr);
544 }
545 
546 #define gst_element_link_many(...) \
547  gst_element_link_many_debug(__VA_ARGS__)
548 */
549  extern void
550 lf(char * msg)
551 {
552  printf("linking elements failed: %s", msg);
553  exit(10);
554 }
555 
556 /***
557  * used to set properties on autoaudiosink's chosen sink
558  */
559 static void
560 autoaudiosink_child_added (GstChildProxy *child_proxy,
561  GObject *object,
562  gchar *name,
563  gpointer user_data)
564 {
565  if (GST_IS_AUDIO_BASE_SRC (object))
566  g_object_set (object,
567  "buffer-time", (gint64) BUFFER_TIME,
568  "latency-time", (gint64) LATENCY_TIME,
569  NULL);
570 }
571 
572 /***
573  * used to set properties on autoaudiosource's chosen sink
574  */
575 static void
576 autoaudiosource_child_added (GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
577 {
578  if (GST_IS_AUDIO_BASE_SRC (object))
579  g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time", (gint64) LATENCY_TIME, NULL);
580 }
581 
582 
583 GstElement *
584 get_pipeline(GstElement *element)
585 {
586  GstPipeline *p;
587 
588  p = GST_PIPELINE (gst_object_get_parent(GST_OBJECT (element)));
589 
590  return GST_ELEMENT (p);
591 }
592 
593  static void
594 decoder_ogg_pad_added (GstElement *element,
595  GstPad *pad,
596  gpointer data)
597 {
598  GstPad *sinkpad;
599  GstElement *decoder = (GstElement *) data;
600 
601  printf("==== ogg pad added callback \n");
602  /* We can now link this pad with the opus-decoder sink pad */
603 // pl_graph(get_pipeline(element));
604  sinkpad = gst_element_get_static_pad (decoder, "sink");
605 
606  gst_pad_link (pad, sinkpad);
607  gst_element_link_many(element, decoder, NULL);
608  gst_object_unref (sinkpad);
609 }
610 
611 
612 int
614 {
615  char readbuf[MAXLINE];
616  int ret;
617  printf("read \n");
618  ret = read (0, readbuf, sizeof (readbuf));
619  if (0 > ret)
620  {
622  _("Read error from STDIN: %d %s\n"),
623  ret, strerror (errno));
624  return FAIL;
625  }
626  //toff += ret;
628  "Received %d bytes of audio data\n",
629  (int) ret);
630  if (0 == ret)
631  return FAIL;
632  //#ifdef DEBUG_READ_PURE_OGG
633 
634  if (d->pure_ogg)
635  {
636  feed_buffer_to_gst (readbuf, ret, d);
637  }
638  else
639  {
640  //#endif
642  readbuf,
643  ret,
644  GNUNET_NO,
645  GNUNET_NO);
646  }
647  return 0;
648 }
649 
658 static int
659 stdin_receiver (void *cls,
660  const struct GNUNET_MessageHeader *msg)
661 {
662  struct AudioMessage *audio;
663  size_t b_len;
664 
665  printf("stdin receiver \n ");
666  dump_buffer (sizeof(msg),
667  (const unsigned char *) msg);
668 
669  switch (ntohs (msg->type))
670  {
672  audio = (struct AudioMessage *) msg;
673 
674  b_len = ntohs (audio->header.size) - sizeof (struct AudioMessage);
675  printf("feeding buffer to gst \n ");
676  feed_buffer_to_gst ((const char *) &audio[1], b_len, cls);
677  break;
678  default:
679  printf("No audio message: %u \n ", ntohs(msg->type));
680  break;
681  }
682  return GNUNET_OK;
683 }
684 
685 
686 GstBin *
688 {
689  GstBin *bin;
690  GstPad *pad, *ghostpad;
691 
692  if ( type == SOURCE )
693  {
694  bin = GST_BIN(gst_bin_new("Gnunet appsrc"));
695 
696 
698  GNUNET_log_setup ("gnunet-helper-audio-playback",
699  "WARNING",
700  NULL));
701 
703  "Audio playback starts\n");
704  printf(" creating appsrc \n ");
705  //d->audio_message.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
706 
707 // d->audio_message = GNUNET_malloc (UINT16_MAX);
708  // d->audio_message = (AudioMessage*)malloc(sizeof(struct AudioMessage));
709 // d->audio_message = GNUNET_malloc(sizeof(struct AudioMessage));
710 
711 
712  //d->audio_message.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
713 
714 
716 
717  if ( d->stdin_mst == NULL)
718  printf("stdin_mst = NULL");
719 
720  d->appsrc = gst_element_factory_make ("appsrc", "appsrc");
721 
722  gst_bin_add_many( bin, d->appsrc, NULL);
723 // gst_element_link_many ( encoder, muxer, NULL);
724 
725  pad = gst_element_get_static_pad (d->appsrc, "src");
726  ghostpad = gst_ghost_pad_new ("src", pad);
727  }
728  if ( type == SINK )
729  {
730  bin = GST_BIN(gst_bin_new("Gnunet appsink"));
731 
732 
734  GNUNET_log_setup ("gnunet-helper-audio-record",
735  "WARNING",
736  NULL));
737 
739  "Audio source starts\n");
740 
741  d->appsink = gst_element_factory_make ("appsink", "appsink");
742 
743  // Move this out of here!
744  d->audio_message = GNUNET_malloc (UINT16_MAX);
746  g_object_set (G_OBJECT (d->appsink), "emit-signals", TRUE, "sync", TRUE, NULL);
747 
748  g_signal_connect (d->appsink, "new-sample",
749  G_CALLBACK (on_appsink_new_sample), &d);
750 
751  gst_bin_add_many( bin, d->appsink, NULL);
752 // gst_element_link_many ( encoder, muxer, NULL);
753 
754  pad = gst_element_get_static_pad (d->appsink, "sink");
755  ghostpad = gst_ghost_pad_new ("sink", pad);
756  }
757 
758  /* set the bin pads */
759  gst_pad_set_active (ghostpad, TRUE);
760  gst_element_add_pad (GST_ELEMENT(bin), ghostpad);
761 
762  gst_object_unref (pad);
763 
764  return bin;
765 }
766 
767  extern GstBin *
769 {
770  GstBin *bin;
771  GstPad *srcpad, *sinkpad, *srcghostpad, *sinkghostpad;
772  GstCaps *rtpcaps;
773  GstElement *encoder, *muxer, *decoder, *demuxer, *jitterbuffer, *rtpcapsfilter;
774 
775  if ( d->usertp == TRUE )
776  {
777  /*
778  * application/x-rtp, media=(string)audio, clock-rate=(int)48000, encoding-name=(string)OPUS, sprop-maxcapturerate=(string)48000, sprop-stereo=(string)0, payload=(int)96, encoding-params=(string)2, ssrc=(uint)630297634, timestamp-offset=(uint)678334141, seqnum-offset=(uint)16938 */
779 /*
780  rtpcaps = gst_caps_new_simple ("application/x-rtp",
781  "media", G_TYPE_STRING, "audio",
782  "clock-rate", G_TYPE_INT, SAMPLING_RATE,
783  "encoding-name", G_TYPE_STRING, "OPUS",
784  "payload", G_TYPE_INT, 96,
785  "sprop-stereo", G_TYPE_STRING, "0",
786  "encoding-params", G_TYPE_STRING, "2",
787  NULL);
788 */
789  rtpcaps = gst_caps_new_simple ("application/x-rtp",
790  "media", G_TYPE_STRING, "audio",
791  "clock-rate", G_TYPE_INT, SAMPLING_RATE,
792  "encoding-name", G_TYPE_STRING, "OPUS",
793  "payload", G_TYPE_INT, 96,
794  "sprop-stereo", G_TYPE_STRING, "0",
795  "encoding-params", G_TYPE_STRING, "2",
796  NULL);
797 
798 
799  rtpcapsfilter = gst_element_factory_make ("capsfilter", "rtpcapsfilter");
800 
801  g_object_set (G_OBJECT (rtpcapsfilter),
802  "caps", rtpcaps,
803  NULL);
804  gst_caps_unref (rtpcaps);
805 
806  }
807 
808 
809  if ( type == ENCODER )
810  {
811  bin = GST_BIN(gst_bin_new("Gnunet audioencoder"));
812 
813  encoder = gst_element_factory_make ("opusenc", "opus-encoder");
814  if ( d->usertp == TRUE )
815  {
816  muxer = gst_element_factory_make ("rtpopuspay", "rtp-payloader");
817  } else {
818  muxer = gst_element_factory_make ("oggmux", "ogg-muxer");
819  }
820  g_object_set (G_OBJECT (encoder),
821  /* "bitrate", 64000, */
822  /* "bandwidth", OPUS_BANDWIDTH_FULLBAND, */
823  "inband-fec", INBAND_FEC_MODE,
824  "packet-loss-percentage", PACKET_LOSS_PERCENTAGE,
825  "max-payload-size", MAX_PAYLOAD_SIZE,
826  "audio", TRUE, /* VoIP, not audio */
827  "frame-size", OPUS_FRAME_SIZE,
828  NULL);
829 
830  if ( d->usertp != TRUE)
831  {
832  g_object_set (G_OBJECT (muxer),
833  "max-delay", OGG_MAX_DELAY,
834  "max-page-delay", OGG_MAX_PAGE_DELAY,
835  NULL);
836  }
837 
838  gst_bin_add_many( bin, encoder, muxer, NULL);
839  gst_element_link_many ( encoder, muxer, NULL);
840  sinkpad = gst_element_get_static_pad(encoder, "sink");
841  sinkghostpad = gst_ghost_pad_new ("sink", sinkpad);
842 
843  srcpad = gst_element_get_static_pad(muxer, "src");
844  srcghostpad = gst_ghost_pad_new ("src", srcpad);
845 
846  }
847  if ( type == DECODER )
848  {
849  bin = GST_BIN(gst_bin_new("Gnunet audiodecoder"));
850 
851  // decoder
852  if ( d->usertp == TRUE )
853  {
854 
855  demuxer = gst_element_factory_make ("rtpopusdepay", "ogg-demuxer");
856  jitterbuffer = gst_element_factory_make ("rtpjitterbuffer", "rtpjitterbuffer");
857  } else {
858  demuxer = gst_element_factory_make ("oggdemux", "ogg-demuxer");
859  }
860  decoder = gst_element_factory_make ("opusdec", "opus-decoder");
861 
862  if ( d->usertp == TRUE )
863  {
864  gst_bin_add_many( bin, rtpcapsfilter, jitterbuffer, demuxer, decoder, NULL);
865  gst_element_link_many ( rtpcapsfilter, jitterbuffer, demuxer, decoder, NULL);
866  sinkpad = gst_element_get_static_pad(rtpcapsfilter, "sink");
867 
868 
869  } else {
870  gst_bin_add_many( bin, demuxer, decoder, NULL);
871 
872  g_signal_connect (demuxer,
873  "pad-added",
874  G_CALLBACK (decoder_ogg_pad_added),
875  decoder);
876 
877  sinkpad = gst_element_get_static_pad(demuxer, "sink");
878  }
879  sinkghostpad = gst_ghost_pad_new ("sink", sinkpad);
880 
881  srcpad = gst_element_get_static_pad(decoder, "src");
882  srcghostpad = gst_ghost_pad_new ("src", srcpad);
883 
884  }
885 
886  // add pads to the bin
887  gst_pad_set_active (sinkghostpad, TRUE);
888  gst_element_add_pad (GST_ELEMENT(bin), sinkghostpad);
889 
890  gst_pad_set_active (srcghostpad, TRUE);
891  gst_element_add_pad (GST_ELEMENT(bin), srcghostpad);
892 
893 
894  return bin;
895 }
896 
897 
898 extern GstBin *
900 {
901  GstBin *bin;
902  GstElement *sink, *source, *queue, *conv, *resampler, *removesilence, *filter;
903  GstPad *pad, *ghostpad;
904  GstCaps *caps;
905  if ( type == SINK ) {
906 
907  bin = GST_BIN(gst_bin_new("Gnunet audiosink"));
908 
909  /* Create all the elements */
910  if ( d->dropsilence == TRUE )
911  {
912  queue = gst_element_factory_make ("queue", "queue");
913  removesilence = gst_element_factory_make ("removesilence", "removesilence");
914  }
915 
916  conv = gst_element_factory_make ("audioconvert", "converter");
917  resampler= gst_element_factory_make ("audioresample", "resampler");
918 
919  if ( d->audiobackend == AUTO )
920  {
921  sink = gst_element_factory_make ("autoaudiosink", "audiosink");
922  g_signal_connect (sink, "child-added", G_CALLBACK (autoaudiosink_child_added), NULL);
923 
924  }
925 
926  if ( d->audiobackend == ALSA )
927  {
928  sink = gst_element_factory_make ("alsaaudiosink", "audiosink");
929  }
930 
931  if ( d->audiobackend == JACK )
932  {
933  sink = gst_element_factory_make ("jackaudiosink", "audiosink");
934 
935  g_object_set (G_OBJECT (sink), "client-name", "gnunet", NULL);
936 
937  if (g_object_class_find_property
938  (G_OBJECT_GET_CLASS (sink), "port-pattern"))
939  {
940 
941 // char *portpattern = "system";
942 
943  g_object_set (G_OBJECT (sink), "port-pattern", d->jack_pp_out,
944  NULL);
945  }
946 
947  }
948 
949  if ( d->audiobackend == FAKE )
950  {
951  sink = gst_element_factory_make ("fakesink", "audiosink");
952  }
953 
954  g_object_set (sink,
955  "buffer-time", (gint64) BUFFER_TIME,
956  "latency-time", (gint64) LATENCY_TIME,
957  NULL);
958 
959  if ( d->dropsilence == TRUE )
960  {
961  // Do not remove silence by default
962  g_object_set( removesilence, "remove", FALSE, NULL);
963  g_object_set( queue, "max-size-buffers", 12, NULL);
964  /*
965  g_signal_connect (source,
966  "need-data",
967  G_CALLBACK(appsrc_need_data),
968  NULL);
969 
970  g_signal_connect (source,
971  "enough-data",
972  G_CALLBACK(appsrc_enough_data),
973  NULL);
974  */
975 /*
976  g_signal_connect (queue,
977  "notify::current-level-bytes",
978  G_CALLBACK(queue_current_level),
979  NULL);
980 
981  g_signal_connect (queue,
982  "underrun",
983  G_CALLBACK(queue_underrun),
984  NULL);
985 
986  g_signal_connect (queue,
987  "running",
988  G_CALLBACK(queue_running),
989  NULL);
990 
991  g_signal_connect (queue,
992  "overrun",
993  G_CALLBACK(queue_overrun),
994  NULL);
995 
996  g_signal_connect (queue,
997  "pushing",
998  G_CALLBACK(queue_pushing),
999  NULL);
1000  */
1001 
1002  }
1003 
1004 
1005 
1006 
1007 
1008  gst_bin_add_many (bin , conv, resampler, sink, NULL);
1009  gst_element_link_many ( conv, resampler, sink, NULL);
1010 
1011  if ( d->dropsilence == TRUE )
1012  {
1013  gst_bin_add_many (bin , queue ,removesilence , NULL);
1014 
1015  if ( !gst_element_link_many ( queue, removesilence, conv, NULL) )
1016  lf ("queue, removesilence, conv ");
1017 
1018  pad = gst_element_get_static_pad (queue, "sink");
1019 
1020  } else {
1021 
1022  pad = gst_element_get_static_pad(conv, "sink");
1023 
1024  }
1025 
1026  ghostpad = gst_ghost_pad_new ("sink", pad);
1027 
1028  } else {
1029  // SOURCE
1030 
1031  bin = GST_BIN(gst_bin_new("Gnunet audiosource"));
1032 
1033  // source = gst_element_factory_make("audiotestsrc", "audiotestsrcbla");
1034 
1035  if (d->audiobackend == AUTO )
1036  {
1037  source = gst_element_factory_make ("autoaudiosrc", "audiosource");
1038  }
1039  if (d->audiobackend == ALSA )
1040  {
1041  source = gst_element_factory_make ("alsasrc", "audiosource");
1042  }
1043  if (d->audiobackend == JACK )
1044  {
1045  source = gst_element_factory_make ("jackaudiosrc", "audiosource");
1046  }
1047  if (d->audiobackend == TEST )
1048  {
1049  source = gst_element_factory_make ("audiotestsrc", "audiosource");
1050  }
1051 
1052  filter = gst_element_factory_make ("capsfilter", "filter");
1053  conv = gst_element_factory_make ("audioconvert", "converter");
1054  resampler= gst_element_factory_make ("audioresample", "resampler");
1055 
1056  if (d->audiobackend == AUTO ) {
1057  g_signal_connect (source, "child-added", G_CALLBACK (autoaudiosource_child_added), NULL);
1058 
1059  } else {
1060  if (GST_IS_AUDIO_BASE_SRC (source))
1061  g_object_set (source, "buffer-time", (gint64) BUFFER_TIME, "latency-time", (gint64) LATENCY_TIME, NULL);
1062  if ( d->audiobackend == JACK ) {
1063  g_object_set (G_OBJECT (source), "client-name", "gnunet", NULL);
1064  if (g_object_class_find_property
1065  (G_OBJECT_GET_CLASS (source), "port-pattern"))
1066  {
1067 
1068  char *portpattern = "moc";
1069 
1070  g_object_set (G_OBJECT (source), "port-pattern", portpattern,
1071  NULL);
1072  }
1073  }
1074  }
1075 
1076  caps = gst_caps_new_simple ("audio/x-raw",
1077  /* "format", G_TYPE_STRING, "S16LE", */
1078  /* "rate", G_TYPE_INT, SAMPLING_RATE,*/
1079  "channels", G_TYPE_INT, OPUS_CHANNELS,
1080  /* "layout", G_TYPE_STRING, "interleaved",*/
1081  NULL);
1082 
1083  g_object_set (G_OBJECT (filter),
1084  "caps", caps,
1085  NULL);
1086  gst_caps_unref (caps);
1087 
1088  gst_bin_add_many (bin , source, filter, conv, resampler, NULL);
1089  gst_element_link_many ( source, filter, conv, resampler, NULL);
1090 
1091  pad = gst_element_get_static_pad (resampler, "src");
1092 
1093 
1094  /* pads */
1095  ghostpad = gst_ghost_pad_new ("src", pad);
1096 
1097  }
1098 
1099  /* set the bin pads */
1100  gst_pad_set_active (ghostpad, TRUE);
1101  gst_element_add_pad (GST_ELEMENT(bin), ghostpad);
1102 
1103  gst_object_unref (pad);
1104 
1105  return bin;
1106 }
static void queue(const char *hostname)
Add hostname to the list of requests to be made.
#define SAMPLING_RATE
static GstElement * resampler
void pl_graph(GstElement *pipeline)
Definition: gnunet_gst.c:211
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct AudioMessage * audio_message
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO.
Definition: conversation.h:60
static GstElement * conv
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
GstPipeline * pipeline
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static GstElement * pipeline
Main pipeline.
#define OGG_MAX_PAGE_DELAY
Maximum delay for sending out a page, in ns.
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
void gg_load_configuration(GNUNET_gstData *d)
Definition: gnunet_gst.c:66
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create(void)
Create a new configuration object.
gboolean gnunet_gst_bus_call(GstBus *bus, GstMessage *msg, gpointer data)
Definition: gnunet_gst.c:230
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static int stdin_receiver(void *cls, const struct GNUNET_MessageHeader *msg)
Message callback.
Definition: gnunet_gst.c:659
GstElement * gst_element_factory_make_debug(gchar *factoryname, gchar *name)
debug making elements
Definition: gnunet_gst.c:522
static int ret
Final status code.
Definition: gnunet-arm.c:89
static void autoaudiosource_child_added(GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
Definition: gnunet_gst.c:576
static void error_cb(GstBus *bus, GstMessage *msg, GNUNET_gstData *data)
Definition: gnunet_gst.c:311
#define OGG_MAX_DELAY
Maximum delay in multiplexing streams, in ns.
static struct GNUNET_CONTAINER_MultiPeerMap * map
Handle to the map used to store old latency values for peers.
int GNUNET_CONFIGURATION_load(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Load configuration.
static void autoaudiosink_child_added(GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
Definition: gnunet_gst.c:560
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
GstBin * get_app(GNUNET_gstData *d, int type)
Definition: gnunet_gst.c:687
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
GstElement * get_pipeline(GstElement *element)
Definition: gnunet_gst.c:584
#define MAX_PAYLOAD_SIZE
Maximal size of a single opus packet.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
static GstElement * sink
#define MAXLINE
How much data to read in one go.
GstFlowReturn on_appsink_new_sample(GstElement *element, GNUNET_gstData *d)
Definition: gnunet_gst.c:147
#define GNUNET_memcpy(dst, src, n)
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
void state_changed_cb(GstBus *bus, GstMessage *msg, GNUNET_gstData *d)
Definition: gnunet_gst.c:267
Message to transmit the audio (between client and helpers).
Definition: conversation.h:55
#define OPUS_FRAME_SIZE
Size of a single frame fed to the encoder, in ms.
GstBin * get_coder(GNUNET_gstData *d, int type)
Definition: gnunet_gst.c:768
static void eos_cb(GstBus *bus, GstMessage *msg, GNUNET_gstData *data)
Definition: gnunet_gst.c:318
static char buf[2048]
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:87
int GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition: mst.c:116
static struct GNUNET_CONTAINER_BloomFilter * filter
Bloomfilter to quickly tell if we don&#39;t have the content.
#define gst_element_factory_make(element, name)
Definition: gnunet_gst.h:36
struct GNUNET_MessageStreamTokenizer * stdin_mst
void lf(char *msg)
Definition: gnunet_gst.c:550
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
GstElement * appsrc
static GstElement * source
Appsrc instance into which we write data for the pipeline.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet_gst.c:30
#define PACKET_LOSS_PERCENTAGE
Expected packet loss to prepare for, in percents.
static GstElement * demuxer
const char * name
#define LATENCY_TIME
Min number of microseconds to buffer in audiosink.
static void write_data(const char *ptr, size_t msg_size)
Definition: gnunet_gst.c:126
configuration data
Definition: configuration.c:85
#define GNUNET_log(kind,...)
GstElement * appsink
#define GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO
Message to transmit the audio between helper and speaker/microphone library.
int feed_buffer_to_gst(const char *audio, size_t b_len, GNUNET_gstData *d)
Definition: gnunet_gst.c:465
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
Header for all communications.
#define GNUNET_YES
Definition: gnunet_common.h:80
GstBin * get_audiobin(GNUNET_gstData *d, int type)
Definition: gnunet_gst.c:899
static void decoder_ogg_pad_added(GstElement *element, GstPad *pad, gpointer data)
Definition: gnunet_gst.c:594
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
static GstElement * decoder
uint32_t data
The data value.
static void application_cb(GstBus *bus, GstMessage *msg, GNUNET_gstData *data)
Definition: gnunet_gst.c:304
void dump_buffer(unsigned n, const unsigned char *buf)
Definition: gnunet_gst.c:34
#define GNUNET_malloc(size)
Wrapper around malloc.
void gg_setup_gst_bus(GNUNET_gstData *d)
Definition: gnunet_gst.c:325
#define OPUS_CHANNELS
Number of channels.
#define INBAND_FEC_MODE
Set to 1 to enable forward error correction.
#define BUFFER_TIME
Max number of microseconds to buffer in audiosink.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
int gnunet_read(GNUNET_gstData *d)
Definition: gnunet_gst.c:613