GNUnet  0.20.0
gnunet-helper-audio-record.c File Reference

program to record audio data from the microphone More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_protocols.h"
#include "conversation.h"
#include "gnunet_constants.h"
#include "gnunet_core_service.h"
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/rtclock.h>
#include <pulse/pulseaudio.h>
#include <opus/opus.h>
#include <opus/opus_types.h>
#include <ogg/ogg.h>
Include dependency graph for gnunet-helper-audio-record.c:

Go to the source code of this file.

Data Structures

struct  OpusHeadPacket
 
struct  OpusCommentsPacket
 

Macros

#define DEBUG_RECORD_PURE_OGG   1
 
#define SAMPLING_RATE   48000
 Sampling rate. More...
 
#define FRAME_SIZE_MS   40
 How many ms of audio to buffer before encoding them. More...
 
#define FRAME_SIZE   (SAMPLING_RATE / 1000 * FRAME_SIZE_MS)
 How many samples to buffer before encoding them. More...
 
#define PAGE_WATERLINE   800
 Pages are committed when their size goes over this value. More...
 
#define MAX_PAYLOAD_BYTES   1024
 Maximum length of opus payload. More...
 
#define CHANNELS   1
 Number of channels. More...
 
#define CONV_OPUS_PACKET_LOSS_PERCENTAGE   1
 Configures the encoder's expected packet loss percentage. More...
 
#define CONV_OPUS_ENCODING_COMPLEXITY   10
 Configures the encoder's computational complexity. More...
 
#define CONV_OPUS_INBAND_FEC   1
 Configures the encoder's use of inband forward error correction (FEC). More...
 
#define CONV_OPUS_SIGNAL   OPUS_SIGNAL_VOICE
 Configures the type of signal being encoded. More...
 
#define CONV_OPUS_APP_TYPE   OPUS_APPLICATION_VOIP
 Coding mode. More...
 

Functions

static void quit (int ret)
 Pulseaudio shutdown task. More...
 
static void write_data (const char *ptr, size_t msg_size)
 
static void write_page (ogg_page *og)
 
static void packetizer ()
 Creates OPUS packets from PCM data. More...
 
static void stream_read_callback (pa_stream *s, size_t length, void *userdata)
 Pulseaudio callback when new data is available. More...
 
static void exit_signal_callback (pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata)
 Exit callback for SIGTERM and SIGINT. More...
 
static void stream_state_callback (pa_stream *s, void *userdata)
 Pulseaudio stream state callback. More...
 
static void context_state_callback (pa_context *c, void *userdata)
 Pulseaudio context state callback. More...
 
static void pa_init ()
 Pulsaudio init. More...
 
static void opus_init ()
 OPUS init. More...
 
static void ogg_init ()
 
int main (int argc, char *argv[])
 The main function for the record helper. More...
 

Variables

static pa_sample_spec sample_spec
 Specification for recording. More...
 
static GNUNET_NETWORK_STRUCT_END pa_mainloop_api * mainloop_api
 Pulseaudio mainloop api. More...
 
static pa_mainloop * m
 Pulseaudio mainloop. More...
 
static pa_context * context
 Pulseaudio context. More...
 
static pa_stream * stream_in
 Pulseaudio recording stream. More...
 
static pa_io_event * stdio_event
 Pulseaudio io events. More...
 
static OpusEncoder * enc
 OPUS encoder. More...
 
static unsigned char * opus_data
 Buffer for encoded data. More...
 
static float * pcm_buffer
 PCM data buffer for one OPUS frame. More...
 
static int pcm_length
 Length of the pcm data needed for one OPUS frame. More...
 
static char * transmit_buffer
 Audio buffer. More...
 
static size_t transmit_buffer_length
 Length of audio buffer. More...
 
static size_t transmit_buffer_index
 Read index for transmit buffer. More...
 
static struct AudioMessageaudio_message
 Audio message skeleton. More...
 
static ogg_stream_state os
 Ogg muxer state. More...
 
static int32_t packet_id
 Ogg packet id. More...
 
static int64_t enc_granulepos
 Ogg granule for current packet. More...
 
static int dump_pure_ogg
 1 to not to write GNUnet message headers, producing pure playable ogg output More...
 

Detailed Description

program to record audio data from the microphone

Author
Siomon Dieterle
Andreas Fuchs
Christian Grothoff

Definition in file gnunet-helper-audio-record.c.

Macro Definition Documentation

◆ DEBUG_RECORD_PURE_OGG

#define DEBUG_RECORD_PURE_OGG   1

Definition at line 43 of file gnunet-helper-audio-record.c.

◆ SAMPLING_RATE

#define SAMPLING_RATE   48000

Sampling rate.

Definition at line 48 of file gnunet-helper-audio-record.c.

◆ FRAME_SIZE_MS

#define FRAME_SIZE_MS   40

How many ms of audio to buffer before encoding them.

Possible values: 60, 40, 20, 10, 5, 2.5

Definition at line 55 of file gnunet-helper-audio-record.c.

◆ FRAME_SIZE

#define FRAME_SIZE   (SAMPLING_RATE / 1000 * FRAME_SIZE_MS)

How many samples to buffer before encoding them.

Definition at line 60 of file gnunet-helper-audio-record.c.

◆ PAGE_WATERLINE

#define PAGE_WATERLINE   800

Pages are committed when their size goes over this value.

Note that in practice we flush pages VERY often (every frame), which means that pages NEVER really get to be this big. With one-packet-per-page, pages are roughly 100-300 bytes each.

This value is chosen to make MAX_PAYLOAD_BYTES=1024 fit into a single page.

Definition at line 71 of file gnunet-helper-audio-record.c.

◆ MAX_PAYLOAD_BYTES

#define MAX_PAYLOAD_BYTES   1024

Maximum length of opus payload.

Definition at line 76 of file gnunet-helper-audio-record.c.

◆ CHANNELS

#define CHANNELS   1

Number of channels.

Definition at line 81 of file gnunet-helper-audio-record.c.

◆ CONV_OPUS_PACKET_LOSS_PERCENTAGE

#define CONV_OPUS_PACKET_LOSS_PERCENTAGE   1

Configures the encoder's expected packet loss percentage.

Higher values will trigger progressively more loss resistant behavior in the encoder at the expense of quality at a given bitrate in the lossless case, but greater quality under loss.

Definition at line 90 of file gnunet-helper-audio-record.c.

◆ CONV_OPUS_ENCODING_COMPLEXITY

#define CONV_OPUS_ENCODING_COMPLEXITY   10

Configures the encoder's computational complexity.

The supported range is 0-10 inclusive with 10 representing the highest complexity.

Definition at line 98 of file gnunet-helper-audio-record.c.

◆ CONV_OPUS_INBAND_FEC

#define CONV_OPUS_INBAND_FEC   1

Configures the encoder's use of inband forward error correction (FEC).

Note: This is only applicable to the LPC layer.

Definition at line 105 of file gnunet-helper-audio-record.c.

◆ CONV_OPUS_SIGNAL

#define CONV_OPUS_SIGNAL   OPUS_SIGNAL_VOICE

Configures the type of signal being encoded.

This is a hint which helps the encoder's mode selection.

Possible values: OPUS_AUTO - (default) Encoder detects the type automatically. OPUS_SIGNAL_VOICE - Bias thresholds towards choosing LPC or Hybrid modes. OPUS_SIGNAL_MUSIC - Bias thresholds towards choosing MDCT modes.

Definition at line 117 of file gnunet-helper-audio-record.c.

◆ CONV_OPUS_APP_TYPE

#define CONV_OPUS_APP_TYPE   OPUS_APPLICATION_VOIP

Coding mode.

Possible values: OPUS_APPLICATION_VOIP - gives best quality at a given bitrate for voice signals. It enhances the input signal by high-pass filtering and emphasizing formants and harmonics. Optionally it includes in-band forward error correction to protect against packet loss. Use this mode for typical VoIP applications. Because of the enhancement, even at high bitrates the output may sound different from the input. OPUS_APPLICATION_AUDIO - gives best quality at a given bitrate for most non-voice signals like music. Use this mode for music and mixed (music/voice) content, broadcast, and applications requiring less than 15 ms of coding delay. OPUS_APPLICATION_RESTRICTED_LOWDELAY - configures low-delay mode that disables the speech-optimized mode in exchange for slightly reduced delay. This mode can only be set on an newly initialized or freshly reset encoder because it changes the codec delay.

Definition at line 138 of file gnunet-helper-audio-record.c.

Function Documentation

◆ quit()

static void quit ( int  ret)
static

Pulseaudio shutdown task.

Definition at line 270 of file gnunet-helper-audio-record.c.

271 {
272  mainloop_api->quit (mainloop_api,
273  ret);
274  exit (ret);
275 }
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static GNUNET_NETWORK_STRUCT_END pa_mainloop_api * mainloop_api
Pulseaudio mainloop api.

References mainloop_api, and ret.

Referenced by context_state_callback(), exit_signal_callback(), packetizer(), stream_read_callback(), stream_state_callback(), and write_data().

Here is the caller graph for this function:

◆ write_data()

static void write_data ( const char *  ptr,
size_t  msg_size 
)
static

Definition at line 279 of file gnunet-helper-audio-record.c.

281 {
282  ssize_t ret;
283  size_t off;
284 
285  off = 0;
286  while (off < msg_size)
287  {
288  ret = write (STDOUT_FILENO,
289  &ptr[off],
290  msg_size - off);
291  if (0 >= ret)
292  {
293  if (-1 == ret)
295  "write");
296  quit (2);
297  }
298  off += ret;
299  }
300 }
static void quit(int ret)
Pulseaudio shutdown task.
#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

References GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, quit(), and ret.

Referenced by write_page().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_page()

static void write_page ( ogg_page *  og)
static

Definition at line 304 of file gnunet-helper-audio-record.c.

305 {
306  static unsigned long long toff;
307  size_t msg_size;
308 
309  msg_size = sizeof(struct AudioMessage) + og->header_len + og->body_len;
310  audio_message->header.size = htons ((uint16_t) msg_size);
311  GNUNET_memcpy (&audio_message[1], og->header, og->header_len);
312  GNUNET_memcpy (((char *) &audio_message[1]) + og->header_len, og->body,
313  og->body_len);
314 
315  toff += msg_size;
317  "Sending %u bytes of audio data (total: %llu)\n",
318  (unsigned int) msg_size,
319  toff);
320 #ifdef DEBUG_RECORD_PURE_OGG
321  if (dump_pure_ogg)
322  write_data ((const char *) &audio_message[1],
323  og->header_len + og->body_len);
324  else
325 #endif
326  write_data ((const char *) audio_message,
327  msg_size);
328 }
static int dump_pure_ogg
1 to not to write GNUnet message headers, producing pure playable ogg output
static struct AudioMessage * audio_message
Audio message skeleton.
static void write_data(const char *ptr, size_t msg_size)
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_ERROR_TYPE_DEBUG
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
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.

References audio_message, dump_pure_ogg, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, AudioMessage::header, GNUNET_MessageHeader::size, and write_data().

Referenced by ogg_init(), and packetizer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ packetizer()

static void packetizer ( )
static

Creates OPUS packets from PCM data.

Definition at line 335 of file gnunet-helper-audio-record.c.

336 {
337  char *nbuf;
338  size_t new_size;
339  int32_t len;
340  ogg_packet op;
341  ogg_page og;
342 
344  {
347  pcm_length);
349  len =
350  opus_encode_float (enc, pcm_buffer, FRAME_SIZE, opus_data,
352 
353  if (len < 0)
354  {
356  _ ("opus_encode_float() failed: %s. Aborting\n"),
357  opus_strerror (len));
358  quit (5);
359  }
360  if (((uint32_t) len) > UINT16_MAX - sizeof(struct AudioMessage))
361  {
362  GNUNET_break (0);
363  continue;
364  }
365 
366  /* As per OggOpus spec, granule is calculated as if the audio
367  had 48kHz sampling rate. */
369 
370  op.packet = (unsigned char *) opus_data;
371  op.bytes = len;
372  op.b_o_s = 0;
373  op.e_o_s = 0;
374  op.granulepos = enc_granulepos;
375  op.packetno = packet_id++;
376  ogg_stream_packetin (&os, &op);
377 
378  while (ogg_stream_flush_fill (&os, &og, PAGE_WATERLINE))
379  {
380  if (((unsigned long long) og.header_len)
381  + ((unsigned long long) og.body_len) >
382  UINT16_MAX - sizeof(struct AudioMessage))
383  {
384  GNUNET_assert (0);
385  continue;
386  }
387  write_page (&og);
388  }
389  }
390 
392  if (0 != new_size)
393  {
394  nbuf = pa_xmalloc (new_size);
395  memmove (nbuf,
397  new_size);
398  pa_xfree (transmit_buffer);
399  transmit_buffer = nbuf;
400  }
401  else
402  {
403  pa_xfree (transmit_buffer);
404  transmit_buffer = NULL;
405  }
407  transmit_buffer_length = new_size;
408 }
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:144
#define SAMPLING_RATE
Sampling rate.
#define MAX_PAYLOAD_BYTES
Maximum length of opus payload.
static size_t transmit_buffer_index
Read index for transmit buffer.
#define PAGE_WATERLINE
Pages are committed when their size goes over this value.
static float * pcm_buffer
PCM data buffer for one OPUS frame.
static size_t transmit_buffer_length
Length of audio buffer.
static char * transmit_buffer
Audio buffer.
static void write_page(ogg_page *og)
static unsigned char * opus_data
Buffer for encoded data.
static OpusEncoder * enc
OPUS encoder.
static int32_t packet_id
Ogg packet id.
static ogg_stream_state os
Ogg muxer state.
#define FRAME_SIZE
How many samples to buffer before encoding them.
static int64_t enc_granulepos
Ogg granule for current packet.
static int pcm_length
Length of the pcm data needed for one OPUS frame.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define _(String)
GNU gettext support macro.
Definition: platform.h:178

References _, enc, enc_granulepos, FRAME_SIZE, GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_memcpy, len, MAX_PAYLOAD_BYTES, op, opus_data, os, packet_id, PAGE_WATERLINE, pcm_buffer, pcm_length, quit(), SAMPLING_RATE, transmit_buffer, transmit_buffer_index, transmit_buffer_length, and write_page().

Referenced by stream_read_callback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stream_read_callback()

static void stream_read_callback ( pa_stream *  s,
size_t  length,
void *  userdata 
)
static

Pulseaudio callback when new data is available.

Definition at line 415 of file gnunet-helper-audio-record.c.

418 {
419  const void *data;
420 
421  (void) userdata;
423  "Got %u/%d bytes of PCM data\n",
424  (unsigned int) length,
425  pcm_length);
426 
427  GNUNET_assert (NULL != s);
428  GNUNET_assert (length > 0);
429  if (stdio_event)
430  mainloop_api->io_enable (stdio_event, PA_IO_EVENT_OUTPUT);
431 
432  if (pa_stream_peek (s, (const void **) &data, &length) < 0)
433  {
435  _ ("pa_stream_peek() failed: %s\n"),
436  pa_strerror (pa_context_errno (context)));
437  quit (1);
438  return;
439  }
440  GNUNET_assert (NULL != data);
441  GNUNET_assert (length > 0);
442  if (NULL != transmit_buffer)
443  {
444  transmit_buffer = pa_xrealloc (transmit_buffer,
445  transmit_buffer_length + length);
447  data,
448  length);
449  transmit_buffer_length += length;
450  }
451  else
452  {
453  transmit_buffer = pa_xmalloc (length);
455  transmit_buffer_length = length;
457  }
458  pa_stream_drop (s);
459  packetizer ();
460 }
static pa_context * context
Pulseaudio context.
static void packetizer()
Creates OPUS packets from PCM data.
static pa_io_event * stdio_event
Pulseaudio io events.
uint32_t data
The data value.

References _, context, data, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_memcpy, mainloop_api, packetizer(), pcm_length, quit(), stdio_event, transmit_buffer, transmit_buffer_index, and transmit_buffer_length.

Referenced by context_state_callback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ exit_signal_callback()

static void exit_signal_callback ( pa_mainloop_api *  m,
pa_signal_event *  e,
int  sig,
void *  userdata 
)
static

Exit callback for SIGTERM and SIGINT.

Definition at line 467 of file gnunet-helper-audio-record.c.

471 {
472  (void) m;
473  (void) e;
474  (void) sig;
475  (void) userdata;
477  _ ("Got signal, exiting.\n"));
478  quit (1);
479 }
static struct Experiment * e
static pa_mainloop * m
Pulseaudio mainloop.
@ GNUNET_ERROR_TYPE_INFO

References _, e, GNUNET_ERROR_TYPE_INFO, GNUNET_log, m, and quit().

Referenced by pa_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stream_state_callback()

static void stream_state_callback ( pa_stream *  s,
void *  userdata 
)
static

Pulseaudio stream state callback.

Definition at line 486 of file gnunet-helper-audio-record.c.

488 {
489  (void) userdata;
490  GNUNET_assert (NULL != s);
491  switch (pa_stream_get_state (s))
492  {
493  case PA_STREAM_CREATING:
494  case PA_STREAM_TERMINATED:
495  break;
496 
497  case PA_STREAM_READY:
498  {
499  const pa_buffer_attr *a;
500  char cmt[PA_CHANNEL_MAP_SNPRINT_MAX];
501  char sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
502 
504  _ ("Stream successfully created.\n"));
505 
506  if (! (a = pa_stream_get_buffer_attr (s)))
507  {
509  _ ("pa_stream_get_buffer_attr() failed: %s\n"),
510  pa_strerror (pa_context_errno
511  (pa_stream_get_context (s))));
512  }
513  else
514  {
516  _ ("Buffer metrics: maxlength=%u, fragsize=%u\n"),
517  a->maxlength, a->fragsize);
518  }
520  _ ("Using sample spec '%s', channel map '%s'.\n"),
521  pa_sample_spec_snprint (sst, sizeof(sst),
522  pa_stream_get_sample_spec (s)),
523  pa_channel_map_snprint (cmt, sizeof(cmt),
524  pa_stream_get_channel_map (s)));
525 
527  _ ("Connected to device %s (%u, %ssuspended).\n"),
528  pa_stream_get_device_name (s),
529  pa_stream_get_device_index (s),
530  pa_stream_is_suspended (s) ? "" : "not ");
531  }
532  break;
533 
534  case PA_STREAM_FAILED:
535  default:
537  _ ("Stream error: %s\n"),
538  pa_strerror (pa_context_errno (pa_stream_get_context (s))));
539  quit (1);
540  }
541 }

References _, GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_log, and quit().

Referenced by context_state_callback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ context_state_callback()

static void context_state_callback ( pa_context *  c,
void *  userdata 
)
static

Pulseaudio context state callback.

Definition at line 548 of file gnunet-helper-audio-record.c.

550 {
551  (void) userdata;
552  GNUNET_assert (c);
553 
554  switch (pa_context_get_state (c))
555  {
556  case PA_CONTEXT_CONNECTING:
557  case PA_CONTEXT_AUTHORIZING:
558  case PA_CONTEXT_SETTING_NAME:
559  break;
560 
561  case PA_CONTEXT_READY:
562  {
563  int r;
564  pa_buffer_attr na;
565 
568  _ ("Connection established.\n"));
569  if (! (stream_in =
570  pa_stream_new (c, "GNUNET_VoIP recorder", &sample_spec, NULL)))
571  {
573  _ ("pa_stream_new() failed: %s\n"),
574  pa_strerror (pa_context_errno (c)));
575  goto fail;
576  }
577  pa_stream_set_state_callback (stream_in, &stream_state_callback, NULL);
578  pa_stream_set_read_callback (stream_in, &stream_read_callback, NULL);
579  memset (&na, 0, sizeof(na));
580  na.maxlength = UINT32_MAX;
581  na.fragsize = pcm_length;
582  if ((r = pa_stream_connect_record (stream_in, NULL, &na,
583  PA_STREAM_ADJUST_LATENCY)) < 0)
584  {
586  _ ("pa_stream_connect_record() failed: %s\n"),
587  pa_strerror (pa_context_errno (c)));
588  goto fail;
589  }
590 
591  break;
592  }
593 
594  case PA_CONTEXT_TERMINATED:
595  quit (0);
596  break;
597 
598  case PA_CONTEXT_FAILED:
599  default:
601  _ ("Connection failure: %s\n"),
602  pa_strerror (pa_context_errno (c)));
603  goto fail;
604  }
605  return;
606 
607 fail:
608  quit (1);
609 }
static pa_stream * stream_in
Pulseaudio recording stream.
static void stream_read_callback(pa_stream *s, size_t length, void *userdata)
Pulseaudio callback when new data is available.
static void stream_state_callback(pa_stream *s, void *userdata)
Pulseaudio stream state callback.
static pa_sample_spec sample_spec
Specification for recording.

References _, GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_log, pcm_length, quit(), sample_spec, stream_in, stream_read_callback(), and stream_state_callback().

Referenced by pa_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_init()

static void pa_init ( )
static

Pulsaudio init.

Definition at line 616 of file gnunet-helper-audio-record.c.

617 {
618  int r;
619  int i;
620 
621  if (! pa_sample_spec_valid (&sample_spec))
622  {
624  _ ("Wrong Spec\n"));
625  }
626  /* set up main record loop */
627  if (! (m = pa_mainloop_new ()))
628  {
630  _ ("pa_mainloop_new() failed.\n"));
631  }
632  mainloop_api = pa_mainloop_get_api (m);
633 
634  /* listen to signals */
635  r = pa_signal_init (mainloop_api);
636  GNUNET_assert (r == 0);
637  pa_signal_new (SIGINT, &exit_signal_callback, NULL);
638  pa_signal_new (SIGTERM, &exit_signal_callback, NULL);
639 
640  /* connect to the main pulseaudio context */
641 
642  if (! (context = pa_context_new (mainloop_api, "GNUNET VoIP")))
643  {
645  _ ("pa_context_new() failed.\n"));
646  }
647  pa_context_set_state_callback (context, &context_state_callback, NULL);
648  if (pa_context_connect (context, NULL, 0, NULL) < 0)
649  {
651  _ ("pa_context_connect() failed: %s\n"),
652  pa_strerror (pa_context_errno (context)));
653  }
654  if (pa_mainloop_run (m, &i) < 0)
655  {
657  _ ("pa_mainloop_run() failed.\n"));
658  }
659 }
static void context_state_callback(pa_context *c, void *userdata)
Pulseaudio context state callback.
static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata)
Exit callback for SIGTERM and SIGINT.

References _, context, context_state_callback(), exit_signal_callback(), GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, m, mainloop_api, and sample_spec.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ opus_init()

static void opus_init ( )
static

OPUS init.

Definition at line 666 of file gnunet-helper-audio-record.c.

667 {
668  int err;
669 
670  pcm_length = FRAME_SIZE * CHANNELS * sizeof(float);
671  pcm_buffer = pa_xmalloc (pcm_length);
673  enc = opus_encoder_create (SAMPLING_RATE,
674  CHANNELS,
676  &err);
677  opus_encoder_ctl (enc,
678  OPUS_SET_PACKET_LOSS_PERC (
680  opus_encoder_ctl (enc,
681  OPUS_SET_COMPLEXITY (CONV_OPUS_ENCODING_COMPLEXITY));
682  opus_encoder_ctl (enc,
683  OPUS_SET_INBAND_FEC (CONV_OPUS_INBAND_FEC));
684  opus_encoder_ctl (enc,
685  OPUS_SET_SIGNAL (CONV_OPUS_SIGNAL));
686 }
#define CONV_OPUS_INBAND_FEC
Configures the encoder's use of inband forward error correction (FEC).
#define CONV_OPUS_SIGNAL
Configures the type of signal being encoded.
#define CHANNELS
Number of channels.
#define CONV_OPUS_APP_TYPE
Coding mode.
#define CONV_OPUS_ENCODING_COMPLEXITY
Configures the encoder's computational complexity.
#define CONV_OPUS_PACKET_LOSS_PERCENTAGE
Configures the encoder's expected packet loss percentage.
#define GNUNET_malloc(size)
Wrapper around malloc.

References CHANNELS, CONV_OPUS_APP_TYPE, CONV_OPUS_ENCODING_COMPLEXITY, CONV_OPUS_INBAND_FEC, CONV_OPUS_PACKET_LOSS_PERCENTAGE, CONV_OPUS_SIGNAL, enc, FRAME_SIZE, GNUNET_malloc, MAX_PAYLOAD_BYTES, opus_data, pcm_buffer, pcm_length, and SAMPLING_RATE.

Referenced by main().

Here is the caller graph for this function:

◆ ogg_init()

static void ogg_init ( )
static

Definition at line 690 of file gnunet-helper-audio-record.c.

691 {
692  int serialno;
693  struct OpusHeadPacket headpacket;
694  struct OpusCommentsPacket *commentspacket;
695  size_t commentspacket_len;
696 
698  0x7FFFFFFF);
699  /*Initialize Ogg stream struct*/
700  if (-1 == ogg_stream_init (&os, serialno))
701  {
703  _ ("ogg_stream_init() failed.\n"));
704  exit (3);
705  }
706 
707  packet_id = 0;
708 
709  /*Write header*/
710  {
711  ogg_packet op;
712  ogg_page og;
713  const char *opusver;
714  int vendor_length;
715 
716  GNUNET_memcpy (headpacket.magic, "OpusHead", 8);
717  headpacket.version = 1;
718  headpacket.channels = CHANNELS;
719  headpacket.preskip = GNUNET_htole16 (0);
720  headpacket.sampling_rate = GNUNET_htole32 (SAMPLING_RATE);
721  headpacket.gain = GNUNET_htole16 (0);
722  headpacket.channel_mapping = 0; /* Mono or stereo */
723 
724  op.packet = (unsigned char *) &headpacket;
725  op.bytes = sizeof(headpacket);
726  op.b_o_s = 1;
727  op.e_o_s = 0;
728  op.granulepos = 0;
729  op.packetno = packet_id++;
730  ogg_stream_packetin (&os, &op);
731 
732  /* Head packet must be alone on its page */
733  while (ogg_stream_flush (&os, &og))
734  {
735  write_page (&og);
736  }
737 
738  commentspacket_len = sizeof(*commentspacket);
739  opusver = opus_get_version_string ();
740  vendor_length = strlen (opusver);
741  commentspacket_len += vendor_length;
742  commentspacket_len += sizeof(uint32_t);
743 
744  commentspacket = (struct OpusCommentsPacket *) malloc (commentspacket_len);
745  if (NULL == commentspacket)
746  {
748  _ ("Failed to allocate %u bytes for second packet\n"),
749  (unsigned int) commentspacket_len);
750  exit (5);
751  }
752 
753  GNUNET_memcpy (commentspacket->magic, "OpusTags", 8);
754  commentspacket->vendor_length = GNUNET_htole32 (vendor_length);
755  GNUNET_memcpy (&commentspacket[1], opusver, vendor_length);
756  *(uint32_t *) &((char *) &commentspacket[1])[vendor_length] = \
757  GNUNET_htole32 (0); /* no tags */
758 
759  op.packet = (unsigned char *) commentspacket;
760  op.bytes = commentspacket_len;
761  op.b_o_s = 0;
762  op.e_o_s = 0;
763  op.granulepos = 0;
764  op.packetno = packet_id++;
765  ogg_stream_packetin (&os, &op);
766 
767  /* Comment packets must not be mixed with audio packets on their pages */
768  while (ogg_stream_flush (&os, &og))
769  {
770  write_page (&og);
771  }
772 
773  free (commentspacket);
774  }
775 }
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
@ GNUNET_CRYPTO_QUALITY_STRONG
High-quality operations are desired.
#define GNUNET_htole32(x)
#define GNUNET_htole16(x)

References _, OpusHeadPacket::channel_mapping, OpusHeadPacket::channels, CHANNELS, OpusHeadPacket::gain, GNUNET_CRYPTO_QUALITY_STRONG, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_ERROR, GNUNET_htole16, GNUNET_htole32, GNUNET_log, GNUNET_memcpy, OpusHeadPacket::magic, OpusCommentsPacket::magic, op, os, packet_id, OpusHeadPacket::preskip, OpusHeadPacket::sampling_rate, SAMPLING_RATE, OpusCommentsPacket::vendor_length, OpusHeadPacket::version, and write_page().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *  argv[] 
)

The main function for the record helper.

Parameters
argcnumber of arguments from the command line
argvcommand line arguments
Returns
0 ok, 1 on error

Definition at line 786 of file gnunet-helper-audio-record.c.

788 {
789  (void) argc;
790  (void) argv;
792  GNUNET_log_setup ("gnunet-helper-audio-record",
793  "WARNING",
794  NULL));
796  "Audio source starts\n");
797  audio_message = GNUNET_malloc (UINT16_MAX);
799 
800 #ifdef DEBUG_RECORD_PURE_OGG
801  dump_pure_ogg = getenv ("GNUNET_RECORD_PURE_OGG") ? 1 : 0;
802 #endif
803  ogg_init ();
804  opus_init ();
805  pa_init ();
806  return 0;
807 }
char * getenv()
static void pa_init()
Pulsaudio init.
static void ogg_init()
static void opus_init()
OPUS init.
@ GNUNET_OK
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO
Message to transmit the audio between helper and speaker/microphone library.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.

References audio_message, dump_pure_ogg, getenv(), GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_log_setup(), GNUNET_malloc, GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO, GNUNET_OK, AudioMessage::header, ogg_init(), opus_init(), pa_init(), and GNUNET_MessageHeader::type.

Here is the call graph for this function:

Variable Documentation

◆ sample_spec

pa_sample_spec sample_spec
static
Initial value:
= {
.format = PA_SAMPLE_FLOAT32LE,
.rate = 48000 ,
.channels = 1
}

Specification for recording.

May change in the future to spec negotiation.

Definition at line 143 of file gnunet-helper-audio-record.c.

Referenced by context_state_callback(), and pa_init().

◆ mainloop_api

GNUNET_NETWORK_STRUCT_END pa_mainloop_api* mainloop_api
static

Pulseaudio mainloop api.

Definition at line 181 of file gnunet-helper-audio-record.c.

Referenced by pa_init(), quit(), and stream_read_callback().

◆ m

pa_mainloop* m
static

Pulseaudio mainloop.

Definition at line 186 of file gnunet-helper-audio-record.c.

Referenced by exit_signal_callback(), and pa_init().

◆ context

pa_context* context
static

Pulseaudio context.

Definition at line 191 of file gnunet-helper-audio-record.c.

Referenced by pa_init(), and stream_read_callback().

◆ stream_in

pa_stream* stream_in
static

Pulseaudio recording stream.

Definition at line 196 of file gnunet-helper-audio-record.c.

Referenced by context_state_callback().

◆ stdio_event

pa_io_event* stdio_event
static

Pulseaudio io events.

Definition at line 201 of file gnunet-helper-audio-record.c.

Referenced by stream_read_callback().

◆ enc

◆ opus_data

unsigned char* opus_data
static

Buffer for encoded data.

Definition at line 211 of file gnunet-helper-audio-record.c.

Referenced by opus_init(), and packetizer().

◆ pcm_buffer

float* pcm_buffer
static

PCM data buffer for one OPUS frame.

Definition at line 216 of file gnunet-helper-audio-record.c.

Referenced by opus_init(), and packetizer().

◆ pcm_length

int pcm_length
static

Length of the pcm data needed for one OPUS frame.

Definition at line 221 of file gnunet-helper-audio-record.c.

Referenced by context_state_callback(), opus_init(), packetizer(), and stream_read_callback().

◆ transmit_buffer

char* transmit_buffer
static

Audio buffer.

Definition at line 226 of file gnunet-helper-audio-record.c.

Referenced by packetizer(), and stream_read_callback().

◆ transmit_buffer_length

size_t transmit_buffer_length
static

Length of audio buffer.

Definition at line 231 of file gnunet-helper-audio-record.c.

Referenced by packetizer(), and stream_read_callback().

◆ transmit_buffer_index

size_t transmit_buffer_index
static

Read index for transmit buffer.

Definition at line 236 of file gnunet-helper-audio-record.c.

Referenced by packetizer(), and stream_read_callback().

◆ audio_message

struct AudioMessage* audio_message
static

Audio message skeleton.

Definition at line 241 of file gnunet-helper-audio-record.c.

Referenced by main(), and write_page().

◆ os

ogg_stream_state os
static

Ogg muxer state.

Definition at line 246 of file gnunet-helper-audio-record.c.

Referenced by ogg_init(), and packetizer().

◆ packet_id

int32_t packet_id
static

Ogg packet id.

Definition at line 251 of file gnunet-helper-audio-record.c.

Referenced by ogg_init(), and packetizer().

◆ enc_granulepos

int64_t enc_granulepos
static

Ogg granule for current packet.

Definition at line 256 of file gnunet-helper-audio-record.c.

Referenced by packetizer().

◆ dump_pure_ogg

int dump_pure_ogg
static

1 to not to write GNUnet message headers, producing pure playable ogg output

Definition at line 263 of file gnunet-helper-audio-record.c.

Referenced by main(), and write_page().