GNUnet 0.21.2
gnunet-helper-audio-record-gst.c File Reference

program to record audio data from the microphone (GStreamer version) 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 <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <gst/audio/gstaudiobasesrc.h>
#include <glib.h>
Include dependency graph for gnunet-helper-audio-record-gst.c:

Go to the source code of this file.

Macros

#define DEBUG_RECORD_PURE_OGG   1
 
#define OPUS_CHANNELS   1
 Number of channels. More...
 
#define MAX_PAYLOAD_SIZE   (1024 / OPUS_CHANNELS)
 Maximal size of a single opus packet. More...
 
#define OPUS_FRAME_SIZE   40
 Size of a single frame fed to the encoder, in ms. More...
 
#define PACKET_LOSS_PERCENTAGE   1
 Expected packet loss to prepare for, in percents. More...
 
#define INBAND_FEC_MODE   1
 Set to 1 to enable forward error correction. More...
 
#define BUFFER_TIME   1000 /* 1ms */
 Max number of microseconds to buffer in audiosource. More...
 
#define LATENCY_TIME   1000 /* 1ms */
 Min number of microseconds to buffer in audiosource. More...
 
#define OGG_MAX_DELAY   0
 Maximum delay in multiplexing streams, in ns. More...
 
#define OGG_MAX_PAGE_DELAY   0
 Maximum delay for sending out a page, in ns. More...
 

Functions

static void quit ()
 
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
 
void source_child_added (GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
 
static void signalhandler (int s)
 
int main (int argc, char **argv)
 

Variables

static GstElement * pipeline
 Main pipeline. More...
 
static int dump_pure_ogg
 

Detailed Description

program to record audio data from the microphone (GStreamer version)

Author
LRN

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

Macro Definition Documentation

◆ DEBUG_RECORD_PURE_OGG

#define DEBUG_RECORD_PURE_OGG   1

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

◆ OPUS_CHANNELS

#define OPUS_CHANNELS   1

Number of channels.

Must be one of the following (from libopusenc documentation): 1, 2

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

◆ MAX_PAYLOAD_SIZE

#define MAX_PAYLOAD_SIZE   (1024 / OPUS_CHANNELS)

Maximal size of a single opus packet.

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

◆ OPUS_FRAME_SIZE

#define OPUS_FRAME_SIZE   40

Size of a single frame fed to the encoder, in ms.

Must be one of the following (from libopus documentation): 2.5, 5, 10, 20, 40 or 60

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

◆ PACKET_LOSS_PERCENTAGE

#define PACKET_LOSS_PERCENTAGE   1

Expected packet loss to prepare for, in percents.

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

◆ INBAND_FEC_MODE

#define INBAND_FEC_MODE   1

Set to 1 to enable forward error correction.

Set to 0 to disable.

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

◆ BUFFER_TIME

#define BUFFER_TIME   1000 /* 1ms */

Max number of microseconds to buffer in audiosource.

Default is 200000

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

◆ LATENCY_TIME

#define LATENCY_TIME   1000 /* 1ms */

Min number of microseconds to buffer in audiosource.

Default is 10000

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

◆ OGG_MAX_DELAY

#define OGG_MAX_DELAY   0

Maximum delay in multiplexing streams, in ns.

Setting this to 0 forces page flushing, which decreases delay, but increases overhead.

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

◆ OGG_MAX_PAGE_DELAY

#define OGG_MAX_PAGE_DELAY   0

Maximum delay for sending out a page, in ns.

Setting this to 0 forces page flushing, which decreases delay, but increases overhead.

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

Function Documentation

◆ quit()

static void quit ( )
static

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

106{
107 if (NULL != pipeline)
108 gst_element_set_state (pipeline, GST_STATE_NULL);
109}
static GstElement * pipeline
Main pipeline.

References pipeline.

Referenced by bus_call(), main(), and signalhandler().

Here is the caller graph for this function:

◆ bus_call()

static gboolean bus_call ( GstBus *  bus,
GstMessage *  msg,
gpointer  data 
)
static

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

114{
115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bus message\n");
116 switch (GST_MESSAGE_TYPE (msg))
117 {
118 case GST_MESSAGE_EOS:
119 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "End of stream\n");
120 quit ();
121 break;
122
123 case GST_MESSAGE_ERROR:
124 {
125 gchar *debug;
126 GError *error;
127
128 gst_message_parse_error (msg, &error, &debug);
129 g_free (debug);
130
131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error: %s\n", error->message);
132 g_error_free (error);
133
134 quit ();
135 break;
136 }
137
138 default:
139 break;
140 }
141
142 return TRUE;
143}
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static void quit()
#define GNUNET_log(kind,...)
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO

References find_typedefs::debug, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_log, msg, and quit().

Referenced by main().

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

◆ source_child_added()

void source_child_added ( GstChildProxy *  child_proxy,
GObject *  object,
gchar *  name,
gpointer  user_data 
)

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

149{
150 if (GST_IS_AUDIO_BASE_SRC (object))
151 g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time",
152 (gint64) LATENCY_TIME, NULL);
153}
#define LATENCY_TIME
Min number of microseconds to buffer in audiosource.
#define BUFFER_TIME
Max number of microseconds to buffer in audiosource.

References BUFFER_TIME, and LATENCY_TIME.

Referenced by main().

Here is the caller graph for this function:

◆ signalhandler()

static void signalhandler ( int  s)
static

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

158{
159 quit ();
160}

References quit().

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 
)

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

165{
166 GstElement *source, *filter, *encoder, *conv, *resampler, *sink, *oggmux;
167 GstCaps *caps;
168 GstBus *bus;
169 guint bus_watch_id;
171 int abort_send = 0;
172
173 typedef void (*SignalHandlerPointer) (int);
174
175 SignalHandlerPointer inthandler, termhandler;
176 inthandler = signal (SIGINT, signalhandler);
177 termhandler = signal (SIGTERM, signalhandler);
178
179#ifdef DEBUG_RECORD_PURE_OGG
180 dump_pure_ogg = getenv ("GNUNET_RECORD_PURE_OGG") ? 1 : 0;
181#endif
182
183 /* Initialisation */
184 gst_init (&argc, &argv);
185
187 GNUNET_log_setup ("gnunet-helper-audio-record",
188 "WARNING",
189 NULL));
190
192 "Audio source starts\n");
193
195
196 /* Create gstreamer elements */
197 pipeline = gst_pipeline_new ("audio-recorder");
198 source = gst_element_factory_make ("autoaudiosrc", "audiosource");
199 filter = gst_element_factory_make ("capsfilter", "filter");
200 conv = gst_element_factory_make ("audioconvert", "converter");
201 resampler = gst_element_factory_make ("audioresample", "resampler");
202 encoder = gst_element_factory_make ("opusenc", "opus-encoder");
203 oggmux = gst_element_factory_make ("oggmux", "ogg-muxer");
204 sink = gst_element_factory_make ("appsink", "audio-output");
205
206 if (! pipeline || ! filter || ! source || ! conv || ! resampler ||
207 ! encoder || ! oggmux || ! sink)
208 {
210 "One element could not be created. Exiting.\n");
211 return -1;
212 }
213
214 g_signal_connect (source, "child-added", G_CALLBACK (source_child_added),
215 NULL);
216
217 /* Set up the pipeline */
218
219 caps = gst_caps_new_simple ("audio/x-raw",
220 "format", G_TYPE_STRING, "S16LE",
221/* "rate", G_TYPE_INT, SAMPLING_RATE,*/
222 "channels", G_TYPE_INT, OPUS_CHANNELS,
223/* "layout", G_TYPE_STRING, "interleaved",*/
224 NULL);
225 g_object_set (G_OBJECT (filter),
226 "caps", caps,
227 NULL);
228 gst_caps_unref (caps);
229
230 g_object_set (G_OBJECT (encoder),
231/* "bitrate", 64000, */
232/* "bandwidth", OPUS_BANDWIDTH_FULLBAND, */
233 "inband-fec", INBAND_FEC_MODE,
234 "packet-loss-percentage", PACKET_LOSS_PERCENTAGE,
235 "max-payload-size", MAX_PAYLOAD_SIZE,
236 "audio", FALSE, /* VoIP, not audio */
237 "frame-size", OPUS_FRAME_SIZE,
238 NULL);
239
240 g_object_set (G_OBJECT (oggmux),
241 "max-delay", OGG_MAX_DELAY,
242 "max-page-delay", OGG_MAX_PAGE_DELAY,
243 NULL);
244
245 /* we add a message handler */
246 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
247 bus_watch_id = gst_bus_add_watch (bus, bus_call, pipeline);
248 gst_object_unref (bus);
249
250 /* we add all elements into the pipeline */
251 /* audiosource | converter | resampler | opus-encoder | audio-output */
252 gst_bin_add_many (GST_BIN (pipeline), source, filter, conv, resampler,
253 encoder,
254 oggmux, sink, NULL);
255
256 /* we link the elements together */
257 gst_element_link_many (source, filter, conv, resampler, encoder, oggmux, sink,
258 NULL);
259
260 /* Set the pipeline to "playing" state*/
261 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now playing\n");
262 gst_element_set_state (pipeline, GST_STATE_PLAYING);
263
264
265 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running...\n");
266 /* Iterate */
267 while (! abort_send)
268 {
269 GstSample *s;
270 GstBuffer *b;
271 GstMapInfo m;
272 size_t len, msg_size;
273 const char *ptr;
274 int phase;
275
276 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulling...\n");
277 s = gst_app_sink_pull_sample (GST_APP_SINK (sink));
278 if (NULL == s)
279 {
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pulled NULL\n");
281 break;
282 }
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "...pulled!\n");
284 {
285 const GstStructure *si;
286 char *si_str;
287 GstCaps *s_caps;
288 char *caps_str;
289 si = gst_sample_get_info (s);
290 if (si)
291 {
292 si_str = gst_structure_to_string (si);
293 if (si_str)
294 {
295 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample %s\n", si_str);
296 g_free (si_str);
297 }
298 }
299 else
300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no info\n");
301 s_caps = gst_sample_get_caps (s);
302 if (s_caps)
303 {
304 caps_str = gst_caps_to_string (s_caps);
305 if (caps_str)
306 {
307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with caps %s\n",
308 caps_str);
309 g_free (caps_str);
310 }
311 }
312 else
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got sample with no caps\n");
314 }
315 b = gst_sample_get_buffer (s);
316 if ((NULL == b) || ! gst_buffer_map (b, &m, GST_MAP_READ))
317 {
319 "got NULL buffer %p or failed to map the buffer\n", b);
320 gst_sample_unref (s);
321 continue;
322 }
323
324 len = m.size;
325 if (len > UINT16_MAX - sizeof(struct AudioMessage))
326 {
327 GNUNET_break (0);
328 len = UINT16_MAX - sizeof(struct AudioMessage);
329 }
330 msg_size = sizeof(struct AudioMessage) + len;
331 audio_message.header.size = htons ((uint16_t) msg_size);
332
334 "Sending %u bytes of audio data\n", (unsigned int) msg_size);
335 for (phase = 0; phase < 2; phase++)
336 {
337 size_t offset;
338 size_t to_send;
339 ssize_t ret;
340 if (0 == phase)
341 {
342#ifdef DEBUG_RECORD_PURE_OGG
343 if (dump_pure_ogg)
344 continue;
345#endif
346 ptr = (const char *) &audio_message;
347 to_send = sizeof(audio_message);
348 }
349 else
350 {
351 ptr = (const char *) m.data;
352 to_send = len;
353 }
355 "Sending %u bytes on phase %d\n", (unsigned int) to_send,
356 phase);
357 for (offset = 0; offset < to_send; offset += ret)
358 {
359 ret = write (1, &ptr[offset], to_send - offset);
360 if (0 >= ret)
361 {
362 if (-1 == ret)
364 "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n",
365 (unsigned int) (to_send - offset),
366 (unsigned int) offset,
367 (unsigned int) (to_send + offset),
368 phase,
369 strerror (errno));
370 abort_send = 1;
371 break;
372 }
373 }
374 if (abort_send)
375 break;
376 }
377 gst_buffer_unmap (b, &m);
378 gst_sample_unref (s);
379 }
380
381 signal (SIGINT, inthandler);
382 signal (SIGINT, termhandler);
383
384 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returned, stopping playback\n");
385 quit ();
386
387 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Deleting pipeline\n");
388 gst_object_unref (GST_OBJECT (pipeline));
389 pipeline = NULL;
390 g_source_remove (bus_watch_id);
391
392 return 0;
393}
char * getenv()
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:104
static int ret
Final status code.
Definition: gnunet-arm.c:94
static unsigned int phase
Processing stage that we are in.
Definition: gnunet-arm.c:114
static GstElement * source
Appsrc instance into which we write data for the pipeline.
static GstElement * resampler
static GstElement * sink
static GstElement * conv
static int dump_pure_ogg
static void signalhandler(int s)
void source_child_added(GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
#define MAX_PAYLOAD_SIZE
Maximal size of a single opus packet.
#define OGG_MAX_DELAY
Maximum delay in multiplexing streams, in ns.
#define INBAND_FEC_MODE
Set to 1 to enable forward error correction.
#define OPUS_FRAME_SIZE
Size of a single frame fed to the encoder, in ms.
#define OGG_MAX_PAGE_DELAY
Maximum delay for sending out a page, in ns.
#define OPUS_CHANNELS
Number of channels.
static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
#define PACKET_LOSS_PERCENTAGE
Expected packet loss to prepare for, in percents.
static struct AudioMessage * audio_message
Audio message skeleton.
static struct GNUNET_CONTAINER_BloomFilter * filter
Bloomfilter to quickly tell if we don't have the content.
#define gst_element_factory_make(element, name)
Definition: gnunet_gst.h:36
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
#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.
enum GNUNET_GenericReturnValue 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.
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

References audio_message, bus_call(), conv, dump_pure_ogg, filter, getenv(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_log_setup(), GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO, GNUNET_OK, gst_element_factory_make, AudioMessage::header, INBAND_FEC_MODE, consensus-simulation::int, m, MAX_PAYLOAD_SIZE, OGG_MAX_DELAY, OGG_MAX_PAGE_DELAY, OPUS_CHANNELS, OPUS_FRAME_SIZE, PACKET_LOSS_PERCENTAGE, phase, pipeline, quit(), resampler, ret, signalhandler(), sink, GNUNET_MessageHeader::size, source, source_child_added(), and GNUNET_MessageHeader::type.

Here is the call graph for this function:

Variable Documentation

◆ pipeline

GstElement* pipeline
static

Main pipeline.

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

Referenced by main(), and quit().

◆ dump_pure_ogg

int dump_pure_ogg
static

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

Referenced by main().