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

269 {
271  ret);
272  exit(ret);
273 }
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 277 of file gnunet-helper-audio-record.c.

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

Referenced by write_page().

279 {
280  ssize_t ret;
281  size_t off;
282 
283  off = 0;
284  while (off < msg_size)
285  {
286  ret = write(STDOUT_FILENO,
287  &ptr[off],
288  msg_size - off);
289  if (0 >= ret)
290  {
291  if (-1 == ret)
293  "write");
294  quit(2);
295  }
296  off += ret;
297  }
298 }
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 302 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().

303 {
304  static unsigned long long toff;
305  size_t msg_size;
306 
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:59
static void write_data(const char *ptr, size_t msg_size)
#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...
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_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#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:181
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 GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
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:181
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 
494  case PA_STREAM_READY:
495  {
496  const pa_buffer_attr *a;
497  char cmt[PA_CHANNEL_MAP_SNPRINT_MAX];
498  char sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
499 
501  _("Stream successfully created.\n"));
502 
503  if (!(a = pa_stream_get_buffer_attr(s)))
504  {
506  _("pa_stream_get_buffer_attr() failed: %s\n"),
507  pa_strerror(pa_context_errno
508  (pa_stream_get_context(s))));
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 
531  case PA_STREAM_FAILED:
532  default:
534  _("Stream error: %s\n"),
535  pa_strerror(pa_context_errno(pa_stream_get_context(s))));
536  quit(1);
537  }
538 }
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
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 545 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().

547 {
548  (void)userdata;
549  GNUNET_assert(c);
550 
551  switch (pa_context_get_state(c))
552  {
553  case PA_CONTEXT_CONNECTING:
554  case PA_CONTEXT_AUTHORIZING:
555  case PA_CONTEXT_SETTING_NAME:
556  break;
557 
558  case PA_CONTEXT_READY:
559  {
560  int r;
561  pa_buffer_attr na;
562 
565  _("Connection established.\n"));
566  if (!(stream_in =
567  pa_stream_new(c, "GNUNET_VoIP recorder", &sample_spec, NULL)))
568  {
570  _("pa_stream_new() failed: %s\n"),
571  pa_strerror(pa_context_errno(c)));
572  goto fail;
573  }
574  pa_stream_set_state_callback(stream_in, &stream_state_callback, NULL);
575  pa_stream_set_read_callback(stream_in, &stream_read_callback, NULL);
576  memset(&na, 0, sizeof(na));
577  na.maxlength = UINT32_MAX;
578  na.fragsize = pcm_length;
579  if ((r = pa_stream_connect_record(stream_in, NULL, &na,
580  PA_STREAM_ADJUST_LATENCY)) < 0)
581  {
583  _("pa_stream_connect_record() failed: %s\n"),
584  pa_strerror(pa_context_errno(c)));
585  goto fail;
586  }
587 
588  break;
589  }
590 
591  case PA_CONTEXT_TERMINATED:
592  quit(0);
593  break;
594 
595  case PA_CONTEXT_FAILED:
596  default:
598  _("Connection failure: %s\n"),
599  pa_strerror(pa_context_errno(c)));
600  goto fail;
601  }
602  return;
603 
604 fail:
605  quit(1);
606 }
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:181
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 613 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().

614 {
615  int r;
616  int i;
617 
618  if (!pa_sample_spec_valid(&sample_spec))
619  {
621  _("Wrong Spec\n"));
622  }
623  /* set up main record loop */
624  if (!(m = pa_mainloop_new()))
625  {
627  _("pa_mainloop_new() failed.\n"));
628  }
629  mainloop_api = pa_mainloop_get_api(m);
630 
631  /* listen to signals */
632  r = pa_signal_init(mainloop_api);
633  GNUNET_assert(r == 0);
634  pa_signal_new(SIGINT, &exit_signal_callback, NULL);
635  pa_signal_new(SIGTERM, &exit_signal_callback, NULL);
636 
637  /* connect to the main pulseaudio context */
638 
639  if (!(context = pa_context_new(mainloop_api, "GNUNET VoIP")))
640  {
642  _("pa_context_new() failed.\n"));
643  }
644  pa_context_set_state_callback(context, &context_state_callback, NULL);
645  if (pa_context_connect(context, NULL, 0, NULL) < 0)
646  {
648  _("pa_context_connect() failed: %s\n"),
649  pa_strerror(pa_context_errno(context)));
650  }
651  if (pa_mainloop_run(m, &i) < 0)
652  {
654  _("pa_mainloop_run() failed.\n"));
655  }
656 }
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:181
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 663 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().

664 {
665  int err;
666 
667  pcm_length = FRAME_SIZE * CHANNELS * sizeof(float);
668  pcm_buffer = pa_xmalloc(pcm_length);
670  enc = opus_encoder_create(SAMPLING_RATE,
671  CHANNELS,
673  &err);
674  opus_encoder_ctl(enc,
675  OPUS_SET_PACKET_LOSS_PERC(CONV_OPUS_PACKET_LOSS_PERCENTAGE));
676  opus_encoder_ctl(enc,
677  OPUS_SET_COMPLEXITY(CONV_OPUS_ENCODING_COMPLEXITY));
678  opus_encoder_ctl(enc,
679  OPUS_SET_INBAND_FEC(CONV_OPUS_INBAND_FEC));
680  opus_encoder_ctl(enc,
681  OPUS_SET_SIGNAL(CONV_OPUS_SIGNAL));
682 }
#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 686 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().

687 {
688  int serialno;
689  struct OpusHeadPacket headpacket;
690  struct OpusCommentsPacket *commentspacket;
691  size_t commentspacket_len;
692 
694  0x7FFFFFFF);
695  /*Initialize Ogg stream struct*/
696  if (-1 == ogg_stream_init(&os, serialno))
697  {
699  _("ogg_stream_init() failed.\n"));
700  exit(3);
701  }
702 
703  packet_id = 0;
704 
705  /*Write header*/
706  {
707  ogg_packet op;
708  ogg_page og;
709  const char *opusver;
710  int vendor_length;
711 
712  GNUNET_memcpy(headpacket.magic, "OpusHead", 8);
713  headpacket.version = 1;
714  headpacket.channels = CHANNELS;
715  headpacket.preskip = GNUNET_htole16(0);
716  headpacket.sampling_rate = GNUNET_htole32(SAMPLING_RATE);
717  headpacket.gain = GNUNET_htole16(0);
718  headpacket.channel_mapping = 0; /* Mono or stereo */
719 
720  op.packet = (unsigned char *)&headpacket;
721  op.bytes = sizeof(headpacket);
722  op.b_o_s = 1;
723  op.e_o_s = 0;
724  op.granulepos = 0;
725  op.packetno = packet_id++;
726  ogg_stream_packetin(&os, &op);
727 
728  /* Head packet must be alone on its page */
729  while (ogg_stream_flush(&os, &og))
730  {
731  write_page(&og);
732  }
733 
734  commentspacket_len = sizeof(*commentspacket);
735  opusver = opus_get_version_string();
736  vendor_length = strlen(opusver);
737  commentspacket_len += vendor_length;
738  commentspacket_len += sizeof(uint32_t);
739 
740  commentspacket = (struct OpusCommentsPacket *)malloc(commentspacket_len);
741  if (NULL == commentspacket)
742  {
744  _("Failed to allocate %u bytes for second packet\n"),
745  (unsigned int)commentspacket_len);
746  exit(5);
747  }
748 
749  GNUNET_memcpy(commentspacket->magic, "OpusTags", 8);
750  commentspacket->vendor_length = GNUNET_htole32(vendor_length);
751  GNUNET_memcpy(&commentspacket[1], opusver, vendor_length);
752  *(uint32_t *)&((char *)&commentspacket[1])[vendor_length] = \
753  GNUNET_htole32(0); /* no tags */
754 
755  op.packet = (unsigned char *)commentspacket;
756  op.bytes = commentspacket_len;
757  op.b_o_s = 0;
758  op.e_o_s = 0;
759  op.granulepos = 0;
760  op.packetno = packet_id++;
761  ogg_stream_packetin(&os, &op);
762 
763  /* Comment packets must not be mixed with audio packets on their pages */
764  while (ogg_stream_flush(&os, &og))
765  {
766  write_page(&og);
767  }
768 
769  free(commentspacket);
770  }
771 }
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 GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
#define CHANNELS
Number of channels.
#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 781 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.

783 {
784  (void)argc;
785  (void)argv;
787  GNUNET_log_setup("gnunet-helper-audio-record",
788  "WARNING",
789  NULL));
791  "Audio source starts\n");
792  audio_message = GNUNET_malloc(UINT16_MAX);
794 
795 #ifdef DEBUG_RECORD_PURE_OGG
796  dump_pure_ogg = getenv("GNUNET_RECORD_PURE_OGG") ? 1 : 0;
797 #endif
798  ogg_init();
799  opus_init();
800  pa_init();
801  return 0;
802 }
static void ogg_init()
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO.
Definition: conversation.h:59
#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:75
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 179 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 184 of file gnunet-helper-audio-record.c.

Referenced by pa_init().

◆ context

pa_context* context
static

Pulseaudio context.

Definition at line 189 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 194 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 199 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 209 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 214 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 219 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 224 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 229 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 234 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 239 of file gnunet-helper-audio-record.c.

Referenced by main().

◆ os

ogg_stream_state os
static

Ogg muxer state.

Definition at line 244 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 249 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 254 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 261 of file gnunet-helper-audio-record.c.

Referenced by main(), and write_page().