aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-helper-audio-playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conversation/gnunet-helper-audio-playback.c')
-rw-r--r--src/conversation/gnunet-helper-audio-playback.c1025
1 files changed, 522 insertions, 503 deletions
diff --git a/src/conversation/gnunet-helper-audio-playback.c b/src/conversation/gnunet-helper-audio-playback.c
index 34e61c100..d7e1cd036 100644
--- a/src/conversation/gnunet-helper-audio-playback.c
+++ b/src/conversation/gnunet-helper-audio-playback.c
@@ -124,7 +124,8 @@ static float gain;
124GNUNET_NETWORK_STRUCT_BEGIN 124GNUNET_NETWORK_STRUCT_BEGIN
125 125
126/* OggOpus spec says the numbers must be in little-endian order */ 126/* OggOpus spec says the numbers must be in little-endian order */
127struct OpusHeadPacket { 127struct OpusHeadPacket
128{
128 uint8_t magic[8]; 129 uint8_t magic[8];
129 uint8_t version; 130 uint8_t version;
130 uint8_t channels; 131 uint8_t channels;
@@ -142,71 +143,71 @@ GNUNET_NETWORK_STRUCT_END
142 * elsewhere in the code. 143 * elsewhere in the code.
143 */ 144 */
144static OpusDecoder * 145static OpusDecoder *
145process_header(ogg_packet *op) 146process_header (ogg_packet *op)
146{ 147{
147 int err; 148 int err;
148 OpusDecoder *dec; 149 OpusDecoder *dec;
149 struct OpusHeadPacket header; 150 struct OpusHeadPacket header;
150 151
151 if (((unsigned int)op->bytes) < sizeof(header)) 152 if (((unsigned int) op->bytes) < sizeof(header))
152 return NULL; 153 return NULL;
153 GNUNET_memcpy(&header, 154 GNUNET_memcpy (&header,
154 op->packet, 155 op->packet,
155 sizeof(header)); 156 sizeof(header));
156 header.preskip = GNUNET_le16toh(header.preskip); 157 header.preskip = GNUNET_le16toh (header.preskip);
157 header.sampling_rate = GNUNET_le32toh(header.sampling_rate); 158 header.sampling_rate = GNUNET_le32toh (header.sampling_rate);
158 header.gain = GNUNET_le16toh(header.gain); 159 header.gain = GNUNET_le16toh (header.gain);
159 160
160 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
161 "Header: v%u, %u-ch, skip %u, %uHz, %u gain\n", 162 "Header: v%u, %u-ch, skip %u, %uHz, %u gain\n",
162 header.version, 163 header.version,
163 header.channels, 164 header.channels,
164 header.preskip, 165 header.preskip,
165 header.sampling_rate, 166 header.sampling_rate,
166 header.gain); 167 header.gain);
167 channels = header.channels; 168 channels = header.channels;
168 preskip = header.preskip; 169 preskip = header.preskip;
169 170
170 if (header.channel_mapping != 0) 171 if (header.channel_mapping != 0)
171 { 172 {
172 fprintf(stderr, 173 fprintf (stderr,
173 "This implementation does not support non-mono streams\n"); 174 "This implementation does not support non-mono streams\n");
174 return NULL; 175 return NULL;
175 } 176 }
176 177
177 dec = opus_decoder_create(SAMPLING_RATE, channels, &err); 178 dec = opus_decoder_create (SAMPLING_RATE, channels, &err);
178 if (OPUS_OK != err) 179 if (OPUS_OK != err)
180 {
181 fprintf (stderr,
182 "Cannot create encoder: %s\n",
183 opus_strerror (err));
184 return NULL;
185 }
186 if (! dec)
187 {
188 fprintf (stderr,
189 "Decoder initialization failed: %s\n",
190 opus_strerror (err));
191 return NULL;
192 }
193
194 if (0 != header.gain)
195 {
196 /*Gain API added in a newer libopus version, if we don't have it
197 we apply the gain ourselves. We also add in a user provided
198 manual gain at the same time.*/
199 int gainadj = (int) header.gain;
200 err = opus_decoder_ctl (dec, OPUS_SET_GAIN (gainadj));
201 if (OPUS_UNIMPLEMENTED == err)
179 { 202 {
180 fprintf(stderr, 203 gain = pow (10.0, gainadj / 5120.0);
181 "Cannot create encoder: %s\n",
182 opus_strerror(err));
183 return NULL;
184 } 204 }
185 if (!dec) 205 else if (OPUS_OK != err)
186 { 206 {
187 fprintf(stderr, 207 fprintf (stderr, "Error setting gain: %s\n", opus_strerror (err));
188 "Decoder initialization failed: %s\n",
189 opus_strerror(err));
190 return NULL; 208 return NULL;
191 } 209 }
192 210 }
193 if (0 != header.gain)
194 {
195 /*Gain API added in a newer libopus version, if we don't have it
196 we apply the gain ourselves. We also add in a user provided
197 manual gain at the same time.*/
198 int gainadj = (int)header.gain;
199 err = opus_decoder_ctl(dec, OPUS_SET_GAIN(gainadj));
200 if (OPUS_UNIMPLEMENTED == err)
201 {
202 gain = pow(10.0, gainadj / 5120.0);
203 }
204 else if (OPUS_OK != err)
205 {
206 fprintf(stderr, "Error setting gain: %s\n", opus_strerror(err));
207 return NULL;
208 }
209 }
210 211
211 return dec; 212 return dec;
212} 213}
@@ -214,58 +215,58 @@ process_header(ogg_packet *op)
214 215
215#ifdef DEBUG_DUMP_DECODED_OGG 216#ifdef DEBUG_DUMP_DECODED_OGG
216static size_t 217static size_t
217fwrite_le32(opus_int32 i32, FILE *file) 218fwrite_le32 (opus_int32 i32, FILE *file)
218{ 219{
219 unsigned char buf[4]; 220 unsigned char buf[4];
220 221
221 buf[0] = (unsigned char)(i32 & 0xFF); 222 buf[0] = (unsigned char) (i32 & 0xFF);
222 buf[1] = (unsigned char)(i32 >> 8 & 0xFF); 223 buf[1] = (unsigned char) (i32 >> 8 & 0xFF);
223 buf[2] = (unsigned char)(i32 >> 16 & 0xFF); 224 buf[2] = (unsigned char) (i32 >> 16 & 0xFF);
224 buf[3] = (unsigned char)(i32 >> 24 & 0xFF); 225 buf[3] = (unsigned char) (i32 >> 24 & 0xFF);
225 return fwrite(buf, 4, 1, file); 226 return fwrite (buf, 4, 1, file);
226} 227}
227 228
228 229
229static size_t 230static size_t
230fwrite_le16(int i16, FILE *file) 231fwrite_le16 (int i16, FILE *file)
231{ 232{
232 unsigned char buf[2]; 233 unsigned char buf[2];
233 234
234 buf[0] = (unsigned char)(i16 & 0xFF); 235 buf[0] = (unsigned char) (i16 & 0xFF);
235 buf[1] = (unsigned char)(i16 >> 8 & 0xFF); 236 buf[1] = (unsigned char) (i16 >> 8 & 0xFF);
236 return fwrite(buf, 2, 1, file); 237 return fwrite (buf, 2, 1, file);
237} 238}
238 239
239 240
240static int 241static int
241write_wav_header() 242write_wav_header ()
242{ 243{
243 int ret; 244 int ret;
244 FILE *file = stdout; 245 FILE *file = stdout;
245 246
246 ret = fprintf(file, "RIFF") >= 0; 247 ret = fprintf (file, "RIFF") >= 0;
247 ret &= fwrite_le32(0x7fffffff, file); 248 ret &= fwrite_le32 (0x7fffffff, file);
248 249
249 ret &= fprintf(file, "WAVEfmt ") >= 0; 250 ret &= fprintf (file, "WAVEfmt ") >= 0;
250 ret &= fwrite_le32(16, file); 251 ret &= fwrite_le32 (16, file);
251 ret &= fwrite_le16(1, file); 252 ret &= fwrite_le16 (1, file);
252 ret &= fwrite_le16(channels, file); 253 ret &= fwrite_le16 (channels, file);
253 ret &= fwrite_le32(SAMPLING_RATE, file); 254 ret &= fwrite_le32 (SAMPLING_RATE, file);
254 ret &= fwrite_le32(2 * channels * SAMPLING_RATE, file); 255 ret &= fwrite_le32 (2 * channels * SAMPLING_RATE, file);
255 ret &= fwrite_le16(2 * channels, file); 256 ret &= fwrite_le16 (2 * channels, file);
256 ret &= fwrite_le16(16, file); 257 ret &= fwrite_le16 (16, file);
257 258
258 ret &= fprintf(file, "data") >= 0; 259 ret &= fprintf (file, "data") >= 0;
259 ret &= fwrite_le32(0x7fffffff, file); 260 ret &= fwrite_le32 (0x7fffffff, file);
260 261
261 return !ret ? -1 : 16; 262 return ! ret ? -1 : 16;
262} 263}
263 264
264#endif 265#endif
265 266
266 267
267static int64_t 268static int64_t
268audio_write(int64_t maxout) 269audio_write (int64_t maxout)
269{ 270{
270 int64_t sampout = 0; 271 int64_t sampout = 0;
271 int tmp_skip; 272 int tmp_skip;
@@ -276,66 +277,67 @@ audio_write(int64_t maxout)
276#ifdef DEBUG_DUMP_DECODED_OGG 277#ifdef DEBUG_DUMP_DECODED_OGG
277 static int wrote_wav_header; 278 static int wrote_wav_header;
278 279
279 if (dump_to_stdout && !wrote_wav_header) 280 if (dump_to_stdout && ! wrote_wav_header)
280 { 281 {
281 write_wav_header(); 282 write_wav_header ();
282 wrote_wav_header = 1; 283 wrote_wav_header = 1;
283 } 284 }
284#endif 285#endif
285 maxout = 0 > maxout ? 0 : maxout; 286 maxout = 0 > maxout ? 0 : maxout;
286 do 287 do
288 {
289 tmp_skip = (preskip > frame_size) ? (int) frame_size : preskip;
290 preskip -= tmp_skip;
291 output = pcm_buffer + channels * tmp_skip;
292 out_len = frame_size - tmp_skip;
293 if (out_len > MAX_FRAME_SIZE)
294 exit (6);
295 frame_size = 0;
296
297 to_write = out_len < maxout ? out_len : (unsigned) maxout;
298 if (0 < maxout)
287 { 299 {
288 tmp_skip = (preskip > frame_size) ? (int)frame_size : preskip; 300 int64_t wrote = 0;
289 preskip -= tmp_skip; 301 wrote = to_write;
290 output = pcm_buffer + channels * tmp_skip; 302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291 out_len = frame_size - tmp_skip; 303 "Writing %u * %u * %u = %llu bytes into PA\n",
292 if (out_len > MAX_FRAME_SIZE) 304 to_write,
293 exit(6); 305 channels,
294 frame_size = 0; 306 (unsigned int) sizeof(float),
295 307 (unsigned long long) (to_write * channels * sizeof(float)));
296 to_write = out_len < maxout ? out_len : (unsigned)maxout;
297 if (0 < maxout)
298 {
299 int64_t wrote = 0;
300 wrote = to_write;
301 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
302 "Writing %u * %u * %u = %llu bytes into PA\n",
303 to_write,
304 channels,
305 (unsigned int)sizeof(float),
306 (unsigned long long)(to_write * channels * sizeof(float)));
307#ifdef DEBUG_DUMP_DECODED_OGG 308#ifdef DEBUG_DUMP_DECODED_OGG
308 if (dump_to_stdout) 309 if (dump_to_stdout)
309 { 310 {
310# define fminf(_x, _y) ((_x) < (_y) ? (_x) : (_y)) 311# define fminf(_x, _y) ((_x) < (_y) ? (_x) : (_y))
311# define fmaxf(_x, _y) ((_x) > (_y) ? (_x) : (_y)) 312# define fmaxf(_x, _y) ((_x) > (_y) ? (_x) : (_y))
312# define float2int(flt) ((int)(floor(.5 + flt))) 313# define float2int(flt) ((int) (floor (.5 + flt)))
313 int i; 314 int i;
314 int16_t *out = alloca(sizeof(short) * MAX_FRAME_SIZE * channels); 315 int16_t *out = alloca (sizeof(short) * MAX_FRAME_SIZE * channels);
315 for (i = 0; i < (int)out_len * channels; i++) 316 for (i = 0; i < (int) out_len * channels; i++)
316 out[i] = (short)float2int(fmaxf(-32768, fminf(output[i] * 32768.f, 32767))); 317 out[i] = (short) float2int (fmaxf (-32768, fminf (output[i] * 32768.f,
317 318 32767)));
318 fwrite(out, 2 * channels, out_len < maxout ? out_len : maxout, stdout); 319
319 } 320 fwrite (out, 2 * channels, out_len < maxout ? out_len : maxout, stdout);
320 else 321 }
322 else
321#endif 323#endif
322 if (pa_stream_write 324 if (pa_stream_write
323 (stream_out, output, to_write * channels * sizeof(float), NULL, 0, 325 (stream_out, output, to_write * channels * sizeof(float), NULL, 0,
324 PA_SEEK_RELATIVE) < 0) 326 PA_SEEK_RELATIVE) < 0)
325 { 327 {
326 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327 _("pa_stream_write() failed: %s\n"), 329 _ ("pa_stream_write() failed: %s\n"),
328 pa_strerror(pa_context_errno(context))); 330 pa_strerror (pa_context_errno (context)));
329 } 331 }
330 sampout += wrote; 332 sampout += wrote;
331 maxout -= wrote; 333 maxout -= wrote;
332 }
333 } 334 }
335 }
334 while (0 < frame_size && 0 < maxout); 336 while (0 < frame_size && 0 < maxout);
335 337
336 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337 "Wrote %" PRId64 " samples\n", 339 "Wrote %" PRId64 " samples\n",
338 sampout); 340 sampout);
339 return sampout; 341 return sampout;
340} 342}
341 343
@@ -344,16 +346,16 @@ audio_write(int64_t maxout)
344 * Pulseaudio shutdown task 346 * Pulseaudio shutdown task
345 */ 347 */
346static void 348static void
347quit(int ret) 349quit (int ret)
348{ 350{
349 mainloop_api->quit(mainloop_api, 351 mainloop_api->quit (mainloop_api,
350 ret); 352 ret);
351 exit(ret); 353 exit (ret);
352} 354}
353 355
354 356
355static void 357static void
356ogg_demux_and_decode() 358ogg_demux_and_decode ()
357{ 359{
358 ogg_page og; 360 ogg_page og;
359 static int stream_init; 361 static int stream_init;
@@ -368,189 +370,204 @@ ogg_demux_and_decode()
368 static int total_links; 370 static int total_links;
369 static int gran_offset; 371 static int gran_offset;
370 372
371 while (1 == ogg_sync_pageout(&oy, &og)) 373 while (1 == ogg_sync_pageout (&oy, &og))
374 {
375 if (0 == stream_init)
376 {
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Initialized the stream\n");
379 ogg_stream_init (&os, ogg_page_serialno (&og));
380 stream_init = 1;
381 }
382 if (ogg_page_serialno (&og) != os.serialno)
383 {
384 /* so all streams are read. */
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Re-set serial number\n");
387 ogg_stream_reset_serialno (&os, ogg_page_serialno (&og));
388 }
389 /*Add page to the bitstream*/
390 ogg_stream_pagein (&os, &og);
391 page_granule = ogg_page_granulepos (&og);
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Reading page that ends at %" PRId64 "\n",
394 page_granule);
395 /*Extract all available packets*/
396 while (1 == ogg_stream_packetout (&os, &op))
372 { 397 {
373 if (0 == stream_init) 398 /*OggOpus streams are identified by a magic string in the initial
399 stream header.*/
400 if (op.b_o_s &&(op.bytes >= 8) && ! memcmp (op.packet, "OpusHead", 8))
401 {
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403 "Got Opus Header\n");
404 if (has_opus_stream && has_tags_packet)
374 { 405 {
375 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 406 /*If we're seeing another BOS OpusHead now it means
376 "Initialized the stream\n"); 407 the stream is chained without an EOS.
377 ogg_stream_init(&os, ogg_page_serialno(&og)); 408 This can easily happen if record helper is terminated unexpectedly.
378 stream_init = 1; 409 */
410 has_opus_stream = 0;
411 if (dec)
412 opus_decoder_destroy (dec);
413 dec = NULL;
414 fprintf (stderr,
415 "\nWarning: stream %" PRId64
416 " ended without EOS and a new stream began.\n",
417 (int64_t) os.serialno);
379 } 418 }
380 if (ogg_page_serialno(&og) != os.serialno) 419 if (! has_opus_stream)
381 { 420 {
382 /* so all streams are read. */ 421 if ((packet_count > 0) &&(opus_serialno == os.serialno) )
383 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 422 {
384 "Re-set serial number\n"); 423 fprintf (stderr,
385 ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); 424 "\nError: Apparent chaining without changing serial number (%"
425 PRId64 "==%" PRId64 ").\n",
426 (int64_t) opus_serialno, (int64_t) os.serialno);
427 quit (1);
428 }
429 opus_serialno = os.serialno;
430 has_opus_stream = 1;
431 has_tags_packet = 0;
432 link_out = 0;
433 packet_count = 0;
434 eos = 0;
435 total_links++;
436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
437 "Got header for stream %" PRId64 ", this is %dth link\n",
438 (int64_t) opus_serialno, total_links);
386 } 439 }
387 /*Add page to the bitstream*/ 440 else
388 ogg_stream_pagein(&os, &og);
389 page_granule = ogg_page_granulepos(&og);
390 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
391 "Reading page that ends at %" PRId64 "\n",
392 page_granule);
393 /*Extract all available packets*/
394 while (1 == ogg_stream_packetout(&os, &op))
395 { 441 {
396 /*OggOpus streams are identified by a magic string in the initial 442 fprintf (stderr, "\nWarning: ignoring opus stream %" PRId64 "\n",
397 stream header.*/ 443 (int64_t) os.serialno);
398 if (op.b_o_s && op.bytes >= 8 && !memcmp(op.packet, "OpusHead", 8))
399 {
400 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
401 "Got Opus Header\n");
402 if (has_opus_stream && has_tags_packet)
403 {
404 /*If we're seeing another BOS OpusHead now it means
405 the stream is chained without an EOS.
406 This can easily happen if record helper is terminated unexpectedly.
407 */
408 has_opus_stream = 0;
409 if (dec)
410 opus_decoder_destroy(dec);
411 dec = NULL;
412 fprintf(stderr, "\nWarning: stream %" PRId64 " ended without EOS and a new stream began.\n", (int64_t)os.serialno);
413 }
414 if (!has_opus_stream)
415 {
416 if (packet_count > 0 && opus_serialno == os.serialno)
417 {
418 fprintf(stderr, "\nError: Apparent chaining without changing serial number (%" PRId64 "==%" PRId64 ").\n",
419 (int64_t)opus_serialno, (int64_t)os.serialno);
420 quit(1);
421 }
422 opus_serialno = os.serialno;
423 has_opus_stream = 1;
424 has_tags_packet = 0;
425 link_out = 0;
426 packet_count = 0;
427 eos = 0;
428 total_links++;
429 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
430 "Got header for stream %" PRId64 ", this is %dth link\n",
431 (int64_t)opus_serialno, total_links);
432 }
433 else
434 {
435 fprintf(stderr, "\nWarning: ignoring opus stream %" PRId64 "\n", (int64_t)os.serialno);
436 }
437 }
438 if (!has_opus_stream || os.serialno != opus_serialno)
439 {
440 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
441 "breaking out\n");
442 break;
443 }
444 /*If first packet in a logical stream, process the Opus header*/
445 if (0 == packet_count)
446 {
447 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
448 "Decoding header\n");
449 dec = process_header(&op);
450 if (!dec)
451 quit(1);
452
453 if (0 != ogg_stream_packetout(&os, &op) || 255 == og.header[og.header_len - 1])
454 {
455 /*The format specifies that the initial header and tags packets are on their
456 own pages. To aid implementors in discovering that their files are wrong
457 we reject them explicitly here. In some player designs files like this would
458 fail even without an explicit test.*/
459 fprintf(stderr, "Extra packets on initial header page. Invalid stream.\n");
460 quit(1);
461 }
462
463 /*Remember how many samples at the front we were told to skip
464 so that we can adjust the timestamp counting.*/
465 gran_offset = preskip;
466
467 if (!pcm_buffer)
468 {
469 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
470 "Allocating %u * %u * %u = %llu bytes of buffer space\n",
471 MAX_FRAME_SIZE,
472 channels,
473 (unsigned int)sizeof(float),
474 (unsigned long long)(MAX_FRAME_SIZE * channels * sizeof(float)));
475 pcm_buffer = pa_xmalloc(sizeof(float) * MAX_FRAME_SIZE * channels);
476 }
477 }
478 else if (1 == packet_count)
479 {
480 has_tags_packet = 1;
481 if (0 != ogg_stream_packetout(&os, &op) || 255 == og.header[og.header_len - 1])
482 {
483 fprintf(stderr, "Extra packets on initial tags page. Invalid stream.\n");
484 quit(1);
485 }
486 }
487 else
488 {
489 int ret;
490 int64_t maxout;
491 int64_t outsamp;
492
493 /*End of stream condition*/
494 if (op.e_o_s && os.serialno == opus_serialno)
495 {
496 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
497 "Got EOS\n");
498 eos = 1; /* don't care for anything except opus eos */
499 }
500
501 /*Decode Opus packet*/
502 ret = opus_decode_float(dec,
503 (const unsigned char *)op.packet,
504 op.bytes,
505 pcm_buffer,
506 MAX_FRAME_SIZE, 0);
507
508 /*If the decoder returned less than zero, we have an error.*/
509 if (0 > ret)
510 {
511 fprintf(stderr, "Decoding error: %s\n", opus_strerror(ret));
512 break;
513 }
514 frame_size = ret;
515 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
516 "Decoded %d bytes/channel (%d bytes) from %u compressed bytes\n",
517 ret,
518 ret * channels,
519 (unsigned int)op.bytes);
520
521 /*Apply header gain, if we're not using an opus library new
522 enough to do this internally.*/
523 if (0 != gain)
524 {
525 int i;
526 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
527 "Applying gain %f\n",
528 gain);
529 for (i = 0; i < frame_size * channels; i++)
530 pcm_buffer[i] *= gain;
531 }
532
533 /*This handles making sure that our output duration respects
534 the final end-trim by not letting the output sample count
535 get ahead of the granpos indicated value.*/
536 maxout = ((page_granule - gran_offset) * SAMPLING_RATE / 48000) - link_out;
537 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
538 "Writing audio packet %" PRId64 ", at most %" PRId64 " samples\n",
539 packet_count, maxout);
540
541 outsamp = audio_write(0 > maxout ? 0 : maxout);
542 link_out += outsamp;
543 }
544 packet_count++;
545 } 444 }
546 if (eos) 445 }
446 if (! has_opus_stream ||(os.serialno != opus_serialno) )
447 {
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "breaking out\n");
450 break;
451 }
452 /*If first packet in a logical stream, process the Opus header*/
453 if (0 == packet_count)
454 {
455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456 "Decoding header\n");
457 dec = process_header (&op);
458 if (! dec)
459 quit (1);
460
461 if ((0 != ogg_stream_packetout (&os, &op)) ||(255 ==
462 og.header[og.header_len
463 - 1]) )
547 { 464 {
548 has_opus_stream = 0; 465 /*The format specifies that the initial header and tags packets are on their
549 if (dec) 466 own pages. To aid implementors in discovering that their files are wrong
550 opus_decoder_destroy(dec); 467 we reject them explicitly here. In some player designs files like this would
551 dec = NULL; 468 fail even without an explicit test.*/
469 fprintf (stderr,
470 "Extra packets on initial header page. Invalid stream.\n");
471 quit (1);
472 }
473
474 /*Remember how many samples at the front we were told to skip
475 so that we can adjust the timestamp counting.*/
476 gran_offset = preskip;
477
478 if (! pcm_buffer)
479 {
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
481 "Allocating %u * %u * %u = %llu bytes of buffer space\n",
482 MAX_FRAME_SIZE,
483 channels,
484 (unsigned int) sizeof(float),
485 (unsigned long long) (MAX_FRAME_SIZE * channels
486 * sizeof(float)));
487 pcm_buffer = pa_xmalloc (sizeof(float) * MAX_FRAME_SIZE * channels);
488 }
489 }
490 else if (1 == packet_count)
491 {
492 has_tags_packet = 1;
493 if ((0 != ogg_stream_packetout (&os, &op)) ||(255 ==
494 og.header[og.header_len
495 - 1]) )
496 {
497 fprintf (stderr,
498 "Extra packets on initial tags page. Invalid stream.\n");
499 quit (1);
552 } 500 }
501 }
502 else
503 {
504 int ret;
505 int64_t maxout;
506 int64_t outsamp;
507
508 /*End of stream condition*/
509 if (op.e_o_s &&(os.serialno == opus_serialno) )
510 {
511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
512 "Got EOS\n");
513 eos = 1; /* don't care for anything except opus eos */
514 }
515
516 /*Decode Opus packet*/
517 ret = opus_decode_float (dec,
518 (const unsigned char *) op.packet,
519 op.bytes,
520 pcm_buffer,
521 MAX_FRAME_SIZE, 0);
522
523 /*If the decoder returned less than zero, we have an error.*/
524 if (0 > ret)
525 {
526 fprintf (stderr, "Decoding error: %s\n", opus_strerror (ret));
527 break;
528 }
529 frame_size = ret;
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531 "Decoded %d bytes/channel (%d bytes) from %u compressed bytes\n",
532 ret,
533 ret * channels,
534 (unsigned int) op.bytes);
535
536 /*Apply header gain, if we're not using an opus library new
537 enough to do this internally.*/
538 if (0 != gain)
539 {
540 int i;
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542 "Applying gain %f\n",
543 gain);
544 for (i = 0; i < frame_size * channels; i++)
545 pcm_buffer[i] *= gain;
546 }
547
548 /*This handles making sure that our output duration respects
549 the final end-trim by not letting the output sample count
550 get ahead of the granpos indicated value.*/
551 maxout = ((page_granule - gran_offset) * SAMPLING_RATE / 48000)
552 - link_out;
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554 "Writing audio packet %" PRId64 ", at most %" PRId64
555 " samples\n",
556 packet_count, maxout);
557
558 outsamp = audio_write (0 > maxout ? 0 : maxout);
559 link_out += outsamp;
560 }
561 packet_count++;
553 } 562 }
563 if (eos)
564 {
565 has_opus_stream = 0;
566 if (dec)
567 opus_decoder_destroy (dec);
568 dec = NULL;
569 }
570 }
554} 571}
555 572
556 573
@@ -563,32 +580,32 @@ ogg_demux_and_decode()
563 * #GNUNET_SYSERR to stop further processing due to error 580 * #GNUNET_SYSERR to stop further processing due to error
564 */ 581 */
565static int 582static int
566stdin_receiver(void *cls, 583stdin_receiver (void *cls,
567 const struct GNUNET_MessageHeader *msg) 584 const struct GNUNET_MessageHeader *msg)
568{ 585{
569 struct AudioMessage *audio; 586 struct AudioMessage *audio;
570 char *data; 587 char *data;
571 size_t payload_len; 588 size_t payload_len;
572 589
573 (void)cls; 590 (void) cls;
574 switch (ntohs(msg->type)) 591 switch (ntohs (msg->type))
575 { 592 {
576 case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO: 593 case GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO:
577 audio = (struct AudioMessage *)msg; 594 audio = (struct AudioMessage *) msg;
578 payload_len = ntohs(audio->header.size) - sizeof(struct AudioMessage); 595 payload_len = ntohs (audio->header.size) - sizeof(struct AudioMessage);
579 596
580 /*Get the ogg buffer for writing*/ 597 /*Get the ogg buffer for writing*/
581 data = ogg_sync_buffer(&oy, payload_len); 598 data = ogg_sync_buffer (&oy, payload_len);
582 /*Read bitstream from input file*/ 599 /*Read bitstream from input file*/
583 GNUNET_memcpy(data, (const unsigned char *)&audio[1], payload_len); 600 GNUNET_memcpy (data, (const unsigned char *) &audio[1], payload_len);
584 ogg_sync_wrote(&oy, payload_len); 601 ogg_sync_wrote (&oy, payload_len);
585 602
586 ogg_demux_and_decode(); 603 ogg_demux_and_decode ();
587 break; 604 break;
588 605
589 default: 606 default:
590 break; 607 break;
591 } 608 }
592 return GNUNET_OK; 609 return GNUNET_OK;
593} 610}
594 611
@@ -597,20 +614,20 @@ stdin_receiver(void *cls,
597 * Callback when data is there for playback 614 * Callback when data is there for playback
598 */ 615 */
599static void 616static void
600stream_write_callback(pa_stream *s, 617stream_write_callback (pa_stream *s,
601 size_t length, 618 size_t length,
602 void *userdata) 619 void *userdata)
603{ 620{
604 /* unblock 'main' */ 621 /* unblock 'main' */
605 (void)userdata; 622 (void) userdata;
606 (void)length; 623 (void) length;
607 (void)s; 624 (void) s;
608 if (-1 != ready_pipe[1]) 625 if (-1 != ready_pipe[1])
609 { 626 {
610 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611 "Unblocking main loop!\n"); 628 "Unblocking main loop!\n");
612 (void)write(ready_pipe[1], "r", 1); 629 (void) write (ready_pipe[1], "r", 1);
613 } 630 }
614} 631}
615 632
616 633
@@ -618,18 +635,18 @@ stream_write_callback(pa_stream *s,
618 * Exit callback for SIGTERM and SIGINT 635 * Exit callback for SIGTERM and SIGINT
619 */ 636 */
620static void 637static void
621exit_signal_callback(pa_mainloop_api *m, 638exit_signal_callback (pa_mainloop_api *m,
622 pa_signal_event *e, 639 pa_signal_event *e,
623 int sig, 640 int sig,
624 void *userdata) 641 void *userdata)
625{ 642{
626 (void)m; 643 (void) m;
627 (void)e; 644 (void) e;
628 (void)sig; 645 (void) sig;
629 (void)userdata; 646 (void) userdata;
630 GNUNET_log(GNUNET_ERROR_TYPE_INFO, 647 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
631 _("gnunet-helper-audio-playback - Got signal, exiting\n")); 648 _ ("gnunet-helper-audio-playback - Got signal, exiting\n"));
632 quit(1); 649 quit (1);
633} 650}
634 651
635 652
@@ -637,64 +654,66 @@ exit_signal_callback(pa_mainloop_api *m,
637 * Pulseaudio stream state callback 654 * Pulseaudio stream state callback
638 */ 655 */
639static void 656static void
640context_state_callback(pa_context *c, 657context_state_callback (pa_context *c,
641 void *userdata) 658 void *userdata)
642{ 659{
643 int p; 660 int p;
644 661
645 (void)userdata; 662 (void) userdata;
646 GNUNET_assert(NULL != c); 663 GNUNET_assert (NULL != c);
647 switch (pa_context_get_state(c)) 664 switch (pa_context_get_state (c))
648 { 665 {
649 case PA_CONTEXT_CONNECTING: 666 case PA_CONTEXT_CONNECTING:
650 case PA_CONTEXT_AUTHORIZING: 667 case PA_CONTEXT_AUTHORIZING:
651 case PA_CONTEXT_SETTING_NAME: 668 case PA_CONTEXT_SETTING_NAME:
652 break; 669 break;
653 670
654 case PA_CONTEXT_READY: 671 case PA_CONTEXT_READY:
655 { 672 {
656 GNUNET_assert(!stream_out); 673 GNUNET_assert (! stream_out);
657 GNUNET_log(GNUNET_ERROR_TYPE_INFO, 674 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
658 _("Connection established.\n")); 675 _ ("Connection established.\n"));
659 if (!(stream_out = 676 if (! (stream_out =
660 pa_stream_new(c, "GNUNET VoIP playback", &sample_spec, NULL))) 677 pa_stream_new (c, "GNUNET VoIP playback", &sample_spec, NULL)))
661 { 678 {
662 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 679 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663 _("pa_stream_new() failed: %s\n"), 680 _ ("pa_stream_new() failed: %s\n"),
664 pa_strerror(pa_context_errno(c))); 681 pa_strerror (pa_context_errno (c)));
665 goto fail; 682 goto fail;
666 } 683 }
667 pa_stream_set_write_callback(stream_out, 684 pa_stream_set_write_callback (stream_out,
668 &stream_write_callback, 685 &stream_write_callback,
669 NULL); 686 NULL);
670 if ((p = 687 if ((p =
671 pa_stream_connect_playback(stream_out, NULL, 688 pa_stream_connect_playback (stream_out, NULL,
672 NULL, 689 NULL,
673 PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, 690 PA_STREAM_ADJUST_LATENCY
674 NULL, NULL)) < 0) 691 | PA_STREAM_INTERPOLATE_TIMING
675 { 692 | PA_STREAM_AUTO_TIMING_UPDATE,
676 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 693 NULL, NULL)) < 0)
677 _("pa_stream_connect_playback() failed: %s\n"), 694 {
678 pa_strerror(pa_context_errno(c))); 695 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
679 goto fail; 696 _ ("pa_stream_connect_playback() failed: %s\n"),
680 } 697 pa_strerror (pa_context_errno (c)));
698 goto fail;
699 }
681 break; 700 break;
682 } 701 }
683 702
684 case PA_CONTEXT_TERMINATED: 703 case PA_CONTEXT_TERMINATED:
685 quit(0); 704 quit (0);
686 break; 705 break;
687 706
688 case PA_CONTEXT_FAILED: 707 case PA_CONTEXT_FAILED:
689 default: 708 default:
690 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 709 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 _("Connection failure: %s\n"), 710 _ ("Connection failure: %s\n"),
692 pa_strerror(pa_context_errno(c))); 711 pa_strerror (pa_context_errno (c)));
693 goto fail; 712 goto fail;
694 } 713 }
695 return; 714 return;
696fail: 715fail:
697 quit(1); 716 quit (1);
698} 717}
699 718
700 719
@@ -702,66 +721,66 @@ fail:
702 * Pulseaudio initialization 721 * Pulseaudio initialization
703 */ 722 */
704static void 723static void
705pa_init() 724pa_init ()
706{ 725{
707 int r; 726 int r;
708 727
709 if (!pa_sample_spec_valid(&sample_spec)) 728 if (! pa_sample_spec_valid (&sample_spec))
710 { 729 {
711 GNUNET_log(GNUNET_ERROR_TYPE_INFO, 730 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
712 _("Wrong Spec\n")); 731 _ ("Wrong Spec\n"));
713 } 732 }
714 /* set up threaded playback mainloop */ 733 /* set up threaded playback mainloop */
715 if (!(m = pa_threaded_mainloop_new())) 734 if (! (m = pa_threaded_mainloop_new ()))
716 { 735 {
717 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
718 _("pa_mainloop_new() failed.\n")); 737 _ ("pa_mainloop_new() failed.\n"));
719 } 738 }
720 mainloop_api = pa_threaded_mainloop_get_api(m); 739 mainloop_api = pa_threaded_mainloop_get_api (m);
721 /* listen to signals */ 740 /* listen to signals */
722 r = pa_signal_init(mainloop_api); 741 r = pa_signal_init (mainloop_api);
723 GNUNET_assert(r == 0); 742 GNUNET_assert (r == 0);
724 pa_signal_new(SIGINT, exit_signal_callback, NULL); 743 pa_signal_new (SIGINT, exit_signal_callback, NULL);
725 pa_signal_new(SIGTERM, exit_signal_callback, NULL); 744 pa_signal_new (SIGTERM, exit_signal_callback, NULL);
726 745
727 746
728 /* connect to the main pulseaudio context */ 747 /* connect to the main pulseaudio context */
729 if (!(context = pa_context_new(mainloop_api, "GNUnet VoIP"))) 748 if (! (context = pa_context_new (mainloop_api, "GNUnet VoIP")))
730 { 749 {
731 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 750 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
732 _("pa_context_new() failed.\n")); 751 _ ("pa_context_new() failed.\n"));
733 } 752 }
734 pa_context_set_state_callback(context, context_state_callback, NULL); 753 pa_context_set_state_callback (context, context_state_callback, NULL);
735 754
736 if (pa_context_connect(context, NULL, 0, NULL) < 0) 755 if (pa_context_connect (context, NULL, 0, NULL) < 0)
737 { 756 {
738 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
739 _("pa_context_connect() failed: %s\n"), 758 _ ("pa_context_connect() failed: %s\n"),
740 pa_strerror(pa_context_errno(context))); 759 pa_strerror (pa_context_errno (context)));
741 } 760 }
742 if (pa_threaded_mainloop_start(m) < 0) 761 if (pa_threaded_mainloop_start (m) < 0)
743 { 762 {
744 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
745 _("pa_mainloop_run() failed.\n")); 764 _ ("pa_mainloop_run() failed.\n"));
746 } 765 }
747} 766}
748 767
749 768
750static void 769static void
751ogg_init() 770ogg_init ()
752{ 771{
753 ogg_sync_init(&oy); 772 ogg_sync_init (&oy);
754} 773}
755 774
756 775
757static void 776static void
758drain_callback(pa_stream*s, int success, void *userdata) 777drain_callback (pa_stream*s, int success, void *userdata)
759{ 778{
760 (void)s; 779 (void) s;
761 (void)success; 780 (void) success;
762 (void)userdata; 781 (void) userdata;
763 pa_threaded_mainloop_signal(m, 782 pa_threaded_mainloop_signal (m,
764 0); 783 0);
765} 784}
766 785
767 786
@@ -773,7 +792,7 @@ drain_callback(pa_stream*s, int success, void *userdata)
773 * @return 0 ok, 1 on error 792 * @return 0 ok, 1 on error
774 */ 793 */
775int 794int
776main(int argc, char *argv[]) 795main (int argc, char *argv[])
777{ 796{
778 static unsigned long long toff; 797 static unsigned long long toff;
779 char readbuf[MAXLINE]; 798 char readbuf[MAXLINE];
@@ -782,87 +801,87 @@ main(int argc, char *argv[])
782 ssize_t ret; 801 ssize_t ret;
783 802
784#ifdef DEBUG_READ_PURE_OGG 803#ifdef DEBUG_READ_PURE_OGG
785 int read_pure_ogg = getenv("GNUNET_READ_PURE_OGG") ? 1 : 0; 804 int read_pure_ogg = getenv ("GNUNET_READ_PURE_OGG") ? 1 : 0;
786#endif 805#endif
787 806
788 (void)argc; 807 (void) argc;
789 (void)argv; 808 (void) argv;
790 GNUNET_assert(GNUNET_OK == 809 GNUNET_assert (GNUNET_OK ==
791 GNUNET_log_setup("gnunet-helper-audio-playback", 810 GNUNET_log_setup ("gnunet-helper-audio-playback",
792 "WARNING", 811 "WARNING",
793 NULL)); 812 NULL));
794 if (0 != pipe(ready_pipe)) 813 if (0 != pipe (ready_pipe))
795 { 814 {
796 GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "pipe"); 815 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
797 return 1; 816 return 1;
798 } 817 }
799 stdin_mst = GNUNET_MST_create(&stdin_receiver, NULL); 818 stdin_mst = GNUNET_MST_create (&stdin_receiver, NULL);
800 ogg_init(); 819 ogg_init ();
801 pa_init(); 820 pa_init ();
802 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803 "Waiting for PulseAudio to be ready.\n"); 822 "Waiting for PulseAudio to be ready.\n");
804 GNUNET_assert(1 == read(ready_pipe[0], &c, 1)); 823 GNUNET_assert (1 == read (ready_pipe[0], &c, 1));
805 close(ready_pipe[0]); 824 close (ready_pipe[0]);
806 close(ready_pipe[1]); 825 close (ready_pipe[1]);
807 ready_pipe[0] = -1; 826 ready_pipe[0] = -1;
808 ready_pipe[1] = -1; 827 ready_pipe[1] = -1;
809#ifdef DEBUG_DUMP_DECODED_OGG 828#ifdef DEBUG_DUMP_DECODED_OGG
810 dump_to_stdout = getenv("GNUNET_DUMP_DECODED_OGG") ? 1 : 0; 829 dump_to_stdout = getenv ("GNUNET_DUMP_DECODED_OGG") ? 1 : 0;
811#endif 830#endif
812 while (1) 831 while (1)
832 {
833 ret = read (STDIN_FILENO,
834 readbuf,
835 sizeof(readbuf));
836 toff += ret;
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838 "Received %d bytes of audio data (total: %llu)\n",
839 (int) ret,
840 toff);
841 if (0 > ret)
813 { 842 {
814 ret = read(STDIN_FILENO, 843 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
815 readbuf, 844 _ ("Read error from STDIN: %s\n"),
816 sizeof(readbuf)); 845 strerror (errno));
817 toff += ret; 846 break;
818 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 847 }
819 "Received %d bytes of audio data (total: %llu)\n", 848 if (0 == ret)
820 (int)ret, 849 break;
821 toff);
822 if (0 > ret)
823 {
824 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
825 _("Read error from STDIN: %s\n"),
826 strerror(errno));
827 break;
828 }
829 if (0 == ret)
830 break;
831#ifdef DEBUG_READ_PURE_OGG 850#ifdef DEBUG_READ_PURE_OGG
832 if (read_pure_ogg) 851 if (read_pure_ogg)
833 { 852 {
834 char *data = ogg_sync_buffer(&oy, ret); 853 char *data = ogg_sync_buffer (&oy, ret);
835 GNUNET_memcpy(data, readbuf, ret); 854 GNUNET_memcpy (data, readbuf, ret);
836 ogg_sync_wrote(&oy, ret); 855 ogg_sync_wrote (&oy, ret);
837 ogg_demux_and_decode(); 856 ogg_demux_and_decode ();
838 }
839 else
840#endif
841 GNUNET_MST_from_buffer(stdin_mst,
842 readbuf, ret,
843 GNUNET_NO, GNUNET_NO);
844 } 857 }
845 GNUNET_MST_destroy(stdin_mst); 858 else
859#endif
860 GNUNET_MST_from_buffer (stdin_mst,
861 readbuf, ret,
862 GNUNET_NO, GNUNET_NO);
863 }
864 GNUNET_MST_destroy (stdin_mst);
846 if (stream_out) 865 if (stream_out)
866 {
867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868 "Locking\n");
869 pa_threaded_mainloop_lock (m);
870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871 "Draining\n");
872 pa_operation *o = pa_stream_drain (stream_out, drain_callback, NULL);
873 while (pa_operation_get_state (o) == PA_OPERATION_RUNNING)
847 { 874 {
848 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "Locking\n"); 876 "Waiting\n");
850 pa_threaded_mainloop_lock(m); 877 pa_threaded_mainloop_wait (m);
851 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
852 "Draining\n");
853 pa_operation *o = pa_stream_drain(stream_out, drain_callback, NULL);
854 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
855 {
856 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
857 "Waiting\n");
858 pa_threaded_mainloop_wait(m);
859 }
860 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
861 "Unreffing\n");
862 pa_operation_unref(o);
863 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
864 "Unlocking\n");
865 pa_threaded_mainloop_unlock(m);
866 } 878 }
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Unreffing\n");
881 pa_operation_unref (o);
882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
883 "Unlocking\n");
884 pa_threaded_mainloop_unlock (m);
885 }
867 return 0; 886 return 0;
868} 887}