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