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