diff options
Diffstat (limited to 'src/conversation/gnunet-helper-audio-record-gst.c')
-rw-r--r-- | src/conversation/gnunet-helper-audio-record-gst.c | 385 |
1 files changed, 197 insertions, 188 deletions
diff --git a/src/conversation/gnunet-helper-audio-record-gst.c b/src/conversation/gnunet-helper-audio-record-gst.c index f41f529ea..a3607014e 100644 --- a/src/conversation/gnunet-helper-audio-record-gst.c +++ b/src/conversation/gnunet-helper-audio-record-gst.c | |||
@@ -102,61 +102,63 @@ static int dump_pure_ogg; | |||
102 | #endif | 102 | #endif |
103 | 103 | ||
104 | static void | 104 | static void |
105 | quit() | 105 | quit () |
106 | { | 106 | { |
107 | if (NULL != pipeline) | 107 | if (NULL != pipeline) |
108 | gst_element_set_state(pipeline, GST_STATE_NULL); | 108 | gst_element_set_state (pipeline, GST_STATE_NULL); |
109 | } | 109 | } |
110 | 110 | ||
111 | static gboolean | 111 | static gboolean |
112 | bus_call(GstBus *bus, GstMessage *msg, gpointer data) | 112 | bus_call (GstBus *bus, GstMessage *msg, gpointer data) |
113 | { | 113 | { |
114 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Bus message\n"); | 114 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bus message\n"); |
115 | switch (GST_MESSAGE_TYPE(msg)) | 115 | switch (GST_MESSAGE_TYPE (msg)) |
116 | { | 116 | { |
117 | case GST_MESSAGE_EOS: | 117 | case GST_MESSAGE_EOS: |
118 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, "End of stream\n"); | 118 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "End of stream\n"); |
119 | quit(); | 119 | quit (); |
120 | break; | 120 | break; |
121 | 121 | ||
122 | case GST_MESSAGE_ERROR: | 122 | case GST_MESSAGE_ERROR: |
123 | { | 123 | { |
124 | gchar *debug; | 124 | gchar *debug; |
125 | GError *error; | 125 | GError *error; |
126 | 126 | ||
127 | gst_message_parse_error(msg, &error, &debug); | 127 | gst_message_parse_error (msg, &error, &debug); |
128 | g_free(debug); | 128 | g_free (debug); |
129 | 129 | ||
130 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error: %s\n", error->message); | 130 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error: %s\n", error->message); |
131 | g_error_free(error); | 131 | g_error_free (error); |
132 | 132 | ||
133 | quit(); | 133 | quit (); |
134 | break; | 134 | break; |
135 | } | 135 | } |
136 | 136 | ||
137 | default: | 137 | default: |
138 | break; | 138 | break; |
139 | } | 139 | } |
140 | 140 | ||
141 | return TRUE; | 141 | return TRUE; |
142 | } | 142 | } |
143 | 143 | ||
144 | void | 144 | void |
145 | source_child_added(GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data) | 145 | source_child_added (GstChildProxy *child_proxy, GObject *object, gchar *name, |
146 | gpointer user_data) | ||
146 | { | 147 | { |
147 | if (GST_IS_AUDIO_BASE_SRC(object)) | 148 | if (GST_IS_AUDIO_BASE_SRC (object)) |
148 | g_object_set(object, "buffer-time", (gint64)BUFFER_TIME, "latency-time", (gint64)LATENCY_TIME, NULL); | 149 | g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time", |
150 | (gint64) LATENCY_TIME, NULL); | ||
149 | } | 151 | } |
150 | 152 | ||
151 | static void | 153 | static void |
152 | signalhandler(int s) | 154 | signalhandler (int s) |
153 | { | 155 | { |
154 | quit(); | 156 | quit (); |
155 | } | 157 | } |
156 | 158 | ||
157 | 159 | ||
158 | int | 160 | int |
159 | main(int argc, char **argv) | 161 | main (int argc, char **argv) |
160 | { | 162 | { |
161 | GstElement *source, *filter, *encoder, *conv, *resampler, *sink, *oggmux; | 163 | GstElement *source, *filter, *encoder, *conv, *resampler, *sink, *oggmux; |
162 | GstCaps *caps; | 164 | GstCaps *caps; |
@@ -168,214 +170,221 @@ main(int argc, char **argv) | |||
168 | typedef void (*SignalHandlerPointer) (int); | 170 | typedef void (*SignalHandlerPointer) (int); |
169 | 171 | ||
170 | SignalHandlerPointer inthandler, termhandler; | 172 | SignalHandlerPointer inthandler, termhandler; |
171 | inthandler = signal(SIGINT, signalhandler); | 173 | inthandler = signal (SIGINT, signalhandler); |
172 | termhandler = signal(SIGTERM, signalhandler); | 174 | termhandler = signal (SIGTERM, signalhandler); |
173 | 175 | ||
174 | #ifdef DEBUG_RECORD_PURE_OGG | 176 | #ifdef DEBUG_RECORD_PURE_OGG |
175 | dump_pure_ogg = getenv("GNUNET_RECORD_PURE_OGG") ? 1 : 0; | 177 | dump_pure_ogg = getenv ("GNUNET_RECORD_PURE_OGG") ? 1 : 0; |
176 | #endif | 178 | #endif |
177 | 179 | ||
178 | /* Initialisation */ | 180 | /* Initialisation */ |
179 | gst_init(&argc, &argv); | 181 | gst_init (&argc, &argv); |
180 | 182 | ||
181 | GNUNET_assert(GNUNET_OK == | 183 | GNUNET_assert (GNUNET_OK == |
182 | GNUNET_log_setup("gnunet-helper-audio-record", | 184 | GNUNET_log_setup ("gnunet-helper-audio-record", |
183 | "WARNING", | 185 | "WARNING", |
184 | NULL)); | 186 | NULL)); |
185 | 187 | ||
186 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | 188 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
187 | "Audio source starts\n"); | 189 | "Audio source starts\n"); |
188 | 190 | ||
189 | audio_message.header.type = htons(GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO); | 191 | audio_message.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO); |
190 | 192 | ||
191 | /* Create gstreamer elements */ | 193 | /* Create gstreamer elements */ |
192 | pipeline = gst_pipeline_new("audio-recorder"); | 194 | pipeline = gst_pipeline_new ("audio-recorder"); |
193 | source = gst_element_factory_make("autoaudiosrc", "audiosource"); | 195 | source = gst_element_factory_make ("autoaudiosrc", "audiosource"); |
194 | filter = gst_element_factory_make("capsfilter", "filter"); | 196 | filter = gst_element_factory_make ("capsfilter", "filter"); |
195 | conv = gst_element_factory_make("audioconvert", "converter"); | 197 | conv = gst_element_factory_make ("audioconvert", "converter"); |
196 | resampler = gst_element_factory_make("audioresample", "resampler"); | 198 | resampler = gst_element_factory_make ("audioresample", "resampler"); |
197 | encoder = gst_element_factory_make("opusenc", "opus-encoder"); | 199 | encoder = gst_element_factory_make ("opusenc", "opus-encoder"); |
198 | oggmux = gst_element_factory_make("oggmux", "ogg-muxer"); | 200 | oggmux = gst_element_factory_make ("oggmux", "ogg-muxer"); |
199 | sink = gst_element_factory_make("appsink", "audio-output"); | 201 | sink = gst_element_factory_make ("appsink", "audio-output"); |
200 | 202 | ||
201 | if (!pipeline || !filter || !source || !conv || !resampler || !encoder || !oggmux || !sink) | 203 | if (! pipeline || ! filter || ! source || ! conv || ! resampler || |
202 | { | 204 | ! encoder || ! oggmux || ! sink) |
203 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, | 205 | { |
204 | "One element could not be created. Exiting.\n"); | 206 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
205 | return -1; | 207 | "One element could not be created. Exiting.\n"); |
206 | } | 208 | return -1; |
207 | 209 | } | |
208 | g_signal_connect(source, "child-added", G_CALLBACK(source_child_added), NULL); | 210 | |
211 | g_signal_connect (source, "child-added", G_CALLBACK (source_child_added), | ||
212 | NULL); | ||
209 | 213 | ||
210 | /* Set up the pipeline */ | 214 | /* Set up the pipeline */ |
211 | 215 | ||
212 | caps = gst_caps_new_simple("audio/x-raw", | 216 | caps = gst_caps_new_simple ("audio/x-raw", |
213 | "format", G_TYPE_STRING, "S16LE", | 217 | "format", G_TYPE_STRING, "S16LE", |
214 | /* "rate", G_TYPE_INT, SAMPLING_RATE,*/ | 218 | /* "rate", G_TYPE_INT, SAMPLING_RATE,*/ |
215 | "channels", G_TYPE_INT, OPUS_CHANNELS, | 219 | "channels", G_TYPE_INT, OPUS_CHANNELS, |
216 | /* "layout", G_TYPE_STRING, "interleaved",*/ | 220 | /* "layout", G_TYPE_STRING, "interleaved",*/ |
217 | NULL); | 221 | NULL); |
218 | g_object_set(G_OBJECT(filter), | 222 | g_object_set (G_OBJECT (filter), |
219 | "caps", caps, | 223 | "caps", caps, |
220 | NULL); | 224 | NULL); |
221 | gst_caps_unref(caps); | 225 | gst_caps_unref (caps); |
222 | 226 | ||
223 | g_object_set(G_OBJECT(encoder), | 227 | g_object_set (G_OBJECT (encoder), |
224 | /* "bitrate", 64000, */ | 228 | /* "bitrate", 64000, */ |
225 | /* "bandwidth", OPUS_BANDWIDTH_FULLBAND, */ | 229 | /* "bandwidth", OPUS_BANDWIDTH_FULLBAND, */ |
226 | "inband-fec", INBAND_FEC_MODE, | 230 | "inband-fec", INBAND_FEC_MODE, |
227 | "packet-loss-percentage", PACKET_LOSS_PERCENTAGE, | 231 | "packet-loss-percentage", PACKET_LOSS_PERCENTAGE, |
228 | "max-payload-size", MAX_PAYLOAD_SIZE, | 232 | "max-payload-size", MAX_PAYLOAD_SIZE, |
229 | "audio", FALSE, /* VoIP, not audio */ | 233 | "audio", FALSE, /* VoIP, not audio */ |
230 | "frame-size", OPUS_FRAME_SIZE, | 234 | "frame-size", OPUS_FRAME_SIZE, |
231 | NULL); | 235 | NULL); |
232 | 236 | ||
233 | g_object_set(G_OBJECT(oggmux), | 237 | g_object_set (G_OBJECT (oggmux), |
234 | "max-delay", OGG_MAX_DELAY, | 238 | "max-delay", OGG_MAX_DELAY, |
235 | "max-page-delay", OGG_MAX_PAGE_DELAY, | 239 | "max-page-delay", OGG_MAX_PAGE_DELAY, |
236 | NULL); | 240 | NULL); |
237 | 241 | ||
238 | /* we add a message handler */ | 242 | /* we add a message handler */ |
239 | bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); | 243 | bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); |
240 | bus_watch_id = gst_bus_add_watch(bus, bus_call, pipeline); | 244 | bus_watch_id = gst_bus_add_watch (bus, bus_call, pipeline); |
241 | gst_object_unref(bus); | 245 | gst_object_unref (bus); |
242 | 246 | ||
243 | /* we add all elements into the pipeline */ | 247 | /* we add all elements into the pipeline */ |
244 | /* audiosource | converter | resampler | opus-encoder | audio-output */ | 248 | /* audiosource | converter | resampler | opus-encoder | audio-output */ |
245 | gst_bin_add_many(GST_BIN(pipeline), source, filter, conv, resampler, encoder, | 249 | gst_bin_add_many (GST_BIN (pipeline), source, filter, conv, resampler, |
246 | oggmux, sink, NULL); | 250 | encoder, |
251 | oggmux, sink, NULL); | ||
247 | 252 | ||
248 | /* we link the elements together */ | 253 | /* we link the elements together */ |
249 | gst_element_link_many(source, filter, conv, resampler, encoder, oggmux, sink, NULL); | 254 | gst_element_link_many (source, filter, conv, resampler, encoder, oggmux, sink, |
255 | NULL); | ||
250 | 256 | ||
251 | /* Set the pipeline to "playing" state*/ | 257 | /* Set the pipeline to "playing" state*/ |
252 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Now playing\n"); | 258 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now playing\n"); |
253 | gst_element_set_state(pipeline, GST_STATE_PLAYING); | 259 | gst_element_set_state (pipeline, GST_STATE_PLAYING); |
254 | 260 | ||
255 | 261 | ||
256 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Running...\n"); | 262 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running...\n"); |
257 | /* Iterate */ | 263 | /* Iterate */ |
258 | while (!abort_send) | 264 | while (! abort_send) |
265 | { | ||
266 | GstSample *s; | ||
267 | GstBuffer *b; | ||
268 | GstMapInfo m; | ||
269 | size_t len, msg_size; | ||
270 | const char *ptr; | ||
271 | int phase; | ||
272 | |||
273 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulling...\n"); | ||
274 | s = gst_app_sink_pull_sample (GST_APP_SINK (sink)); | ||
275 | if (NULL == s) | ||
276 | { | ||
277 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulled NULL\n"); | ||
278 | break; | ||
279 | } | ||
280 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "...pulled!\n"); | ||
259 | { | 281 | { |
260 | GstSample *s; | 282 | const GstStructure *si; |
261 | GstBuffer *b; | 283 | char *si_str; |
262 | GstMapInfo m; | 284 | GstCaps *s_caps; |
263 | size_t len, msg_size; | 285 | char *caps_str; |
264 | const char *ptr; | 286 | si = gst_sample_get_info (s); |
265 | int phase; | 287 | if (si) |
266 | 288 | { | |
267 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "pulling...\n"); | 289 | si_str = gst_structure_to_string (si); |
268 | s = gst_app_sink_pull_sample(GST_APP_SINK(sink)); | 290 | if (si_str) |
269 | if (NULL == s) | ||
270 | { | 291 | { |
271 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "pulled NULL\n"); | 292 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample %s\n", si_str); |
272 | break; | 293 | g_free (si_str); |
273 | } | 294 | } |
274 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "...pulled!\n"); | ||
275 | { | ||
276 | const GstStructure *si; | ||
277 | char *si_str; | ||
278 | GstCaps *s_caps; | ||
279 | char *caps_str; | ||
280 | si = gst_sample_get_info(s); | ||
281 | if (si) | ||
282 | { | ||
283 | si_str = gst_structure_to_string(si); | ||
284 | if (si_str) | ||
285 | { | ||
286 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got sample %s\n", si_str); | ||
287 | g_free(si_str); | ||
288 | } | ||
289 | } | ||
290 | else | ||
291 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got sample with no info\n"); | ||
292 | s_caps = gst_sample_get_caps(s); | ||
293 | if (s_caps) | ||
294 | { | ||
295 | caps_str = gst_caps_to_string(s_caps); | ||
296 | if (caps_str) | ||
297 | { | ||
298 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got sample with caps %s\n", caps_str); | ||
299 | g_free(caps_str); | ||
300 | } | ||
301 | } | ||
302 | else | ||
303 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got sample with no caps\n"); | ||
304 | } | 295 | } |
305 | b = gst_sample_get_buffer(s); | 296 | else |
306 | if (NULL == b || !gst_buffer_map(b, &m, GST_MAP_READ)) | 297 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no info\n"); |
298 | s_caps = gst_sample_get_caps (s); | ||
299 | if (s_caps) | ||
300 | { | ||
301 | caps_str = gst_caps_to_string (s_caps); | ||
302 | if (caps_str) | ||
307 | { | 303 | { |
308 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got NULL buffer %p or failed to map the buffer\n", b); | 304 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with caps %s\n", |
309 | gst_sample_unref(s); | 305 | caps_str); |
310 | continue; | 306 | g_free (caps_str); |
311 | } | 307 | } |
308 | } | ||
309 | else | ||
310 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no caps\n"); | ||
311 | } | ||
312 | b = gst_sample_get_buffer (s); | ||
313 | if ((NULL == b) || ! gst_buffer_map (b, &m, GST_MAP_READ)) | ||
314 | { | ||
315 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
316 | "got NULL buffer %p or failed to map the buffer\n", b); | ||
317 | gst_sample_unref (s); | ||
318 | continue; | ||
319 | } | ||
312 | 320 | ||
313 | len = m.size; | 321 | len = m.size; |
314 | if (len > UINT16_MAX - sizeof(struct AudioMessage)) | 322 | if (len > UINT16_MAX - sizeof(struct AudioMessage)) |
315 | { | 323 | { |
316 | GNUNET_break(0); | 324 | GNUNET_break (0); |
317 | len = UINT16_MAX - sizeof(struct AudioMessage); | 325 | len = UINT16_MAX - sizeof(struct AudioMessage); |
318 | } | 326 | } |
319 | msg_size = sizeof(struct AudioMessage) + len; | 327 | msg_size = sizeof(struct AudioMessage) + len; |
320 | audio_message.header.size = htons((uint16_t)msg_size); | 328 | audio_message.header.size = htons ((uint16_t) msg_size); |
321 | 329 | ||
322 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | 330 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
323 | "Sending %u bytes of audio data\n", (unsigned int)msg_size); | 331 | "Sending %u bytes of audio data\n", (unsigned int) msg_size); |
324 | for (phase = 0; phase < 2; phase++) | 332 | for (phase = 0; phase < 2; phase++) |
325 | { | 333 | { |
326 | size_t offset; | 334 | size_t offset; |
327 | size_t to_send; | 335 | size_t to_send; |
328 | ssize_t ret; | 336 | ssize_t ret; |
329 | if (0 == phase) | 337 | if (0 == phase) |
330 | { | 338 | { |
331 | #ifdef DEBUG_RECORD_PURE_OGG | 339 | #ifdef DEBUG_RECORD_PURE_OGG |
332 | if (dump_pure_ogg) | 340 | if (dump_pure_ogg) |
333 | continue; | 341 | continue; |
334 | #endif | 342 | #endif |
335 | ptr = (const char *)&audio_message; | 343 | ptr = (const char *) &audio_message; |
336 | to_send = sizeof(audio_message); | 344 | to_send = sizeof(audio_message); |
337 | } | 345 | } |
338 | else | 346 | else |
339 | { | 347 | { |
340 | ptr = (const char *)m.data; | 348 | ptr = (const char *) m.data; |
341 | to_send = len; | 349 | to_send = len; |
342 | } | 350 | } |
343 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | 351 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
344 | "Sending %u bytes on phase %d\n", (unsigned int)to_send, phase); | 352 | "Sending %u bytes on phase %d\n", (unsigned int) to_send, |
345 | for (offset = 0; offset < to_send; offset += ret) | 353 | phase); |
346 | { | 354 | for (offset = 0; offset < to_send; offset += ret) |
347 | ret = write(1, &ptr[offset], to_send - offset); | 355 | { |
348 | if (0 >= ret) | 356 | ret = write (1, &ptr[offset], to_send - offset); |
349 | { | 357 | if (0 >= ret) |
350 | if (-1 == ret) | 358 | { |
351 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | 359 | if (-1 == ret) |
352 | "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n", | 360 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
353 | (unsigned int)(to_send - offset), | 361 | "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n", |
354 | (unsigned int)offset, | 362 | (unsigned int) (to_send - offset), |
355 | (unsigned int)(to_send + offset), | 363 | (unsigned int) offset, |
356 | phase, | 364 | (unsigned int) (to_send + offset), |
357 | strerror(errno)); | 365 | phase, |
358 | abort_send = 1; | 366 | strerror (errno)); |
359 | break; | 367 | abort_send = 1; |
360 | } | 368 | break; |
361 | } | ||
362 | if (abort_send) | ||
363 | break; | ||
364 | } | 369 | } |
365 | gst_buffer_unmap(b, &m); | 370 | } |
366 | gst_sample_unref(s); | 371 | if (abort_send) |
372 | break; | ||
367 | } | 373 | } |
374 | gst_buffer_unmap (b, &m); | ||
375 | gst_sample_unref (s); | ||
376 | } | ||
368 | 377 | ||
369 | signal(SIGINT, inthandler); | 378 | signal (SIGINT, inthandler); |
370 | signal(SIGINT, termhandler); | 379 | signal (SIGINT, termhandler); |
371 | 380 | ||
372 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Returned, stopping playback\n"); | 381 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returned, stopping playback\n"); |
373 | quit(); | 382 | quit (); |
374 | 383 | ||
375 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Deleting pipeline\n"); | 384 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Deleting pipeline\n"); |
376 | gst_object_unref(GST_OBJECT(pipeline)); | 385 | gst_object_unref (GST_OBJECT (pipeline)); |
377 | pipeline = NULL; | 386 | pipeline = NULL; |
378 | g_source_remove(bus_watch_id); | 387 | g_source_remove (bus_watch_id); |
379 | 388 | ||
380 | return 0; | 389 | return 0; |
381 | } | 390 | } |