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