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