aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-helper-audio-playback-gst.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conversation/gnunet-helper-audio-playback-gst.c')
-rw-r--r--src/conversation/gnunet-helper-audio-playback-gst.c385
1 files changed, 195 insertions, 190 deletions
diff --git a/src/conversation/gnunet-helper-audio-playback-gst.c b/src/conversation/gnunet-helper-audio-playback-gst.c
index 51450af90..b268fa215 100644
--- a/src/conversation/gnunet-helper-audio-playback-gst.c
+++ b/src/conversation/gnunet-helper-audio-playback-gst.c
@@ -11,12 +11,12 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
18 SPDX-License-Identifier: AGPL3.0-or-later 18 SPDX-License-Identifier: AGPL3.0-or-later
19*/ 19 */
20/** 20/**
21 * @file conversation/gnunet-helper-audio-playback-gst.c 21 * @file conversation/gnunet-helper-audio-playback-gst.c
22 * @brief program to playback audio data to the speaker (GStreamer version) 22 * @brief program to playback audio data to the speaker (GStreamer version)
@@ -81,140 +81,144 @@ static int abort_read;
81 81
82 82
83static void 83static void
84sink_child_added (GstChildProxy *child_proxy, 84sink_child_added(GstChildProxy *child_proxy,
85 GObject *object, 85 GObject *object,
86 gchar *name, 86 gchar *name,
87 gpointer user_data) 87 gpointer user_data)
88{ 88{
89 if (GST_IS_AUDIO_BASE_SRC (object)) 89 if (GST_IS_AUDIO_BASE_SRC(object))
90 g_object_set (object, 90 g_object_set(object,
91 "buffer-time", (gint64) BUFFER_TIME, 91 "buffer-time", (gint64)BUFFER_TIME,
92 "latency-time", (gint64) LATENCY_TIME, 92 "latency-time", (gint64)LATENCY_TIME,
93 NULL); 93 NULL);
94} 94}
95 95
96 96
97static void 97static void
98ogg_pad_added (GstElement *element, 98ogg_pad_added(GstElement *element,
99 GstPad *pad, 99 GstPad *pad,
100 gpointer data) 100 gpointer data)
101{ 101{
102 GstPad *sinkpad; 102 GstPad *sinkpad;
103 GstElement *decoder = (GstElement *) data; 103 GstElement *decoder = (GstElement *)data;
104 104
105 /* We can now link this pad with the opus-decoder sink pad */ 105 /* We can now link this pad with the opus-decoder sink pad */
106 sinkpad = gst_element_get_static_pad (decoder, "sink"); 106 sinkpad = gst_element_get_static_pad(decoder, "sink");
107 107
108 gst_pad_link (pad, sinkpad); 108 gst_pad_link(pad, sinkpad);
109 109
110 gst_element_link_many (decoder, conv, resampler, sink, NULL); 110 gst_element_link_many(decoder, conv, resampler, sink, NULL);
111 111
112 gst_object_unref (sinkpad); 112 gst_object_unref(sinkpad);
113} 113}
114 114
115 115
116static void 116static void
117quit () 117quit()
118{ 118{
119 if (NULL != source) 119 if (NULL != source)
120 gst_app_src_end_of_stream (GST_APP_SRC (source)); 120 gst_app_src_end_of_stream(GST_APP_SRC(source));
121 if (NULL != pipeline) 121 if (NULL != pipeline)
122 gst_element_set_state (pipeline, GST_STATE_NULL); 122 gst_element_set_state(pipeline, GST_STATE_NULL);
123 abort_read = 1; 123 abort_read = 1;
124} 124}
125 125
126 126
127static gboolean 127static gboolean
128bus_call (GstBus *bus, GstMessage *msg, gpointer data) 128bus_call(GstBus *bus, GstMessage *msg, gpointer data)
129{ 129{
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 130 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
131 "Bus message\n"); 131 "Bus message\n");
132 switch (GST_MESSAGE_TYPE (msg)) 132 switch (GST_MESSAGE_TYPE(msg))
133 { 133 {
134 case GST_MESSAGE_EOS: 134 case GST_MESSAGE_EOS:
135 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 135 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
136 "End of stream\n"); 136 "End of stream\n");
137 quit (); 137 quit();
138 break; 138 break;
139 139
140 case GST_MESSAGE_ERROR: 140 case GST_MESSAGE_ERROR:
141 { 141 {
142 gchar *debug; 142 gchar *debug;
143 GError *error; 143 GError *error;
144 144
145 gst_message_parse_error (msg, &error, &debug); 145 gst_message_parse_error(msg, &error, &debug);
146 g_free (debug); 146 g_free(debug);
147 147
148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 148 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
149 "Error: %s\n", 149 "Error: %s\n",
150 error->message); 150 error->message);
151 g_error_free (error); 151 g_error_free(error);
152 152
153 quit (); 153 quit();
154 break;
155 }
156
157 default:
154 break; 158 break;
155 } 159 }
156 default:
157 break;
158 }
159 160
160 return TRUE; 161 return TRUE;
161} 162}
162 163
163 164
164static void 165static void
165signalhandler (int s) 166signalhandler(int s)
166{ 167{
167 quit (); 168 quit();
168} 169}
169 170
170 171
171static int 172static int
172feed_buffer_to_gst (const char *audio, size_t b_len) 173feed_buffer_to_gst(const char *audio, size_t b_len)
173{ 174{
174 GstBuffer *b; 175 GstBuffer *b;
175 gchar *bufspace; 176 gchar *bufspace;
176 GstFlowReturn flow; 177 GstFlowReturn flow;
177 178
178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 179 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
179 "Feeding %u bytes to GStreamer\n", 180 "Feeding %u bytes to GStreamer\n",
180 (unsigned int) b_len); 181 (unsigned int)b_len);
181 182
182 bufspace = g_memdup (audio, b_len); 183 bufspace = g_memdup(audio, b_len);
183 b = gst_buffer_new_wrapped (bufspace, b_len); 184 b = gst_buffer_new_wrapped(bufspace, b_len);
184 if (NULL == b) 185 if (NULL == b)
185 { 186 {
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 187 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
187 "Failed to wrap a buffer\n"); 188 "Failed to wrap a buffer\n");
188 g_free (bufspace); 189 g_free(bufspace);
189 return GNUNET_SYSERR; 190 return GNUNET_SYSERR;
190 } 191 }
191 flow = gst_app_src_push_buffer (GST_APP_SRC (source), b); 192 flow = gst_app_src_push_buffer(GST_APP_SRC(source), b);
192 /* They all return GNUNET_OK, because currently player stops when 193 /* They all return GNUNET_OK, because currently player stops when
193 * data stops coming. This might need to be changed for the player 194 * data stops coming. This might need to be changed for the player
194 * to also stop when pipeline breaks. 195 * to also stop when pipeline breaks.
195 */ 196 */
196 switch (flow) 197 switch (flow)
197 { 198 {
198 case GST_FLOW_OK: 199 case GST_FLOW_OK:
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 200 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
200 "Fed %u bytes to the pipeline\n", 201 "Fed %u bytes to the pipeline\n",
201 (unsigned int) b_len); 202 (unsigned int)b_len);
202 break; 203 break;
203 case GST_FLOW_FLUSHING: 204
204 /* buffer was dropped, because pipeline state is not PAUSED or PLAYING */ 205 case GST_FLOW_FLUSHING:
205 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 206 /* buffer was dropped, because pipeline state is not PAUSED or PLAYING */
206 "Dropped a buffer\n"); 207 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
207 break; 208 "Dropped a buffer\n");
208 case GST_FLOW_EOS: 209 break;
209 /* end of stream */ 210
210 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 211 case GST_FLOW_EOS:
211 "EOS\n"); 212 /* end of stream */
212 break; 213 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
213 default: 214 "EOS\n");
214 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 215 break;
215 "Unexpected push result\n"); 216
216 break; 217 default:
217 } 218 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
219 "Unexpected push result\n");
220 break;
221 }
218 return GNUNET_OK; 222 return GNUNET_OK;
219} 223}
220 224
@@ -228,29 +232,30 @@ feed_buffer_to_gst (const char *audio, size_t b_len)
228 * #GNUNET_SYSERR to stop further processing due to error 232 * #GNUNET_SYSERR to stop further processing due to error
229 */ 233 */
230static int 234static int
231stdin_receiver (void *cls, 235stdin_receiver(void *cls,
232 const struct GNUNET_MessageHeader *msg) 236 const struct GNUNET_MessageHeader *msg)
233{ 237{
234 struct AudioMessage *audio; 238 struct AudioMessage *audio;
235 size_t b_len; 239 size_t b_len;
236 240
237 switch (ntohs (msg->type)) 241 switch (ntohs(msg->type))
238 { 242 {
239 case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO: 243 case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO:
240 audio = (struct AudioMessage *) msg; 244 audio = (struct AudioMessage *)msg;
241 245
242 b_len = ntohs (audio->header.size) - sizeof (struct AudioMessage); 246 b_len = ntohs(audio->header.size) - sizeof(struct AudioMessage);
243 feed_buffer_to_gst ((const char *) &audio[1], b_len); 247 feed_buffer_to_gst((const char *)&audio[1], b_len);
244 break; 248 break;
245 default: 249
246 break; 250 default:
247 } 251 break;
252 }
248 return GNUNET_OK; 253 return GNUNET_OK;
249} 254}
250 255
251 256
252int 257int
253main (int argc, char **argv) 258main(int argc, char **argv)
254{ 259{
255 GstBus *bus; 260 GstBus *bus;
256 guint bus_watch_id; 261 guint bus_watch_id;
@@ -260,144 +265,144 @@ main (int argc, char **argv)
260 265
261 SignalHandlerPointer inthandler, termhandler; 266 SignalHandlerPointer inthandler, termhandler;
262#ifdef DEBUG_READ_PURE_OGG 267#ifdef DEBUG_READ_PURE_OGG
263 int read_pure_ogg = getenv ("GNUNET_READ_PURE_OGG") ? 1 : 0; 268 int read_pure_ogg = getenv("GNUNET_READ_PURE_OGG") ? 1 : 0;
264#endif 269#endif
265 270
266 inthandler = signal (SIGINT, 271 inthandler = signal(SIGINT,
267 &signalhandler); 272 &signalhandler);
268 termhandler = signal (SIGTERM, 273 termhandler = signal(SIGTERM,
269 &signalhandler); 274 &signalhandler);
270 275
271#ifdef WINDOWS 276#ifdef WINDOWS
272 setmode (0, _O_BINARY); 277 setmode(0, _O_BINARY);
273#endif 278#endif
274 279
275 /* Initialisation */ 280 /* Initialisation */
276 gst_init (&argc, &argv); 281 gst_init(&argc, &argv);
277 282
278 GNUNET_assert (GNUNET_OK == 283 GNUNET_assert(GNUNET_OK ==
279 GNUNET_log_setup ("gnunet-helper-audio-playback-gst", 284 GNUNET_log_setup("gnunet-helper-audio-playback-gst",
280 "WARNING", 285 "WARNING",
281 NULL)); 286 NULL));
282 287
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 288 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
284 "Audio sink starts\n"); 289 "Audio sink starts\n");
285 290
286 stdin_mst = GNUNET_MST_create (&stdin_receiver, 291 stdin_mst = GNUNET_MST_create(&stdin_receiver,
287 NULL); 292 NULL);
288 293
289 /* Create gstreamer elements */ 294 /* Create gstreamer elements */
290 pipeline = gst_pipeline_new ("audio-player"); 295 pipeline = gst_pipeline_new("audio-player");
291 source = gst_element_factory_make ("appsrc", "audio-input"); 296 source = gst_element_factory_make("appsrc", "audio-input");
292 demuxer = gst_element_factory_make ("oggdemux", "ogg-demuxer"); 297 demuxer = gst_element_factory_make("oggdemux", "ogg-demuxer");
293 decoder = gst_element_factory_make ("opusdec", "opus-decoder"); 298 decoder = gst_element_factory_make("opusdec", "opus-decoder");
294 conv = gst_element_factory_make ("audioconvert", "converter"); 299 conv = gst_element_factory_make("audioconvert", "converter");
295 resampler= gst_element_factory_make ("audioresample", "resampler"); 300 resampler = gst_element_factory_make("audioresample", "resampler");
296 sink = gst_element_factory_make ("autoaudiosink", "audiosink"); 301 sink = gst_element_factory_make("autoaudiosink", "audiosink");
297 302
298 if (!pipeline || !source || !conv || !resampler || !decoder || !demuxer || !sink) 303 if (!pipeline || !source || !conv || !resampler || !decoder || !demuxer || !sink)
299 { 304 {
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 305 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
301 "One element could not be created. Exiting.\n"); 306 "One element could not be created. Exiting.\n");
302 return -1; 307 return -1;
303 } 308 }
304 309
305 g_signal_connect (sink, 310 g_signal_connect(sink,
306 "child-added", 311 "child-added",
307 G_CALLBACK (sink_child_added), 312 G_CALLBACK(sink_child_added),
308 NULL); 313 NULL);
309 g_signal_connect (demuxer, 314 g_signal_connect(demuxer,
310 "pad-added", 315 "pad-added",
311 G_CALLBACK (ogg_pad_added), 316 G_CALLBACK(ogg_pad_added),
312 decoder); 317 decoder);
313 318
314 /* Keep a reference to it, we operate on it */ 319 /* Keep a reference to it, we operate on it */
315 gst_object_ref (GST_OBJECT (source)); 320 gst_object_ref(GST_OBJECT(source));
316 321
317 /* Set up the pipeline */ 322 /* Set up the pipeline */
318 323
319 /* we feed appsrc as fast as possible, it just blocks when it's full */ 324 /* we feed appsrc as fast as possible, it just blocks when it's full */
320 g_object_set (G_OBJECT (source), 325 g_object_set(G_OBJECT(source),
321/* "format", GST_FORMAT_TIME,*/ 326/* "format", GST_FORMAT_TIME,*/
322 "block", TRUE, 327 "block", TRUE,
323 "is-live", TRUE, 328 "is-live", TRUE,
324 NULL); 329 NULL);
325 330
326 g_object_set (G_OBJECT (decoder), 331 g_object_set(G_OBJECT(decoder),
327/* "plc", FALSE,*/ 332/* "plc", FALSE,*/
328/* "apply-gain", TRUE,*/ 333/* "apply-gain", TRUE,*/
329 "use-inband-fec", TRUE, 334 "use-inband-fec", TRUE,
330 NULL); 335 NULL);
331 336
332 /* we add a message handler */ 337 /* we add a message handler */
333 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 338 bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
334 bus_watch_id = gst_bus_add_watch (bus, bus_call, pipeline); 339 bus_watch_id = gst_bus_add_watch(bus, bus_call, pipeline);
335 gst_object_unref (bus); 340 gst_object_unref(bus);
336 341
337 /* we add all elements into the pipeline */ 342 /* we add all elements into the pipeline */
338 /* audio-input | ogg-demuxer | opus-decoder | converter | resampler | audiosink */ 343 /* audio-input | ogg-demuxer | opus-decoder | converter | resampler | audiosink */
339 gst_bin_add_many (GST_BIN (pipeline), source, demuxer, decoder, conv, 344 gst_bin_add_many(GST_BIN(pipeline), source, demuxer, decoder, conv,
340 resampler, sink, NULL); 345 resampler, sink, NULL);
341 346
342 /* we link the elements together */ 347 /* we link the elements together */
343 gst_element_link_many (source, demuxer, NULL); 348 gst_element_link_many(source, demuxer, NULL);
344 349
345 /* Set the pipeline to "playing" state*/ 350 /* Set the pipeline to "playing" state*/
346 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now playing\n"); 351 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Now playing\n");
347 gst_element_set_state (pipeline, GST_STATE_PLAYING); 352 gst_element_set_state(pipeline, GST_STATE_PLAYING);
348 353
349 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running...\n"); 354 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Running...\n");
350 /* Iterate */ 355 /* Iterate */
351 toff = 0; 356 toff = 0;
352 while (!abort_read) 357 while (!abort_read)
353 {
354 char readbuf[MAXLINE];
355 int ret;
356
357 ret = read (0, readbuf, sizeof (readbuf));
358 if (0 > ret)
359 { 358 {
360 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 359 char readbuf[MAXLINE];
361 _("Read error from STDIN: %d %s\n"), 360 int ret;
362 ret, strerror (errno)); 361
363 break; 362 ret = read(0, readbuf, sizeof(readbuf));
364 } 363 if (0 > ret)
365 toff += ret; 364 {
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 365 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
367 "Received %d bytes of audio data (total: %llu)\n", 366 _("Read error from STDIN: %d %s\n"),
368 (int) ret, 367 ret, strerror(errno));
369 (unsigned long long) toff); 368 break;
370 if (0 == ret) 369 }
371 break; 370 toff += ret;
371 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
372 "Received %d bytes of audio data (total: %llu)\n",
373 (int)ret,
374 (unsigned long long)toff);
375 if (0 == ret)
376 break;
372#ifdef DEBUG_READ_PURE_OGG 377#ifdef DEBUG_READ_PURE_OGG
373 if (read_pure_ogg) 378 if (read_pure_ogg)
374 { 379 {
375 feed_buffer_to_gst (readbuf, ret); 380 feed_buffer_to_gst(readbuf, ret);
376 } 381 }
377 else 382 else
378#endif 383#endif
379 GNUNET_MST_from_buffer (stdin_mst, 384 GNUNET_MST_from_buffer(stdin_mst,
380 readbuf, 385 readbuf,
381 ret, 386 ret,
382 GNUNET_NO, 387 GNUNET_NO,
383 GNUNET_NO); 388 GNUNET_NO);
384 } 389 }
385 GNUNET_MST_destroy (stdin_mst); 390 GNUNET_MST_destroy(stdin_mst);
386 391
387 signal (SIGINT, inthandler); 392 signal(SIGINT, inthandler);
388 signal (SIGINT, termhandler); 393 signal(SIGINT, termhandler);
389 394
390 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 395 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
391 "Returned, stopping playback\n"); 396 "Returned, stopping playback\n");
392 quit (); 397 quit();
393 398
394 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 399 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
395 "Deleting pipeline\n"); 400 "Deleting pipeline\n");
396 gst_object_unref (GST_OBJECT (source)); 401 gst_object_unref(GST_OBJECT(source));
397 source = NULL; 402 source = NULL;
398 gst_object_unref (GST_OBJECT (pipeline)); 403 gst_object_unref(GST_OBJECT(pipeline));
399 pipeline = NULL; 404 pipeline = NULL;
400 g_source_remove (bus_watch_id); 405 g_source_remove(bus_watch_id);
401 406
402 return 0; 407 return 0;
403} 408}