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