aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am8
-rw-r--r--src/conversation/Makefile.am58
-rwxr-xr-xsrc/conversation/gnunet-helper-audio-playback-gst.c372
-rwxr-xr-xsrc/conversation/gnunet-helper-audio-record-gst.c334
4 files changed, 757 insertions, 15 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 94345a5bd..0aa1ec4d1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,9 +24,11 @@ if HAVE_EXPERIMENTAL
24endif 24endif
25 25
26 26
27if HAVE_PULSE 27if BUILD_PULSE_HELPERS
28if HAVE_OPUS 28CONVERSATION_DIR = conversation
29 CONVERSATION_DIR = conversation 29else
30if BUILD_GST_HELPERS
31CONVERSATION_DIR = conversation
30endif 32endif
31endif 33endif
32 34
diff --git a/src/conversation/Makefile.am b/src/conversation/Makefile.am
index e455ba45e..a11763cc5 100644
--- a/src/conversation/Makefile.am
+++ b/src/conversation/Makefile.am
@@ -2,6 +2,10 @@ SUBDIRS = .
2 2
3plugindir = $(libdir)/gnunet 3plugindir = $(libdir)/gnunet
4 4
5if MINGW
6 WINFLAGS = -no-undefined -Wl,--export-all-symbols
7endif
8
5AM_CPPFLAGS = \ 9AM_CPPFLAGS = \
6 $(GNUNET_CPPFLAGS) \ 10 $(GNUNET_CPPFLAGS) \
7 -I$(top_srcdir)/src/include \ 11 -I$(top_srcdir)/src/include \
@@ -69,26 +73,30 @@ bin_PROGRAMS = \
69libexec_PROGRAMS = \ 73libexec_PROGRAMS = \
70 gnunet-service-conversation 74 gnunet-service-conversation
71 75
72if HAVE_PULSE
73if HAVE_OPUS
74libexec_PROGRAMS += \
75 gnunet-helper-audio-record \
76 gnunet-helper-audio-playback
77endif
78endif
79
80
81check_PROGRAMS = \ 76check_PROGRAMS = \
82 test_conversation_api \ 77 test_conversation_api \
83 test_conversation_api_reject \ 78 test_conversation_api_reject \
84 test_conversation_api_twocalls 79 test_conversation_api_twocalls
85 80
86if HAVE_PULSE 81if BUILD_PULSE_HELPERS
87if HAVE_OPUS 82AUDIO_HELPER_RECD=gnunet-helper-audio-record
88TESTS = $(check_PROGRAMS) 83AUDIO_HELPER_PLAY=gnunet-helper-audio-playback
84AUDIO_TESTS=$(check_PROGRAMS)
85else
86if BUILD_GST_HELPERS
87AUDIO_HELPER_RECD=gnunet-helper-audio-record
88AUDIO_HELPER_PLAY=gnunet-helper-audio-playback
89AUDIO_TESTS=$(check_PROGRAMS)
89endif 90endif
90endif 91endif
91 92
93libexec_PROGRAMS += \
94 $(AUDIO_HELPER_RECD) \
95 $(AUDIO_HELPER_PLAY)
96
97TESTS = $(AUDIO_TESTS)
98
99if BUILD_PULSE_HELPERS
92gnunet_helper_audio_record_SOURCES = \ 100gnunet_helper_audio_record_SOURCES = \
93 gnunet-helper-audio-record.c 101 gnunet-helper-audio-record.c
94gnunet_helper_audio_record_LDADD = \ 102gnunet_helper_audio_record_LDADD = \
@@ -106,6 +114,32 @@ gnunet_helper_audio_playback_LDADD = \
106 $(INTLLIBS) 114 $(INTLLIBS)
107gnunet_helper_audio_playback_LDFLAGS = \ 115gnunet_helper_audio_playback_LDFLAGS = \
108 $(GNUNET_LDFLAGS) $(WINFLAGS) 116 $(GNUNET_LDFLAGS) $(WINFLAGS)
117else
118if BUILD_GST_HELPERS
119gnunet_helper_audio_record_SOURCES = \
120 gnunet-helper-audio-record-gst.c
121gnunet_helper_audio_record_LDADD = \
122 $(top_builddir)/src/util/libgnunetutil.la \
123 $(GST_LIBS) \
124 $(INTLLIBS)
125gnunet_helper_audio_record_LDFLAGS = \
126 $(GNUNET_LDFLAGS) $(WINFLAGS) $(GST_LDFLAGS)
127gnunet_helper_audio_record_CFLAGS = \
128 $(GST_CFLAGS)
129
130gnunet_helper_audio_playback_SOURCES = \
131 gnunet-helper-audio-playback-gst.c
132gnunet_helper_audio_playback_LDADD = \
133 $(top_builddir)/src/util/libgnunetutil.la \
134 -lopus \
135 $(GST_LIBS) \
136 $(INTLLIBS)
137gnunet_helper_audio_playback_LDFLAGS = \
138 $(GNUNET_LDFLAGS) $(WINFLAGS) $(GST_LDFLAGS)
139gnunet_helper_audio_playback_CFLAGS = \
140 $(GST_CFLAGS)
141endif
142endif
109 143
110gnunet_service_conversation_SOURCES = \ 144gnunet_service_conversation_SOURCES = \
111 gnunet-service-conversation.c 145 gnunet-service-conversation.c
diff --git a/src/conversation/gnunet-helper-audio-playback-gst.c b/src/conversation/gnunet-helper-audio-playback-gst.c
new file mode 100755
index 000000000..d6d2316fc
--- /dev/null
+++ b/src/conversation/gnunet-helper-audio-playback-gst.c
@@ -0,0 +1,372 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file conversation/gnunet-helper-audio-playback-gst.c
22 * @brief program to playback audio data to the speaker (GStreamer version)
23 * @author LRN
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_protocols.h"
28#include "conversation.h"
29#include "gnunet_constants.h"
30#include "gnunet_core_service.h"
31
32#include <gst/gst.h>
33#include <gst/app/gstappsrc.h>
34#include <gst/audio/gstaudiobasesrc.h>
35#include <glib.h>
36
37#include <opus/opus.h>
38#include <opus/opus_types.h>
39
40/**
41 * How much data to read in one go
42 */
43#define MAXLINE 4096
44
45#define SAMPLING_RATE 48000
46
47#define CHANNELS 1
48
49#define FRAME_SIZE (SAMPLING_RATE / 50)
50
51#define PCM_LENGTH (FRAME_SIZE * CHANNELS * sizeof (int16_t))
52
53/**
54 * Max number of microseconds to buffer in audiosink.
55 * Default is 200000
56 */
57#define BUFFER_TIME 1000
58
59/**
60 * Min number of microseconds to buffer in audiosink.
61 * Default is 10000
62 */
63#define LATENCY_TIME 1000
64
65/**
66 * Tokenizer for the data we get from stdin
67 */
68struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst;
69
70/**
71 * Main pipeline.
72 */
73static GstElement *pipeline;
74
75/**
76 * Appsrc instance into which we write data for the pipeline.
77 */
78static GstElement *source;
79
80/**
81 * OPUS decoder
82 */
83static OpusDecoder *dec;
84
85
86/**
87 * Set to 1 to break the reading loop
88 */
89static int abort_read;
90
91
92/**
93 * OPUS initialization
94 */
95static void
96opus_init ()
97{
98 int err;
99 int channels = 1;
100
101 dec = opus_decoder_create (SAMPLING_RATE, channels, &err);
102}
103
104void
105sink_child_added (GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
106{
107 if (GST_IS_AUDIO_BASE_SRC (object))
108 g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time", (gint64) LATENCY_TIME, NULL);
109}
110
111static void
112quit ()
113{
114 if (NULL != source)
115 gst_app_src_end_of_stream (GST_APP_SRC (source));
116 if (NULL != pipeline)
117 gst_element_set_state (pipeline, GST_STATE_NULL);
118 abort_read = 1;
119}
120
121static gboolean
122bus_call (GstBus *bus, GstMessage *msg, gpointer data)
123{
124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bus message\n");
125 switch (GST_MESSAGE_TYPE (msg))
126 {
127 case GST_MESSAGE_EOS:
128 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "End of stream\n");
129 quit ();
130 break;
131
132 case GST_MESSAGE_ERROR:
133 {
134 gchar *debug;
135 GError *error;
136
137 gst_message_parse_error (msg, &error, &debug);
138 g_free (debug);
139
140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error: %s\n", error->message);
141 g_error_free (error);
142
143 quit ();
144 break;
145 }
146 default:
147 break;
148 }
149
150 return TRUE;
151}
152
153
154static void
155signalhandler (int s)
156{
157 quit ();
158}
159
160
161/**
162 * Message callback
163 */
164static int
165stdin_receiver (void *cls,
166 void *client,
167 const struct GNUNET_MessageHeader *msg)
168{
169 struct AudioMessage *audio;
170 GstBuffer *b;
171 int16_t *bufspace;
172 GstFlowReturn flow;
173 int ret;
174
175 switch (ntohs (msg->type))
176 {
177 case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO:
178 audio = (struct AudioMessage *) msg;
179
180 bufspace = (int16_t *) g_malloc (PCM_LENGTH);
181
182 ret = opus_decode (dec,
183 (const unsigned char *) &audio[1],
184 ntohs (audio->header.size) - sizeof (struct AudioMessage),
185 bufspace,
186 FRAME_SIZE, 0);
187 if (ret < 0)
188 {
189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
190 "Opus decoding failed: %d\n",
191 ret);
192 g_free (bufspace);
193 return GNUNET_OK;
194 }
195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
196 "Decoded frame with %u bytes\n",
197 ntohs (audio->header.size));
198
199 b = gst_buffer_new_wrapped (bufspace, ret * sizeof (int16_t));
200 if (NULL == b)
201 {
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to wrap a buffer\n");
203 g_free (bufspace);
204 return GNUNET_SYSERR;
205 }
206
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pushing...\n");
208 flow = gst_app_src_push_buffer (GST_APP_SRC (source), b);
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pushed!\n");
210 /* They all return GNUNET_OK, because currently player stops when
211 * data stops coming. This might need to be changed for the player
212 * to also stop when pipeline breaks.
213 */
214 switch (flow)
215 {
216 case GST_FLOW_OK:
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fed %u bytes to the pipeline\n",
218 (unsigned int) ret * sizeof (int16_t));
219 break;
220 case GST_FLOW_FLUSHING:
221 /* buffer was dropped, because pipeline state is not PAUSED or PLAYING */
222 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Dropped a buffer\n");
223 break;
224 case GST_FLOW_EOS:
225 /* end of stream */
226 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "EOS\n");
227 break;
228 default:
229 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unexpected push result\n");
230 break;
231 }
232 break;
233 default:
234 break;
235 }
236 return GNUNET_OK;
237}
238
239
240int
241main (int argc, char **argv)
242{
243 GstElement *conv, *resampler, *sink;
244 GstBus *bus;
245 GstCaps *caps;
246 guint bus_watch_id;
247 uint64_t toff;
248
249 typedef void (*SignalHandlerPointer) (int);
250
251 SignalHandlerPointer inthandler, termhandler;
252
253 inthandler = signal (SIGINT, signalhandler);
254 termhandler = signal (SIGTERM, signalhandler);
255
256#ifdef WINDOWS
257 setmode (0, _O_BINARY);
258#endif
259
260 opus_init ();
261
262 /* Initialisation */
263 gst_init (&argc, &argv);
264
265 GNUNET_assert (GNUNET_OK ==
266 GNUNET_log_setup ("gnunet-helper-audio-playback",
267 "WARNING",
268 NULL));
269
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271 "Audio sink starts\n");
272
273 stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, NULL);
274
275 /* Create gstreamer elements */
276 pipeline = gst_pipeline_new ("audio-player");
277 source = gst_element_factory_make ("appsrc", "audio-input");
278 conv = gst_element_factory_make ("audioconvert", "converter");
279 resampler= gst_element_factory_make ("audioresample", "resampler");
280 sink = gst_element_factory_make ("autoaudiosink", "audiosink");
281
282 if (!pipeline || !source || !conv || !resampler || !sink)
283 {
284 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
285 "One element could not be created. Exiting.\n");
286 return -1;
287 }
288
289 g_signal_connect (sink, "child-added", G_CALLBACK (sink_child_added), NULL);
290
291 caps = gst_caps_new_simple ("audio/x-raw",
292 "format", G_TYPE_STRING, "S16LE",
293 "rate", G_TYPE_INT, SAMPLING_RATE,
294 "channels", G_TYPE_INT, CHANNELS,
295 "layout", G_TYPE_STRING, "interleaved",
296 NULL);
297 gst_app_src_set_caps (GST_APP_SRC (source), caps);
298 gst_caps_unref (caps);
299
300 /* Keep a reference to it, we operate on it */
301 gst_object_ref (GST_OBJECT (source));
302
303 /* Set up the pipeline */
304
305 /* we feed appsrc as fast as possible, it just blocks when it's full */
306 g_object_set (G_OBJECT (source),
307 "format", GST_FORMAT_TIME,
308 "block", TRUE,
309 "is-live", TRUE,
310 NULL);
311
312 /* we add a message handler */
313 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
314 bus_watch_id = gst_bus_add_watch (bus, bus_call, pipeline);
315 gst_object_unref (bus);
316
317 /* we add all elements into the pipeline */
318 /* audio-input | converter | resampler | audiosink */
319 gst_bin_add_many (GST_BIN (pipeline), source, conv,
320 resampler, sink, NULL);
321
322 /* we link the elements together */
323 gst_element_link_many (source, conv, resampler, sink, NULL);
324
325 /* Set the pipeline to "playing" state*/
326 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now playing\n");
327 gst_element_set_state (pipeline, GST_STATE_PLAYING);
328
329 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running...\n");
330 /* Iterate */
331 toff = 0;
332 while (!abort_read)
333 {
334 char readbuf[MAXLINE];
335 int ret;
336
337 ret = read (0, readbuf, sizeof (readbuf));
338 if (0 > ret)
339 {
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341 _("Read error from STDIN: %d %s\n"),
342 ret, strerror (errno));
343 break;
344 }
345 toff += ret;
346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
347 "Received %d bytes of audio data (total: %llu)\n",
348 (int) ret,
349 toff);
350 if (0 == ret)
351 break;
352 GNUNET_SERVER_mst_receive (stdin_mst, NULL,
353 readbuf, ret,
354 GNUNET_NO, GNUNET_NO);
355 }
356 GNUNET_SERVER_mst_destroy (stdin_mst);
357
358 signal (SIGINT, inthandler);
359 signal (SIGINT, termhandler);
360
361 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returned, stopping playback\n");
362 quit ();
363
364 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Deleting pipeline\n");
365 gst_object_unref (GST_OBJECT (source));
366 source = NULL;
367 gst_object_unref (GST_OBJECT (pipeline));
368 pipeline = NULL;
369 g_source_remove (bus_watch_id);
370
371 return 0;
372}
diff --git a/src/conversation/gnunet-helper-audio-record-gst.c b/src/conversation/gnunet-helper-audio-record-gst.c
new file mode 100755
index 000000000..8d7a88fab
--- /dev/null
+++ b/src/conversation/gnunet-helper-audio-record-gst.c
@@ -0,0 +1,334 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file conversation/gnunet-helper-audio-record-gst.c
22 * @brief program to record audio data from the microphone (GStreamer version)
23 * @author LRN
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_protocols.h"
28#include "conversation.h"
29#include "gnunet_constants.h"
30#include "gnunet_core_service.h"
31
32#include <gst/gst.h>
33#include <gst/app/gstappsink.h>
34#include <gst/audio/gstaudiobasesrc.h>
35#include <glib.h>
36
37/**
38 * Number of channels.
39 * Must be one of the following (from libopusenc documentation):
40 * 1, 2
41 */
42#define OPUS_CHANNELS 1
43
44/**
45 * Maximal size of a single opus packet.
46 */
47#define MAX_PAYLOAD_SIZE (1024 / OPUS_CHANNELS)
48
49/**
50 * Size of a single frame fed to the encoder, in ms.
51 * Must be one of the following (from libopus documentation):
52 * 2.5, 5, 10, 20, 40 or 60
53 */
54#define OPUS_FRAME_SIZE 20
55
56/**
57 * Expected packet loss to prepare for, in percents.
58 */
59#define PACKET_LOSS_PERCENTAGE 1
60
61/**
62 * Set to 1 to enable forward error correction.
63 * Set to 0 to disable.
64 */
65#define INBAND_FEC_MODE 1
66
67/**
68 * Max number of microseconds to buffer in audiosource.
69 * Default is 200000
70 */
71#define BUFFER_TIME 1000
72
73/**
74 * Min number of microseconds to buffer in audiosource.
75 * Default is 10000
76 */
77#define LATENCY_TIME 1000
78
79/**
80 * Main pipeline.
81 */
82static GstElement *pipeline;
83
84static void
85quit ()
86{
87 if (NULL != pipeline)
88 gst_element_set_state (pipeline, GST_STATE_NULL);
89}
90
91static gboolean
92bus_call (GstBus *bus, GstMessage *msg, gpointer data)
93{
94 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bus message\n");
95 switch (GST_MESSAGE_TYPE (msg))
96 {
97 case GST_MESSAGE_EOS:
98 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "End of stream\n");
99 quit ();
100 break;
101
102 case GST_MESSAGE_ERROR:
103 {
104 gchar *debug;
105 GError *error;
106
107 gst_message_parse_error (msg, &error, &debug);
108 g_free (debug);
109
110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error: %s\n", error->message);
111 g_error_free (error);
112
113 quit ();
114 break;
115 }
116 default:
117 break;
118 }
119
120 return TRUE;
121}
122
123void
124source_child_added (GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
125{
126 if (GST_IS_AUDIO_BASE_SRC (object))
127 g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time", (gint64) LATENCY_TIME, NULL);
128}
129
130static void
131signalhandler (int s)
132{
133 quit ();
134}
135
136
137int
138main (int argc, char **argv)
139{
140 GstElement *source, *encoder, *conv, *resampler, *sink;
141 GstBus *bus;
142 guint bus_watch_id;
143 struct AudioMessage audio_message;
144 int abort_send = 0;
145
146 typedef void (*SignalHandlerPointer) (int);
147
148 SignalHandlerPointer inthandler, termhandler;
149 inthandler = signal (SIGINT, signalhandler);
150 termhandler = signal (SIGTERM, signalhandler);
151
152#ifdef WINDOWS
153 setmode (1, _O_BINARY);
154#endif
155
156 /* Initialisation */
157 gst_init (&argc, &argv);
158
159 GNUNET_assert (GNUNET_OK ==
160 GNUNET_log_setup ("gnunet-helper-audio-record",
161 "WARNING",
162 NULL));
163
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165 "Audio source starts\n");
166
167 audio_message.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
168
169 /* Create gstreamer elements */
170 pipeline = gst_pipeline_new ("audio-recorder");
171 source = gst_element_factory_make ("autoaudiosrc", "audiosource");
172 conv = gst_element_factory_make ("audioconvert", "converter");
173 resampler= gst_element_factory_make ("audioresample", "resampler");
174 encoder = gst_element_factory_make ("opusenc", "opus-encoder");
175 sink = gst_element_factory_make ("appsink", "audio-output");
176
177 if (!pipeline || !source || !conv || !resampler || !encoder || !sink)
178 {
179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
180 "One element could not be created. Exiting.\n");
181 return -1;
182 }
183
184 g_signal_connect (source, "child-added", G_CALLBACK (source_child_added), NULL);
185
186 /* Set up the pipeline */
187
188 g_object_set (G_OBJECT (encoder),
189/* "bitrate", 64000, */
190/* "bandwidth", OPUS_BANDWIDTH_FULLBAND, */
191 "inband-fec", INBAND_FEC_MODE,
192 "packet-loss-percentage", PACKET_LOSS_PERCENTAGE,
193 "max-payload-size", MAX_PAYLOAD_SIZE,
194 "audio", FALSE, /* VoIP, not audio */
195 "frame-size", OPUS_FRAME_SIZE,
196 NULL);
197
198 /* we add a message handler */
199 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
200 bus_watch_id = gst_bus_add_watch (bus, bus_call, pipeline);
201 gst_object_unref (bus);
202
203 /* we add all elements into the pipeline */
204 /* audiosource | converter | resampler | opus-encoder | audio-output */
205 gst_bin_add_many (GST_BIN (pipeline), source, conv, resampler, encoder,
206 sink, NULL);
207
208 /* we link the elements together */
209 gst_element_link_many (source, conv, resampler, encoder, sink, NULL);
210
211 /* Set the pipeline to "playing" state*/
212 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now playing\n");
213 gst_element_set_state (pipeline, GST_STATE_PLAYING);
214
215
216 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running...\n");
217 /* Iterate */
218 while (!abort_send)
219 {
220 GstSample *s;
221 GstBuffer *b;
222 GstMapInfo m;
223 size_t len, msg_size;
224 const char *ptr;
225 int phase;
226
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulling...\n");
228 s = gst_app_sink_pull_sample (GST_APP_SINK (sink));
229 if (NULL == s)
230 {
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulled NULL\n");
232 break;
233 }
234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "...pulled!\n");
235 {
236 const GstStructure *si;
237 char *si_str;
238 GstCaps *s_caps;
239 char *caps_str;
240 si = gst_sample_get_info (s);
241 if (si)
242 {
243 si_str = gst_structure_to_string (si);
244 if (si_str)
245 {
246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample %s\n", si_str);
247 g_free (si_str);
248 }
249 }
250 else
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no info\n");
252 s_caps = gst_sample_get_caps (s);
253 if (s_caps)
254 {
255 caps_str = gst_caps_to_string (s_caps);
256 if (caps_str)
257 {
258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with caps %s\n", caps_str);
259 g_free (caps_str);
260 }
261 }
262 else
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no caps\n");
264 }
265 b = gst_sample_get_buffer (s);
266 if (NULL == b || !gst_buffer_map (b, &m, GST_MAP_READ))
267 {
268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got NULL buffer %p or failed to map the buffer\n", b);
269 gst_sample_unref (s);
270 continue;
271 }
272
273 len = m.size;
274 if (len > UINT16_MAX - sizeof (struct AudioMessage))
275 {
276 GNUNET_break (0);
277 len = UINT16_MAX - sizeof (struct AudioMessage);
278 }
279 msg_size = sizeof (struct AudioMessage) + len;
280 audio_message.header.size = htons ((uint16_t) msg_size);
281
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Sending %u bytes of audio data\n", (unsigned int) msg_size);
284 for (phase = 0; phase < 2; phase++)
285 {
286 size_t offset;
287 size_t to_send;
288 ssize_t ret;
289 if (0 == phase)
290 {
291 ptr = (const char *) &audio_message;
292 to_send = sizeof (audio_message);
293 }
294 else
295 {
296 ptr = (const char *) m.data;
297 to_send = len;
298 }
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Sending %u bytes on phase %d\n", (unsigned int) to_send, phase);
301 for (offset = 0; offset < to_send; offset += ret)
302 {
303 ret = write (1, &ptr[offset], to_send - offset);
304 if (0 >= ret)
305 {
306 if (-1 == ret)
307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
308 "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n",
309 (unsigned int) to_send - offset, (unsigned int) offset,
310 (unsigned int) (to_send + offset), phase, strerror (errno));
311 abort_send = 1;
312 break;
313 }
314 }
315 if (abort_send)
316 break;
317 }
318 gst_buffer_unmap (b, &m);
319 gst_sample_unref (s);
320 }
321
322 signal (SIGINT, inthandler);
323 signal (SIGINT, termhandler);
324
325 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returned, stopping playback\n");
326 quit ();
327
328 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Deleting pipeline\n");
329 gst_object_unref (GST_OBJECT (pipeline));
330 pipeline = NULL;
331 g_source_remove (bus_watch_id);
332
333 return 0;
334}