GNUnet 0.22.2
gnunet-helper-audio-playback.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "conversation.h"
31#include "gnunet_constants.h"
32#include "gnunet_core_service.h"
33
34#include <pulse/simple.h>
35#include <pulse/error.h>
36#include <pulse/rtclock.h>
37
38#include <pulse/pulseaudio.h>
39#include <opus/opus.h>
40#include <opus/opus_types.h>
41#include <ogg/ogg.h>
42
43#define DEBUG_READ_PURE_OGG 1
44#define DEBUG_DUMP_DECODED_OGG 1
45
46#define MAXLINE 4096
47
48#define SAMPLING_RATE 48000
49
50#define CHANNELS 1
51
52/* 120ms at 48000 */
53#define MAX_FRAME_SIZE (960 * 6)
54
58static pa_sample_spec sample_spec = {
59 .format = PA_SAMPLE_FLOAT32LE,
60 .rate = SAMPLING_RATE,
61 .channels = CHANNELS
62};
63
64#ifdef DEBUG_DUMP_DECODED_OGG
65static int dump_to_stdout;
66#endif
67
71static pa_mainloop_api *mainloop_api;
72
76static pa_threaded_mainloop *m;
77
81static pa_context *context;
82
86static pa_stream *stream_out;
87
91static OpusDecoder *dec;
92
96static float *pcm_buffer;
97
101static int frame_size;
102
106static int ready_pipe[2];
107
111static ogg_sync_state oy;
112
116static ogg_stream_state os;
117
118static int channels;
119
120static int preskip;
121
122static float gain;
123
125
126/* OggOpus spec says the numbers must be in little-endian order */
128{
129 uint8_t magic[8];
130 uint8_t version;
131 uint8_t channels;
136};
137
139
145static OpusDecoder *
146process_header (ogg_packet *op)
147{
148 int err;
149 OpusDecoder *dec;
150 struct OpusHeadPacket header;
151
152 if (((unsigned int) op->bytes) < sizeof(header))
153 return NULL;
154 GNUNET_memcpy (&header,
155 op->packet,
156 sizeof(header));
157 header.preskip = GNUNET_le16toh (header.preskip);
159 header.gain = GNUNET_le16toh (header.gain);
160
162 "Header: v%u, %u-ch, skip %u, %uHz, %u gain\n",
163 header.version,
164 header.channels,
165 header.preskip,
166 header.sampling_rate,
167 header.gain);
168 channels = header.channels;
169 preskip = header.preskip;
170
171 if (header.channel_mapping != 0)
172 {
173 fprintf (stderr,
174 "This implementation does not support non-mono streams\n");
175 return NULL;
176 }
177
178 dec = opus_decoder_create (SAMPLING_RATE, channels, &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)
202 {
203 gain = pow (10.0, gainadj / 5120.0);
204 }
205 else if (OPUS_OK != err)
206 {
207 fprintf (stderr, "Error setting gain: %s\n", opus_strerror (err));
208 return NULL;
209 }
210 }
211
212 return dec;
213}
214
215
216#ifdef DEBUG_DUMP_DECODED_OGG
217static size_t
218fwrite_le32 (opus_int32 i32, FILE *file)
219{
220 unsigned char buf[4];
221
222 buf[0] = (unsigned char) (i32 & 0xFF);
223 buf[1] = (unsigned char) (i32 >> 8 & 0xFF);
224 buf[2] = (unsigned char) (i32 >> 16 & 0xFF);
225 buf[3] = (unsigned char) (i32 >> 24 & 0xFF);
226 return fwrite (buf, 4, 1, file);
227}
228
229
230static size_t
231fwrite_le16 (int i16, FILE *file)
232{
233 unsigned char buf[2];
234
235 buf[0] = (unsigned char) (i16 & 0xFF);
236 buf[1] = (unsigned char) (i16 >> 8 & 0xFF);
237 return fwrite (buf, 2, 1, file);
238}
239
240
241static int
243{
244 int ret;
245 FILE *file = stdout;
246
247 ret = fprintf (file, "RIFF") >= 0;
248 ret &= fwrite_le32 (0x7fffffff, file);
249
250 ret &= fprintf (file, "WAVEfmt ") >= 0;
251 ret &= fwrite_le32 (16, file);
252 ret &= fwrite_le16 (1, file);
253 ret &= fwrite_le16 (channels, file);
254 ret &= fwrite_le32 (SAMPLING_RATE, file);
255 ret &= fwrite_le32 (2 * channels * SAMPLING_RATE, file);
256 ret &= fwrite_le16 (2 * channels, file);
257 ret &= fwrite_le16 (16, file);
258
259 ret &= fprintf (file, "data") >= 0;
260 ret &= fwrite_le32 (0x7fffffff, file);
261
262 return ! ret ? -1 : 16;
263}
264
265
266#endif
267
268
269static int64_t
270audio_write (int64_t maxout)
271{
272 int64_t sampout = 0;
273 int tmp_skip;
274 unsigned out_len;
275 unsigned to_write;
276 float *output;
277
278#ifdef DEBUG_DUMP_DECODED_OGG
279 static int wrote_wav_header;
280
281 if (dump_to_stdout && ! wrote_wav_header)
282 {
284 wrote_wav_header = 1;
285 }
286#endif
287 maxout = 0 > maxout ? 0 : maxout;
288 do
289 {
290 tmp_skip = (preskip > frame_size) ? (int) frame_size : preskip;
291 preskip -= tmp_skip;
292 output = pcm_buffer + channels * tmp_skip;
293 out_len = frame_size - tmp_skip;
294 if (out_len > MAX_FRAME_SIZE)
295 exit (6);
296 frame_size = 0;
297
298 to_write = out_len < maxout ? out_len : (unsigned) maxout;
299 if (0 < maxout)
300 {
301 int64_t wrote = 0;
302 wrote = to_write;
304 "Writing %u * %u * %u = %llu bytes into PA\n",
305 to_write,
306 channels,
307 (unsigned int) sizeof(float),
308 (unsigned long long) (to_write * channels * sizeof(float)));
309#ifdef DEBUG_DUMP_DECODED_OGG
310 if (dump_to_stdout)
311 {
312# define fminf(_x, _y) ((_x) < (_y) ? (_x) : (_y))
313# define fmaxf(_x, _y) ((_x) > (_y) ? (_x) : (_y))
314# define float2int(flt) ((int) (floor (.5 + flt)))
315 int i;
316 int16_t *out = alloca (sizeof(short) * MAX_FRAME_SIZE * channels);
317 for (i = 0; i < (int) out_len * channels; i++)
318 out[i] = (short) float2int (fmaxf (-32768, fminf (output[i] * 32768.f,
319 32767)));
320
321 fwrite (out, 2 * channels, out_len < maxout ? out_len : maxout, stdout);
322 }
323 else
324#endif
325 if (pa_stream_write
326 (stream_out, output, to_write * channels * sizeof(float), NULL, 0,
327 PA_SEEK_RELATIVE) < 0)
328 {
330 _ ("pa_stream_write() failed: %s\n"),
331 pa_strerror (pa_context_errno (context)));
332 }
333 sampout += wrote;
334 maxout -= wrote;
335 }
336 }
337 while (0 < frame_size && 0 < maxout);
338
340 "Wrote %" PRId64 " samples\n",
341 sampout);
342 return sampout;
343}
344
345
349static void
351{
353 ret);
354 exit (ret);
355}
356
357
358static void
360{
361 ogg_page og;
362 static int stream_init;
363 int64_t page_granule = 0;
364 ogg_packet op;
365 static int has_opus_stream;
366 static int has_tags_packet;
367 static int32_t opus_serialno;
368 static int64_t link_out;
369 static int64_t packet_count;
370 int eos = 0;
371 static int total_links;
372 static int gran_offset;
373
374 while (1 == ogg_sync_pageout (&oy, &og))
375 {
376 if (0 == stream_init)
377 {
379 "Initialized the stream\n");
380 ogg_stream_init (&os, ogg_page_serialno (&og));
381 stream_init = 1;
382 }
383 if (ogg_page_serialno (&og) != os.serialno)
384 {
385 /* so all streams are read. */
387 "Re-set serial number\n");
388 ogg_stream_reset_serialno (&os, ogg_page_serialno (&og));
389 }
390 /*Add page to the bitstream*/
391 ogg_stream_pagein (&os, &og);
392 page_granule = ogg_page_granulepos (&og);
394 "Reading page that ends at %" PRId64 "\n",
395 page_granule);
396 /*Extract all available packets*/
397 while (1 == ogg_stream_packetout (&os, &op))
398 {
399 /*OggOpus streams are identified by a magic string in the initial
400 stream header.*/
401 if (op.b_o_s && (op.bytes >= 8) && ! memcmp (op.packet, "OpusHead", 8))
402 {
404 "Got Opus Header\n");
405 if (has_opus_stream && has_tags_packet)
406 {
407 /*If we're seeing another BOS OpusHead now it means
408 the stream is chained without an EOS.
409 This can easily happen if record helper is terminated unexpectedly.
410 */
411 has_opus_stream = 0;
412 if (dec)
413 opus_decoder_destroy (dec);
414 dec = NULL;
415 fprintf (stderr,
416 "\nWarning: stream %" PRId64
417 " ended without EOS and a new stream began.\n",
418 (int64_t) os.serialno);
419 }
420 if (! has_opus_stream)
421 {
422 if ((packet_count > 0) && (opus_serialno == os.serialno) )
423 {
424 fprintf (stderr,
425 "\nError: Apparent chaining without changing serial number (%"
426 PRId64 "==%" PRId64 ").\n",
427 (int64_t) opus_serialno, (int64_t) os.serialno);
428 quit (1);
429 }
430 opus_serialno = os.serialno;
431 has_opus_stream = 1;
432 has_tags_packet = 0;
433 link_out = 0;
434 packet_count = 0;
435 eos = 0;
436 total_links++;
438 "Got header for stream %" PRId64 ", this is %dth link\n",
439 (int64_t) opus_serialno, total_links);
440 }
441 else
442 {
443 fprintf (stderr, "\nWarning: ignoring opus stream %" PRId64 "\n",
444 (int64_t) os.serialno);
445 }
446 }
447 if (! has_opus_stream || (os.serialno != opus_serialno) )
448 {
450 "breaking out\n");
451 break;
452 }
453 /*If first packet in a logical stream, process the Opus header*/
454 if (0 == packet_count)
455 {
457 "Decoding header\n");
458 dec = process_header (&op);
459 if (! dec)
460 quit (1);
461
462 if ((0 != ogg_stream_packetout (&os, &op)) || (255 ==
463 og.header[og.header_len
464 - 1]) )
465 {
466 /*The format specifies that the initial header and tags packets are on their
467 own pages. To aid implementors in discovering that their files are wrong
468 we reject them explicitly here. In some player designs files like this would
469 fail even without an explicit test.*/
470 fprintf (stderr,
471 "Extra packets on initial header page. Invalid stream.\n");
472 quit (1);
473 }
474
475 /*Remember how many samples at the front we were told to skip
476 so that we can adjust the timestamp counting.*/
477 gran_offset = preskip;
478
479 if (! pcm_buffer)
480 {
482 "Allocating %u * %u * %u = %llu bytes of buffer space\n",
484 channels,
485 (unsigned int) sizeof(float),
486 (unsigned long long) (MAX_FRAME_SIZE * channels
487 * sizeof(float)));
488 pcm_buffer = pa_xmalloc (sizeof(float) * MAX_FRAME_SIZE * channels);
489 }
490 }
491 else if (1 == packet_count)
492 {
493 has_tags_packet = 1;
494 if ((0 != ogg_stream_packetout (&os, &op)) || (255 ==
495 og.header[og.header_len
496 - 1]) )
497 {
498 fprintf (stderr,
499 "Extra packets on initial tags page. Invalid stream.\n");
500 quit (1);
501 }
502 }
503 else
504 {
505 int ret;
506 int64_t maxout;
507 int64_t outsamp;
508
509 /*End of stream condition*/
510 if (op.e_o_s && (os.serialno == opus_serialno) )
511 {
513 "Got EOS\n");
514 eos = 1; /* don't care for anything except opus eos */
515 }
516
517 /*Decode Opus packet*/
518 ret = opus_decode_float (dec,
519 (const unsigned char *) op.packet,
520 op.bytes,
522 MAX_FRAME_SIZE, 0);
523
524 /*If the decoder returned less than zero, we have an error.*/
525 if (0 > ret)
526 {
527 fprintf (stderr, "Decoding error: %s\n", opus_strerror (ret));
528 break;
529 }
530 frame_size = ret;
532 "Decoded %d bytes/channel (%d bytes) from %u compressed bytes\n",
533 ret,
534 ret * channels,
535 (unsigned int) op.bytes);
536
537 /*Apply header gain, if we're not using an opus library new
538 enough to do this internally.*/
539 if (0 != gain)
540 {
541 int i;
543 "Applying gain %f\n",
544 gain);
545 for (i = 0; i < frame_size * channels; i++)
546 pcm_buffer[i] *= gain;
547 }
548
549 /*This handles making sure that our output duration respects
550 the final end-trim by not letting the output sample count
551 get ahead of the granpos indicated value.*/
552 maxout = ((page_granule - gran_offset) * SAMPLING_RATE / 48000)
553 - link_out;
555 "Writing audio packet %" PRId64 ", at most %" PRId64
556 " samples\n",
557 packet_count, maxout);
558
559 outsamp = audio_write (0 > maxout ? 0 : maxout);
560 link_out += outsamp;
561 }
562 packet_count++;
563 }
564 if (eos)
565 {
566 has_opus_stream = 0;
567 if (dec)
568 opus_decoder_destroy (dec);
569 dec = NULL;
570 }
571 }
572}
573
574
583static int
584stdin_receiver (void *cls,
585 const struct GNUNET_MessageHeader *msg)
586{
587 struct AudioMessage *audio;
588 char *data;
589 size_t payload_len;
590
591 (void) cls;
592 switch (ntohs (msg->type))
593 {
595 audio = (struct AudioMessage *) msg;
596 payload_len = ntohs (audio->header.size) - sizeof(struct AudioMessage);
597
598 /*Get the ogg buffer for writing*/
599 data = ogg_sync_buffer (&oy, payload_len);
600 /*Read bitstream from input file*/
601 GNUNET_memcpy (data, (const unsigned char *) &audio[1], payload_len);
602 ogg_sync_wrote (&oy, payload_len);
603
605 break;
606
607 default:
608 break;
609 }
610 return GNUNET_OK;
611}
612
613
617static void
619 size_t length,
620 void *userdata)
621{
622 /* unblock 'main' */
623 (void) userdata;
624 (void) length;
625 (void) s;
626 if (-1 != ready_pipe[1])
627 {
629 "Unblocking main loop!\n");
630 (void) write (ready_pipe[1], "r", 1);
631 }
632}
633
634
638static void
639exit_signal_callback (pa_mainloop_api *m,
640 pa_signal_event *e,
641 int sig,
642 void *userdata)
643{
644 (void) m;
645 (void) e;
646 (void) sig;
647 (void) userdata;
649 _ ("gnunet-helper-audio-playback - Got signal, exiting\n"));
650 quit (1);
651}
652
653
657static void
659 void *userdata)
660{
661 int p;
662
663 (void) userdata;
664 GNUNET_assert (NULL != c);
665 switch (pa_context_get_state (c))
666 {
667 case PA_CONTEXT_CONNECTING:
668 case PA_CONTEXT_AUTHORIZING:
669 case PA_CONTEXT_SETTING_NAME:
670 break;
671
672 case PA_CONTEXT_READY:
673 {
676 _ ("Connection established.\n"));
677 if (! (stream_out =
678 pa_stream_new (c, "GNUNET VoIP playback", &sample_spec, NULL)))
679 {
681 _ ("pa_stream_new() failed: %s\n"),
682 pa_strerror (pa_context_errno (c)));
683 goto fail;
684 }
685 pa_stream_set_write_callback (stream_out,
687 NULL);
688 if ((p =
689 pa_stream_connect_playback (stream_out, NULL,
690 NULL,
691 PA_STREAM_ADJUST_LATENCY
692 | PA_STREAM_INTERPOLATE_TIMING
693 | PA_STREAM_AUTO_TIMING_UPDATE,
694 NULL, NULL)) < 0)
695 {
697 _ ("pa_stream_connect_playback() failed: %s\n"),
698 pa_strerror (pa_context_errno (c)));
699 goto fail;
700 }
701 break;
702 }
703
704 case PA_CONTEXT_TERMINATED:
705 quit (0);
706 break;
707
708 case PA_CONTEXT_FAILED:
709 default:
711 _ ("Connection failure: %s\n"),
712 pa_strerror (pa_context_errno (c)));
713 goto fail;
714 }
715 return;
716fail:
717 quit (1);
718}
719
720
724static void
726{
727 int r;
728
729 if (! pa_sample_spec_valid (&sample_spec))
730 {
732 _ ("Wrong Spec\n"));
733 }
734 /* set up threaded playback mainloop */
735 if (! (m = pa_threaded_mainloop_new ()))
736 {
738 _ ("pa_mainloop_new() failed.\n"));
739 }
740 mainloop_api = pa_threaded_mainloop_get_api (m);
741 /* listen to signals */
742 r = pa_signal_init (mainloop_api);
743 GNUNET_assert (r == 0);
744 pa_signal_new (SIGINT, exit_signal_callback, NULL);
745 pa_signal_new (SIGTERM, exit_signal_callback, NULL);
746
747
748 /* connect to the main pulseaudio context */
749 if (! (context = pa_context_new (mainloop_api, "GNUnet VoIP")))
750 {
752 _ ("pa_context_new() failed.\n"));
753 }
754 pa_context_set_state_callback (context, context_state_callback, NULL);
755
756 if (pa_context_connect (context, NULL, 0, NULL) < 0)
757 {
759 _ ("pa_context_connect() failed: %s\n"),
760 pa_strerror (pa_context_errno (context)));
761 }
762 if (pa_threaded_mainloop_start (m) < 0)
763 {
765 _ ("pa_mainloop_run() failed.\n"));
766 }
767}
768
769
770static void
772{
773 ogg_sync_init (&oy);
774}
775
776
777static void
778drain_callback (pa_stream*s, int success, void *userdata)
779{
780 (void) s;
781 (void) success;
782 (void) userdata;
783 pa_threaded_mainloop_signal (m,
784 0);
785}
786
787
795int
796main (int argc, char *argv[])
797{
798 static unsigned long long toff;
799 char readbuf[MAXLINE];
801 char c;
802 ssize_t ret;
803
804#ifdef DEBUG_READ_PURE_OGG
805 int read_pure_ogg = getenv ("GNUNET_READ_PURE_OGG") ? 1 : 0;
806#endif
807
808 (void) argc;
809 (void) argv;
811 GNUNET_log_setup ("gnunet-helper-audio-playback",
812 "WARNING",
813 NULL));
814 if (0 != pipe (ready_pipe))
815 {
817 return 1;
818 }
820 ogg_init ();
821 pa_init ();
823 "Waiting for PulseAudio to be ready.\n");
824 GNUNET_assert (1 == read (ready_pipe[0], &c, 1));
825 close (ready_pipe[0]);
826 close (ready_pipe[1]);
827 ready_pipe[0] = -1;
828 ready_pipe[1] = -1;
829#ifdef DEBUG_DUMP_DECODED_OGG
830 dump_to_stdout = getenv ("GNUNET_DUMP_DECODED_OGG") ? 1 : 0;
831#endif
832 while (1)
833 {
834 ret = read (STDIN_FILENO,
835 readbuf,
836 sizeof(readbuf));
837 toff += ret;
839 "Received %d bytes of audio data (total: %llu)\n",
840 (int) ret,
841 toff);
842 if (0 > ret)
843 {
845 _ ("Read error from STDIN: %s\n"),
846 strerror (errno));
847 break;
848 }
849 if (0 == ret)
850 break;
851#ifdef DEBUG_READ_PURE_OGG
852 if (read_pure_ogg)
853 {
854 char *data = ogg_sync_buffer (&oy, ret);
855 GNUNET_memcpy (data, readbuf, ret);
856 ogg_sync_wrote (&oy, ret);
858 }
859 else
860#endif
862 readbuf, ret,
864 }
866 if (stream_out)
867 {
869 "Locking\n");
870 pa_threaded_mainloop_lock (m);
872 "Draining\n");
873 pa_operation *o = pa_stream_drain (stream_out, drain_callback, NULL);
874 while (pa_operation_get_state (o) == PA_OPERATION_RUNNING)
875 {
877 "Waiting\n");
878 pa_threaded_mainloop_wait (m);
879 }
881 "Unreffing\n");
882 pa_operation_unref (o);
884 "Unlocking\n");
885 pa_threaded_mainloop_unlock (m);
886 }
887 return 0;
888}
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
constants for network protocols
char * getenv()
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:143
static int ret
Final status code.
Definition: gnunet-arm.c:93
static char * data
The data to insert into the dht.
struct GNUNET_MessageStreamTokenizer * stdin_mst
Tokenizer for the data we get from stdin.
static int write_wav_header()
int main(int argc, char *argv[])
The main function for the playback helper.
static GNUNET_NETWORK_STRUCT_END OpusDecoder * process_header(ogg_packet *op)
Process an Opus header and setup the opus decoder based on it.
#define fminf(_x, _y)
static int channels
#define SAMPLING_RATE
#define CHANNELS
static void quit(int ret)
Pulseaudio shutdown task.
static pa_context * context
Pulseaudio context.
static pa_mainloop_api * mainloop_api
Pulseaudio mainloop api.
static void drain_callback(pa_stream *s, int success, void *userdata)
static int ready_pipe[2]
Pipe we use to signal the main loop that we are ready to receive.
static OpusDecoder * dec
OPUS decoder.
#define MAXLINE
static void pa_init()
Pulseaudio initialization.
static void stream_write_callback(pa_stream *s, size_t length, void *userdata)
Callback when data is there for playback.
static float * pcm_buffer
PCM data buffer.
static void ogg_init()
#define float2int(flt)
static int preskip
static int stdin_receiver(void *cls, const struct GNUNET_MessageHeader *msg)
Message callback.
static size_t fwrite_le32(opus_int32 i32, FILE *file)
static pa_threaded_mainloop * m
Pulseaudio threaded mainloop.
#define fmaxf(_x, _y)
static void context_state_callback(pa_context *c, void *userdata)
Pulseaudio stream state callback.
static ogg_sync_state oy
Ogg I/O state.
static size_t fwrite_le16(int i16, FILE *file)
static int64_t audio_write(int64_t maxout)
static pa_sample_spec sample_spec
Pulseaudio specification.
static void ogg_demux_and_decode()
static int dump_to_stdout
static float gain
static pa_stream * stream_out
Pulseaudio output stream.
#define MAX_FRAME_SIZE
static int frame_size
Number of samples for one frame.
static ogg_stream_state os
Ogg stream state.
static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata)
Exit callback for SIGTERM and SIGINT.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
Core service; the main API for encrypted P2P communications.
Constants for network protocols.
#define GNUNET_NETWORK_STRUCT_BEGIN
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_le32toh(x)
#define GNUNET_le16toh(x)
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32;.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
#define GNUNET_PACKED
gcc-ism to get packed structs.
@ GNUNET_OK
@ GNUNET_NO
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
enum GNUNET_GenericReturnValue GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO
Message to transmit the audio between helper and speaker/microphone library.
enum GNUNET_GenericReturnValue GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition: mst.c:101
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:86
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:404
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
Message to transmit the audio (between client and helpers).
Definition: conversation.h:59
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO.
Definition: conversation.h:63
Header for all communications.
Handle to a message stream tokenizer.
Definition: mst.c:45