GNUnet  0.10.x
Data Structures | Macros | Functions | Variables
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 commited 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.

Referenced by ogg_init(), opus_init(), and packetizer().

◆ 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.

Referenced by opus_init(), and packetizer().

◆ PAGE_WATERLINE

#define PAGE_WATERLINE   800

Pages are commited 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.

Referenced by packetizer().

◆ MAX_PAYLOAD_BYTES

#define MAX_PAYLOAD_BYTES   1024

Maximum length of opus payload.

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

Referenced by opus_init(), and packetizer().

◆ CHANNELS

#define CHANNELS   1

Number of channels.

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

Referenced by ogg_init(), and opus_init().

◆ 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.

Referenced by opus_init().

◆ 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.

Referenced by opus_init().

◆ 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.

Referenced by opus_init().

◆ 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.

Referenced by opus_init().

◆ 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.

Referenced by opus_init().

Function Documentation

◆ quit()

static void quit ( int  ret)
static

Pulseaudio shutdown task.

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

References mainloop_api.

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

271 {
272  mainloop_api->quit (mainloop_api,
273  ret);
274  exit (ret);
275 }
static GNUNET_NETWORK_STRUCT_END pa_mainloop_api * mainloop_api
Pulseaudio mainloop api.
static int ret
Final status code.
Definition: gnunet-arm.c:89
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.

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

Referenced by write_page().

281 {
282  ssize_t ret;
283  size_t off;
284  off = 0;
285  while (off < msg_size)
286  {
287  ret = write (STDOUT_FILENO,
288  &ptr[off],
289  msg_size - off);
290  if (0 >= ret)
291  {
292  if (-1 == ret)
294  "write");
295  quit (2);
296  }
297  off += ret;
298  }
299 }
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
static void quit(int ret)
Pulseaudio shutdown task.
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 303 of file gnunet-helper-audio-record.c.

References 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().

304 {
305  static unsigned long long toff;
306  size_t msg_size;
307  msg_size = sizeof (struct AudioMessage) + og->header_len + og->body_len;
308  audio_message->header.size = htons ((uint16_t) msg_size);
309  GNUNET_memcpy (&audio_message[1], og->header, og->header_len);
310  GNUNET_memcpy (((char *) &audio_message[1]) + og->header_len, og->body, og->body_len);
311 
312  toff += msg_size;
314  "Sending %u bytes of audio data (total: %llu)\n",
315  (unsigned int) msg_size,
316  toff);
317 #ifdef DEBUG_RECORD_PURE_OGG
318  if (dump_pure_ogg)
319  write_data ((const char *) &audio_message[1],
320  og->header_len + og->body_len);
321  else
322 #endif
323  write_data ((const char *) audio_message,
324  msg_size);
325 }
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO.
Definition: conversation.h:60
static void write_data(const char *ptr, size_t msg_size)
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
#define GNUNET_memcpy(dst, src, n)
Message to transmit the audio (between client and helpers).
Definition: conversation.h:55
static struct AudioMessage * audio_message
Audio message skeleton.
static int dump_pure_ogg
1 to not to write GNUnet message headers, producing pure playable ogg output
#define GNUNET_log(kind,...)
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 332 of file gnunet-helper-audio-record.c.

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().

333 {
334  char *nbuf;
335  size_t new_size;
336  int32_t len;
337  ogg_packet op;
338  ogg_page og;
339 
341  {
344  pcm_length);
346  len =
347  opus_encode_float (enc, pcm_buffer, FRAME_SIZE, opus_data,
349 
350  if (len < 0)
351  {
353  _("opus_encode_float() failed: %s. Aborting\n"),
354  opus_strerror (len));
355  quit (5);
356  }
357  if (((uint32_t)len) > UINT16_MAX - sizeof (struct AudioMessage))
358  {
359  GNUNET_break (0);
360  continue;
361  }
362 
363  /* As per OggOpus spec, granule is calculated as if the audio
364  had 48kHz sampling rate. */
366 
367  op.packet = (unsigned char *) opus_data;
368  op.bytes = len;
369  op.b_o_s = 0;
370  op.e_o_s = 0;
371  op.granulepos = enc_granulepos;
372  op.packetno = packet_id++;
373  ogg_stream_packetin (&os, &op);
374 
375  while (ogg_stream_flush_fill (&os, &og, PAGE_WATERLINE))
376  {
377  if ( ((unsigned long long) og.header_len) +
378  ((unsigned long long) og.body_len) >
379  UINT16_MAX - sizeof (struct AudioMessage))
380  {
381  GNUNET_assert (0);
382  continue;
383  }
384  write_page (&og);
385  }
386  }
387 
389  if (0 != new_size)
390  {
391  nbuf = pa_xmalloc (new_size);
392  memmove (nbuf,
393  &transmit_buffer[transmit_buffer_index],
394  new_size);
395  pa_xfree (transmit_buffer);
396  transmit_buffer = nbuf;
397  }
398  else
399  {
400  pa_xfree (transmit_buffer);
401  transmit_buffer = NULL;
402  }
403  transmit_buffer_index = 0;
404  transmit_buffer_length = new_size;
405 }
static void write_page(ogg_page *og)
static size_t transmit_buffer_index
Read index for transmit buffer.
static int pcm_length
Length of the pcm data needed for one OPUS frame.
static int64_t enc_granulepos
Ogg granule for current packet.
#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:208
#define GNUNET_memcpy(dst, src, n)
Message to transmit the audio (between client and helpers).
Definition: conversation.h:55
#define SAMPLING_RATE
Sampling rate.
static char * transmit_buffer
Audio buffer.
static void quit(int ret)
Pulseaudio shutdown task.
#define MAX_PAYLOAD_BYTES
Maximum length of opus payload.
static size_t transmit_buffer_length
Length of audio buffer.
static unsigned char * opus_data
Buffer for encoded data.
static OpusEncoder * enc
OPUS encoder.
#define GNUNET_log(kind,...)
#define FRAME_SIZE
How many samples to buffer before encoding them.
static int32_t packet_id
Ogg packet id.
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:139
static float * pcm_buffer
PCM data buffer for one OPUS frame.
static ogg_stream_state os
Ogg muxer state.
#define PAGE_WATERLINE
Pages are commited when their size goes over this value.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
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 412 of file gnunet-helper-audio-record.c.

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().

415 {
416  const void *data;
417 
418  (void) userdata;
420  "Got %u/%d bytes of PCM data\n",
421  (unsigned int) length,
422  pcm_length);
423 
424  GNUNET_assert (NULL != s);
425  GNUNET_assert (length > 0);
426  if (stdio_event)
427  mainloop_api->io_enable (stdio_event, PA_IO_EVENT_OUTPUT);
428 
429  if (pa_stream_peek (s, (const void **) &data, &length) < 0)
430  {
432  _("pa_stream_peek() failed: %s\n"),
433  pa_strerror (pa_context_errno (context)));
434  quit (1);
435  return;
436  }
437  GNUNET_assert (NULL != data);
438  GNUNET_assert (length > 0);
439  if (NULL != transmit_buffer)
440  {
441  transmit_buffer = pa_xrealloc (transmit_buffer,
442  transmit_buffer_length + length);
444  data,
445  length);
446  transmit_buffer_length += length;
447  }
448  else
449  {
450  transmit_buffer = pa_xmalloc (length);
451  GNUNET_memcpy (transmit_buffer, data, length);
452  transmit_buffer_length = length;
454  }
455  pa_stream_drop (s);
456  packetizer ();
457 }
static size_t transmit_buffer_index
Read index for transmit buffer.
static int pcm_length
Length of the pcm data needed for one OPUS frame.
static GNUNET_NETWORK_STRUCT_END pa_mainloop_api * mainloop_api
Pulseaudio mainloop api.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static pa_context * context
Pulseaudio context.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
#define GNUNET_memcpy(dst, src, n)
static char * transmit_buffer
Audio buffer.
static void quit(int ret)
Pulseaudio shutdown task.
static size_t transmit_buffer_length
Length of audio buffer.
static void packetizer()
Creates OPUS packets from PCM data.
static pa_io_event * stdio_event
Pulseaudio io events.
#define GNUNET_log(kind,...)
uint32_t data
The data value.
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 464 of file gnunet-helper-audio-record.c.

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

Referenced by pa_init().

468 {
469  (void) m;
470  (void) e;
471  (void) sig;
472  (void) userdata;
474  _("Got signal, exiting.\n"));
475  quit (1);
476 }
static struct Experiment * e
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static void quit(int ret)
Pulseaudio shutdown task.
static pa_mainloop * m
Pulseaudio mainloop.
#define GNUNET_log(kind,...)
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 483 of file gnunet-helper-audio-record.c.

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

Referenced by context_state_callback().

485 {
486  (void) userdata;
487  GNUNET_assert (NULL != s);
488  switch (pa_stream_get_state (s))
489  {
490  case PA_STREAM_CREATING:
491  case PA_STREAM_TERMINATED:
492  break;
493  case PA_STREAM_READY:
494  {
495  const pa_buffer_attr *a;
496  char cmt[PA_CHANNEL_MAP_SNPRINT_MAX];
497  char sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
498 
500  _("Stream successfully created.\n"));
501 
502  if (!(a = pa_stream_get_buffer_attr (s)))
503  {
505  _("pa_stream_get_buffer_attr() failed: %s\n"),
506  pa_strerror (pa_context_errno
507  (pa_stream_get_context (s))));
508 
509  }
510  else
511  {
513  _("Buffer metrics: maxlength=%u, fragsize=%u\n"),
514  a->maxlength, a->fragsize);
515  }
517  _("Using sample spec '%s', channel map '%s'.\n"),
518  pa_sample_spec_snprint (sst, sizeof (sst),
519  pa_stream_get_sample_spec (s)),
520  pa_channel_map_snprint (cmt, sizeof (cmt),
521  pa_stream_get_channel_map (s)));
522 
524  _("Connected to device %s (%u, %ssuspended).\n"),
525  pa_stream_get_device_name (s),
526  pa_stream_get_device_index (s),
527  pa_stream_is_suspended (s) ? "" : "not ");
528  }
529  break;
530  case PA_STREAM_FAILED:
531  default:
533  _("Stream error: %s\n"),
534  pa_strerror (pa_context_errno (pa_stream_get_context (s))));
535  quit (1);
536  }
537 }
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static void quit(int ret)
Pulseaudio shutdown task.
#define GNUNET_log(kind,...)
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 544 of file gnunet-helper-audio-record.c.

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().

546 {
547  (void) userdata;
548  GNUNET_assert (c);
549 
550  switch (pa_context_get_state (c))
551  {
552  case PA_CONTEXT_CONNECTING:
553  case PA_CONTEXT_AUTHORIZING:
554  case PA_CONTEXT_SETTING_NAME:
555  break;
556  case PA_CONTEXT_READY:
557  {
558  int r;
559  pa_buffer_attr na;
560 
563  _("Connection established.\n"));
564  if (! (stream_in =
565  pa_stream_new (c, "GNUNET_VoIP recorder", &sample_spec, NULL)))
566  {
568  _("pa_stream_new() failed: %s\n"),
569  pa_strerror (pa_context_errno (c)));
570  goto fail;
571  }
572  pa_stream_set_state_callback (stream_in, &stream_state_callback, NULL);
573  pa_stream_set_read_callback (stream_in, &stream_read_callback, NULL);
574  memset (&na, 0, sizeof (na));
575  na.maxlength = UINT32_MAX;
576  na.fragsize = pcm_length;
577  if ((r = pa_stream_connect_record (stream_in, NULL, &na,
578  PA_STREAM_ADJUST_LATENCY)) < 0)
579  {
581  _("pa_stream_connect_record() failed: %s\n"),
582  pa_strerror (pa_context_errno (c)));
583  goto fail;
584  }
585 
586  break;
587  }
588  case PA_CONTEXT_TERMINATED:
589  quit (0);
590  break;
591  case PA_CONTEXT_FAILED:
592  default:
594  _("Connection failure: %s\n"),
595  pa_strerror (pa_context_errno (c)));
596  goto fail;
597  }
598  return;
599 
600 fail:
601  quit (1);
602 }
static int pcm_length
Length of the pcm data needed for one OPUS frame.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static pa_stream * stream_in
Pulseaudio recording stream.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static void quit(int ret)
Pulseaudio shutdown task.
static void stream_state_callback(pa_stream *s, void *userdata)
Pulseaudio stream state callback.
#define GNUNET_log(kind,...)
static pa_sample_spec sample_spec
Specification for recording.
static void stream_read_callback(pa_stream *s, size_t length, void *userdata)
Pulseaudio callback when new data is available.
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 609 of file gnunet-helper-audio-record.c.

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().

610 {
611  int r;
612  int i;
613 
614  if (!pa_sample_spec_valid (&sample_spec))
615  {
617  _("Wrong Spec\n"));
618  }
619  /* set up main record loop */
620  if (!(m = pa_mainloop_new ()))
621  {
623  _("pa_mainloop_new() failed.\n"));
624  }
625  mainloop_api = pa_mainloop_get_api (m);
626 
627  /* listen to signals */
628  r = pa_signal_init (mainloop_api);
629  GNUNET_assert (r == 0);
630  pa_signal_new (SIGINT, &exit_signal_callback, NULL);
631  pa_signal_new (SIGTERM, &exit_signal_callback, NULL);
632 
633  /* connect to the main pulseaudio context */
634 
635  if (!(context = pa_context_new (mainloop_api, "GNUNET VoIP")))
636  {
638  _("pa_context_new() failed.\n"));
639  }
640  pa_context_set_state_callback (context, &context_state_callback, NULL);
641  if (pa_context_connect (context, NULL, 0, NULL) < 0)
642  {
644  _("pa_context_connect() failed: %s\n"),
645  pa_strerror (pa_context_errno (context)));
646  }
647  if (pa_mainloop_run (m, &i) < 0)
648  {
650  _("pa_mainloop_run() failed.\n"));
651  }
652 }
static GNUNET_NETWORK_STRUCT_END pa_mainloop_api * mainloop_api
Pulseaudio mainloop api.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static pa_context * context
Pulseaudio context.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata)
Exit callback for SIGTERM and SIGINT.
static void context_state_callback(pa_context *c, void *userdata)
Pulseaudio context state callback.
static pa_mainloop * m
Pulseaudio mainloop.
#define GNUNET_log(kind,...)
static pa_sample_spec sample_spec
Specification for recording.
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 659 of file gnunet-helper-audio-record.c.

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().

660 {
661  int err;
662 
663  pcm_length = FRAME_SIZE * CHANNELS * sizeof (float);
664  pcm_buffer = pa_xmalloc (pcm_length);
666  enc = opus_encoder_create (SAMPLING_RATE,
667  CHANNELS,
669  &err);
670  opus_encoder_ctl (enc,
671  OPUS_SET_PACKET_LOSS_PERC (CONV_OPUS_PACKET_LOSS_PERCENTAGE));
672  opus_encoder_ctl (enc,
673  OPUS_SET_COMPLEXITY (CONV_OPUS_ENCODING_COMPLEXITY));
674  opus_encoder_ctl (enc,
675  OPUS_SET_INBAND_FEC (CONV_OPUS_INBAND_FEC));
676  opus_encoder_ctl (enc,
677  OPUS_SET_SIGNAL (CONV_OPUS_SIGNAL));
678 }
#define CONV_OPUS_ENCODING_COMPLEXITY
Configures the encoder&#39;s computational complexity.
static int pcm_length
Length of the pcm data needed for one OPUS frame.
#define CONV_OPUS_SIGNAL
Configures the type of signal being encoded.
#define CONV_OPUS_INBAND_FEC
Configures the encoder&#39;s use of inband forward error correction (FEC).
#define CHANNELS
Number of channels.
#define SAMPLING_RATE
Sampling rate.
#define CONV_OPUS_PACKET_LOSS_PERCENTAGE
Configures the encoder&#39;s expected packet loss percentage.
#define MAX_PAYLOAD_BYTES
Maximum length of opus payload.
static unsigned char * opus_data
Buffer for encoded data.
static OpusEncoder * enc
OPUS encoder.
#define FRAME_SIZE
How many samples to buffer before encoding them.
static float * pcm_buffer
PCM data buffer for one OPUS frame.
#define CONV_OPUS_APP_TYPE
Coding mode.
#define GNUNET_malloc(size)
Wrapper around malloc.
Here is the caller graph for this function:

◆ ogg_init()

static void ogg_init ( )
static

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

References _, OpusHeadPacket::channel_mapping, CHANNELS, OpusHeadPacket::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, SAMPLING_RATE, OpusHeadPacket::sampling_rate, OpusCommentsPacket::vendor_length, OpusHeadPacket::version, and write_page().

Referenced by main().

683 {
684  int serialno;
685  struct OpusHeadPacket headpacket;
686  struct OpusCommentsPacket *commentspacket;
687  size_t commentspacket_len;
688 
690  0x7FFFFFFF);
691  /*Initialize Ogg stream struct*/
692  if (-1 == ogg_stream_init (&os, serialno))
693  {
695  _("ogg_stream_init() failed.\n"));
696  exit (3);
697  }
698 
699  packet_id = 0;
700 
701  /*Write header*/
702  {
703  ogg_packet op;
704  ogg_page og;
705  const char *opusver;
706  int vendor_length;
707 
708  GNUNET_memcpy (headpacket.magic, "OpusHead", 8);
709  headpacket.version = 1;
710  headpacket.channels = CHANNELS;
711  headpacket.preskip = GNUNET_htole16 (0);
712  headpacket.sampling_rate = GNUNET_htole32 (SAMPLING_RATE);
713  headpacket.gain = GNUNET_htole16 (0);
714  headpacket.channel_mapping = 0; /* Mono or stereo */
715 
716  op.packet = (unsigned char *) &headpacket;
717  op.bytes = sizeof (headpacket);
718  op.b_o_s = 1;
719  op.e_o_s = 0;
720  op.granulepos = 0;
721  op.packetno = packet_id++;
722  ogg_stream_packetin (&os, &op);
723 
724  /* Head packet must be alone on its page */
725  while (ogg_stream_flush (&os, &og))
726  {
727  write_page (&og);
728  }
729 
730  commentspacket_len = sizeof (*commentspacket);
731  opusver = opus_get_version_string ();
732  vendor_length = strlen (opusver);
733  commentspacket_len += vendor_length;
734  commentspacket_len += sizeof (uint32_t);
735 
736  commentspacket = (struct OpusCommentsPacket *) malloc (commentspacket_len);
737  if (NULL == commentspacket)
738  {
740  _("Failed to allocate %u bytes for second packet\n"),
741  (unsigned int) commentspacket_len);
742  exit (5);
743  }
744 
745  GNUNET_memcpy (commentspacket->magic, "OpusTags", 8);
746  commentspacket->vendor_length = GNUNET_htole32 (vendor_length);
747  GNUNET_memcpy (&commentspacket[1], opusver, vendor_length);
748  *(uint32_t *) &((char *) &commentspacket[1])[vendor_length] = \
749  GNUNET_htole32 (0); /* no tags */
750 
751  op.packet = (unsigned char *) commentspacket;
752  op.bytes = commentspacket_len;
753  op.b_o_s = 0;
754  op.e_o_s = 0;
755  op.granulepos = 0;
756  op.packetno = packet_id++;
757  ogg_stream_packetin (&os, &op);
758 
759  /* Comment packets must not be mixed with audio packets on their pages */
760  while (ogg_stream_flush (&os, &og))
761  {
762  write_page (&og);
763  }
764 
765  free (commentspacket);
766  }
767 }
static void write_page(ogg_page *og)
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
#define CHANNELS
Number of channels.
#define GNUNET_memcpy(dst, src, n)
#define SAMPLING_RATE
Sampling rate.
#define GNUNET_htole32(x)
#define GNUNET_htole16(x)
#define GNUNET_log(kind,...)
static int32_t packet_id
Ogg packet id.
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:139
static ogg_stream_state os
Ogg muxer state.
High-quality operations are desired.
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 777 of file gnunet-helper-audio-record.c.

References 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.

779 {
780  (void) argc;
781  (void) argv;
783  GNUNET_log_setup ("gnunet-helper-audio-record",
784  "WARNING",
785  NULL));
787  "Audio source starts\n");
788  audio_message = GNUNET_malloc (UINT16_MAX);
790 
791 #ifdef DEBUG_RECORD_PURE_OGG
792  dump_pure_ogg = getenv ("GNUNET_RECORD_PURE_OGG") ? 1 : 0;
793 #endif
794  ogg_init ();
795  opus_init ();
796  pa_init ();
797  return 0;
798 }
static void ogg_init()
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO.
Definition: conversation.h:60
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
static void opus_init()
OPUS init.
static void pa_init()
Pulsaudio init.
static struct AudioMessage * audio_message
Audio message skeleton.
char * getenv()
static int dump_pure_ogg
1 to not to write GNUnet message headers, producing pure playable ogg output
#define GNUNET_log(kind,...)
#define GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO
Message to transmit the audio between helper and speaker/microphone library.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_malloc(size)
Wrapper around malloc.
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 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

OpusEncoder* enc
static

◆ 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().

◆ 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().