aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-helper-audio-record.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-02 22:13:12 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-02 22:13:12 +0000
commit3d8c72a1dc1981d866d752a3d3567830fecd0eae (patch)
treedc3949c8759052bd051e1a8b0df2255e544067a2 /src/conversation/gnunet-helper-audio-record.c
parent517263c3f5134e5dba57a25e745cb276937602bc (diff)
downloadgnunet-3d8c72a1dc1981d866d752a3d3567830fecd0eae.tar.gz
gnunet-3d8c72a1dc1981d866d752a3d3567830fecd0eae.zip
-debugging logic
Diffstat (limited to 'src/conversation/gnunet-helper-audio-record.c')
-rw-r--r--src/conversation/gnunet-helper-audio-record.c358
1 files changed, 183 insertions, 175 deletions
diff --git a/src/conversation/gnunet-helper-audio-record.c b/src/conversation/gnunet-helper-audio-record.c
index 2267c764b..c14b35fe6 100644
--- a/src/conversation/gnunet-helper-audio-record.c
+++ b/src/conversation/gnunet-helper-audio-record.c
@@ -22,6 +22,7 @@
22 * @brief constants for network protocols 22 * @brief constants for network protocols
23 * @author Siomon Dieterle 23 * @author Siomon Dieterle
24 * @author Andreas Fuchs 24 * @author Andreas Fuchs
25 * @author Christian Grothoff
25 */ 26 */
26#include "platform.h" 27#include "platform.h"
27#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
@@ -38,13 +39,15 @@
38#include <opus/opus.h> 39#include <opus/opus.h>
39#include <opus/opus_types.h> 40#include <opus/opus_types.h>
40 41
42#define SAMPLING_RATE 48000
43
41 44
42/** 45/**
43 * Specification for recording. May change in the future to spec negotiation. 46 * Specification for recording. May change in the future to spec negotiation.
44 */ 47 */
45static pa_sample_spec sample_spec = { 48static pa_sample_spec sample_spec = {
46 .format = PA_SAMPLE_FLOAT32LE, 49 .format = PA_SAMPLE_FLOAT32LE,
47 .rate = 48000, 50 .rate = SAMPLING_RATE,
48 .channels = 1 51 .channels = 1
49}; 52};
50 53
@@ -106,7 +109,7 @@ static int max_payload_bytes = 1500;
106/** 109/**
107 * Audio buffer 110 * Audio buffer
108 */ 111 */
109static void *transmit_buffer; 112static char *transmit_buffer;
110 113
111/** 114/**
112 * Length of audio buffer 115 * Length of audio buffer
@@ -141,15 +144,21 @@ quit (int ret)
141static void 144static void
142packetizer () 145packetizer ()
143{ 146{
147 static unsigned long long toff;
148 char *nbuf;
149 size_t new_size;
150 const char *ptr;
151 size_t off;
152 ssize_t ret;
153 int len; // FIXME: int?
154 size_t msg_size;
155
144 while (transmit_buffer_length >= transmit_buffer_index + pcm_length) 156 while (transmit_buffer_length >= transmit_buffer_index + pcm_length)
145 { 157 {
146 ssize_t ret;
147 int len; // FIXME: int?
148 size_t msg_size;
149
150 memcpy (pcm_buffer, 158 memcpy (pcm_buffer,
151 (float *) transmit_buffer + 159 &transmit_buffer[transmit_buffer_index],
152 (transmit_buffer_index / sizeof (float)), pcm_length); 160 pcm_length);
161 transmit_buffer_index += pcm_length;
153 len = 162 len =
154 opus_encode_float (enc, pcm_buffer, frame_size, opus_data, 163 opus_encode_float (enc, pcm_buffer, frame_size, opus_data,
155 max_payload_bytes); 164 max_payload_bytes);
@@ -162,25 +171,43 @@ packetizer ()
162 audio_message->header.size = htons ((uint16_t) msg_size); 171 audio_message->header.size = htons ((uint16_t) msg_size);
163 memcpy (&audio_message[1], opus_data, len); 172 memcpy (&audio_message[1], opus_data, len);
164 173
165 // FIXME: handle partial writes better... 174 toff += msg_size;
166 if ((ret = write (1, audio_message, msg_size)) != msg_size) 175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176 "Sending %u bytes of audio data (total: %llu)\n",
177 (unsigned int) msg_size,
178 toff);
179 ptr = (const char *) audio_message;
180 off = 0;
181 while (off < msg_size)
167 { 182 {
168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("write")); 183 ret = write (1, &ptr[off], msg_size - off);
169 return; 184 if (0 >= ret)
170 } 185 {
171 transmit_buffer_index += pcm_length; 186 if (-1 == ret)
187 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "write");
188 quit (2);
189 }
190 off += ret;
191 }
172 } 192 }
173 193
174 int new_size = transmit_buffer_length - transmit_buffer_index; 194 new_size = transmit_buffer_length - transmit_buffer_index;
175 if (0 != new_size) 195 if (0 != new_size)
176 { 196 {
177 transmit_buffer = pa_xrealloc (transmit_buffer, new_size); 197 nbuf = pa_xmalloc (new_size);
178 memcpy (transmit_buffer, transmit_buffer + transmit_buffer_index, 198 memmove (nbuf,
179 new_size); 199 &transmit_buffer[transmit_buffer_index],
180 200 new_size);
181 transmit_buffer_index = 0; 201 pa_xfree (transmit_buffer);
182 transmit_buffer_length = new_size; 202 transmit_buffer = nbuf;
183 } 203 }
204 else
205 {
206 pa_xfree (transmit_buffer);
207 transmit_buffer = NULL;
208 }
209 transmit_buffer_index = 0;
210 transmit_buffer_length = new_size;
184} 211}
185 212
186 213
@@ -188,31 +215,33 @@ packetizer ()
188 * Pulseaudio callback when new data is available. 215 * Pulseaudio callback when new data is available.
189 */ 216 */
190static void 217static void
191stream_read_callback (pa_stream * s, size_t length, void *userdata) 218stream_read_callback (pa_stream * s,
219 size_t length,
220 void *userdata)
192{ 221{
193 const void *data; 222 const void *data;
194 223
195 GNUNET_assert (s); 224 GNUNET_assert (NULL != s);
196 GNUNET_assert (length > 0); 225 GNUNET_assert (length > 0);
197 if (stdio_event) 226 if (stdio_event)
198 mainloop_api->io_enable (stdio_event, PA_IO_EVENT_OUTPUT); 227 mainloop_api->io_enable (stdio_event, PA_IO_EVENT_OUTPUT);
199 228
200 if (pa_stream_peek (s, (const void **) &data, &length) < 0) 229 if (pa_stream_peek (s, (const void **) &data, &length) < 0)
201 { 230 {
202 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_stream_peek() failed: %s\n"), 231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
203 pa_strerror (pa_context_errno (context))); 232 _("pa_stream_peek() failed: %s\n"),
204 quit (1); 233 pa_strerror (pa_context_errno (context)));
205 return; 234 quit (1);
206 } 235 return;
207 236 }
208 GNUNET_assert (data); 237 GNUNET_assert (NULL != data);
209 GNUNET_assert (length > 0); 238 GNUNET_assert (length > 0);
210 239 if (NULL != transmit_buffer)
211 if (transmit_buffer)
212 { 240 {
213 transmit_buffer = 241 transmit_buffer = pa_xrealloc (transmit_buffer,
214 pa_xrealloc (transmit_buffer, transmit_buffer_length + length); 242 transmit_buffer_length + length);
215 memcpy ((uint8_t *) transmit_buffer + transmit_buffer_length, data, 243 memcpy (&transmit_buffer[transmit_buffer_length],
244 data,
216 length); 245 length);
217 transmit_buffer_length += length; 246 transmit_buffer_length += length;
218 } 247 }
@@ -249,61 +278,57 @@ exit_signal_callback (pa_mainloop_api * m,
249static void 278static void
250stream_state_callback (pa_stream * s, void *userdata) 279stream_state_callback (pa_stream * s, void *userdata)
251{ 280{
252 GNUNET_assert (s); 281 GNUNET_assert (NULL != s);
253 282
254 switch (pa_stream_get_state (s)) 283 switch (pa_stream_get_state (s))
284 {
285 case PA_STREAM_CREATING:
286 case PA_STREAM_TERMINATED:
287 break;
288 case PA_STREAM_READY:
255 { 289 {
256 case PA_STREAM_CREATING: 290 const pa_buffer_attr *a;
257 case PA_STREAM_TERMINATED: 291 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX],
258 break; 292 sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
259 293
260 case PA_STREAM_READY: 294 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
261 if (1) 295 _("Stream successfully created.\n"));
262 { 296
263 const pa_buffer_attr *a; 297 if (!(a = pa_stream_get_buffer_attr (s)))
264 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], 298 {
265 sst[PA_SAMPLE_SPEC_SNPRINT_MAX]; 299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
266 300 _("pa_stream_get_buffer_attr() failed: %s\n"),
267 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 301 pa_strerror (pa_context_errno
268 _("Stream successfully created.\n")); 302 (pa_stream_get_context (s))));
269 303
270 if (!(a = pa_stream_get_buffer_attr (s))) 304 }
271 { 305 else
272 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 306 {
273 _("pa_stream_get_buffer_attr() failed: %s\n"), 307 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274 pa_strerror (pa_context_errno 308 _("Buffer metrics: maxlength=%u, fragsize=%u\n"),
275 (pa_stream_get_context (s)))); 309 a->maxlength, a->fragsize);
276 310 }
277 } 311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
278 else 312 _("Using sample spec '%s', channel map '%s'.\n"),
279 { 313 pa_sample_spec_snprint (sst, sizeof (sst),
280 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 314 pa_stream_get_sample_spec (s)),
281 _("Buffer metrics: maxlength=%u, fragsize=%u\n"), 315 pa_channel_map_snprint (cmt, sizeof (cmt),
282 a->maxlength, a->fragsize); 316 pa_stream_get_channel_map (s)));
283 } 317
284 318 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
285 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 319 _("Connected to device %s (%u, %ssuspended).\n"),
286 _("Using sample spec '%s', channel map '%s'.\n"), 320 pa_stream_get_device_name (s),
287 pa_sample_spec_snprint (sst, sizeof (sst), 321 pa_stream_get_device_index (s),
288 pa_stream_get_sample_spec (s)), 322 pa_stream_is_suspended (s) ? "" : "not ");
289 pa_channel_map_snprint (cmt, sizeof (cmt), 323 }
290 pa_stream_get_channel_map (s))); 324 break;
291 325 case PA_STREAM_FAILED:
292 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 326 default:
293 _("Connected to device %s (%u, %ssuspended).\n"), 327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294 pa_stream_get_device_name (s), 328 _("Stream error: %s\n"),
295 pa_stream_get_device_index (s), 329 pa_strerror (pa_context_errno (pa_stream_get_context (s))));
296 pa_stream_is_suspended (s) ? "" : "not "); 330 quit (1);
297 } 331 }
298
299 break;
300
301 case PA_STREAM_FAILED:
302 default:
303 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Stream error: %s\n"),
304 pa_strerror (pa_context_errno (pa_stream_get_context (s))));
305 quit (1);
306 }
307} 332}
308 333
309 334
@@ -317,58 +342,48 @@ context_state_callback (pa_context * c,
317 GNUNET_assert (c); 342 GNUNET_assert (c);
318 343
319 switch (pa_context_get_state (c)) 344 switch (pa_context_get_state (c))
345 {
346 case PA_CONTEXT_CONNECTING:
347 case PA_CONTEXT_AUTHORIZING:
348 case PA_CONTEXT_SETTING_NAME:
349 break;
350 case PA_CONTEXT_READY:
351 {
352 int r;
353
354 GNUNET_assert (!stream_in);
355 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
356 _("Connection established.\n"));
357 if (! (stream_in =
358 pa_stream_new (c, "GNUNET_VoIP recorder", &sample_spec, NULL)))
320 { 359 {
321 case PA_CONTEXT_CONNECTING: 360 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
322 case PA_CONTEXT_AUTHORIZING: 361 _("pa_stream_new() failed: %s\n"),
323 case PA_CONTEXT_SETTING_NAME:
324 break;
325
326 case PA_CONTEXT_READY:
327 {
328 int r;
329
330 GNUNET_assert (c);
331 GNUNET_assert (!stream_in);
332
333 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connection established.\n"));
334
335 if (!
336 (stream_in =
337 pa_stream_new (c, "GNUNET_VoIP recorder", &sample_spec, NULL)))
338 {
339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
340 _("pa_stream_new() failed: %s\n"),
341 pa_strerror (pa_context_errno (c)));
342 goto fail;
343 }
344
345
346 pa_stream_set_state_callback (stream_in, stream_state_callback, NULL);
347 pa_stream_set_read_callback (stream_in, stream_read_callback, NULL);
348
349
350 if ((r = pa_stream_connect_record (stream_in, NULL, NULL, 0)) < 0)
351 {
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353 _("pa_stream_connect_record() failed: %s\n"),
354 pa_strerror (pa_context_errno (c)));
355 goto fail;
356 }
357
358 break;
359 }
360
361 case PA_CONTEXT_TERMINATED:
362 quit (0);
363 break;
364
365 case PA_CONTEXT_FAILED:
366 default:
367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Connection failure: %s\n"),
368 pa_strerror (pa_context_errno (c))); 362 pa_strerror (pa_context_errno (c)));
369 goto fail; 363 goto fail;
370 } 364 }
371 365 pa_stream_set_state_callback (stream_in, stream_state_callback, NULL);
366 pa_stream_set_read_callback (stream_in, stream_read_callback, NULL);
367 if ((r = pa_stream_connect_record (stream_in, NULL, NULL, 0)) < 0)
368 {
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 _("pa_stream_connect_record() failed: %s\n"),
371 pa_strerror (pa_context_errno (c)));
372 goto fail;
373 }
374
375 break;
376 }
377 case PA_CONTEXT_TERMINATED:
378 quit (0);
379 break;
380 case PA_CONTEXT_FAILED:
381 default:
382 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
383 _("Connection failure: %s\n"),
384 pa_strerror (pa_context_errno (c)));
385 goto fail;
386 }
372 return; 387 return;
373 388
374fail: 389fail:
@@ -386,21 +401,19 @@ pa_init ()
386 int i; 401 int i;
387 402
388 if (!pa_sample_spec_valid (&sample_spec)) 403 if (!pa_sample_spec_valid (&sample_spec))
389 { 404 {
390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong Spec\n")); 405 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
391 } 406 _("Wrong Spec\n"));
392 407 }
393 /* set up main record loop */ 408 /* set up main record loop */
394
395 if (!(m = pa_mainloop_new ())) 409 if (!(m = pa_mainloop_new ()))
396 { 410 {
397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_new() failed.\n")); 411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
398 } 412 _("pa_mainloop_new() failed.\n"));
399 413 }
400 mainloop_api = pa_mainloop_get_api (m); 414 mainloop_api = pa_mainloop_get_api (m);
401 415
402 /* listen to signals */ 416 /* listen to signals */
403
404 r = pa_signal_init (mainloop_api); 417 r = pa_signal_init (mainloop_api);
405 GNUNET_assert (r == 0); 418 GNUNET_assert (r == 0);
406 pa_signal_new (SIGINT, exit_signal_callback, NULL); 419 pa_signal_new (SIGINT, exit_signal_callback, NULL);
@@ -409,23 +422,22 @@ pa_init ()
409 /* connect to the main pulseaudio context */ 422 /* connect to the main pulseaudio context */
410 423
411 if (!(context = pa_context_new (mainloop_api, "GNUNET VoIP"))) 424 if (!(context = pa_context_new (mainloop_api, "GNUNET VoIP")))
412 { 425 {
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_context_new() failed.\n")); 426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
414 } 427 _("pa_context_new() failed.\n"));
415 428 }
416 pa_context_set_state_callback (context, context_state_callback, NULL); 429 pa_context_set_state_callback (context, context_state_callback, NULL);
417
418 if (pa_context_connect (context, NULL, 0, NULL) < 0) 430 if (pa_context_connect (context, NULL, 0, NULL) < 0)
419 { 431 {
420 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 432 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
421 _("pa_context_connect() failed: %s\n"), 433 _("pa_context_connect() failed: %s\n"),
422 pa_strerror (pa_context_errno (context))); 434 pa_strerror (pa_context_errno (context)));
423 } 435 }
424
425 if (pa_mainloop_run (m, &i) < 0) 436 if (pa_mainloop_run (m, &i) < 0)
426 { 437 {
427 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_run() failed.\n")); 438 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
428 } 439 _("pa_mainloop_run() failed.\n"));
440 }
429} 441}
430 442
431 443
@@ -435,20 +447,17 @@ pa_init ()
435static void 447static void
436opus_init () 448opus_init ()
437{ 449{
438 opus_int32 sampling_rate = 48000;
439 int channels = 1; 450 int channels = 1;
440 int err; 451 int err;
441 452
442 frame_size = sampling_rate / 50; 453 frame_size = SAMPLING_RATE / 50;
443 pcm_length = frame_size * channels * sizeof (float); 454 pcm_length = frame_size * channels * sizeof (float);
444 enc = 455 pcm_buffer = pa_xmalloc (pcm_length);
445 opus_encoder_create (sampling_rate, channels, OPUS_APPLICATION_VOIP, 456 opus_data = GNUNET_malloc (max_payload_bytes);
446 &err); 457 enc = opus_encoder_create (SAMPLING_RATE,
447 pcm_buffer = (float *) pa_xmalloc (pcm_length); 458 channels,
448 opus_data = (unsigned char *) calloc (max_payload_bytes, sizeof (char)); 459 OPUS_APPLICATION_VOIP,
449 460 &err);
450 audio_message = pa_xmalloc (UINT16_MAX);
451 audio_message->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
452} 461}
453 462
454 463
@@ -462,14 +471,13 @@ opus_init ()
462int 471int
463main (int argc, char *argv[]) 472main (int argc, char *argv[])
464{ 473{
465 fprintf (stderr, "HERE2!\n");
466
467 GNUNET_assert (GNUNET_OK == 474 GNUNET_assert (GNUNET_OK ==
468 GNUNET_log_setup ("gnunet-helper-audio-record", 475 GNUNET_log_setup ("gnunet-helper-audio-record",
469 "WARNING", 476 "DEBUG",
470 NULL)); 477 "/tmp/helper-audio-record"));
478 audio_message = GNUNET_malloc (UINT16_MAX);
479 audio_message->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
471 opus_init (); 480 opus_init ();
472 pa_init (); 481 pa_init ();
473
474 return 0; 482 return 0;
475} 483}