GNUnet  0.10.x
Macros | Functions | Variables
gnunet-helper-audio-playback-gst.c File Reference

program to playback audio data to the speaker (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/audio/gstaudiobasesrc.h>
#include <gst/app/gstappsrc.h>
#include <glib.h>
Include dependency graph for gnunet-helper-audio-playback-gst.c:

Go to the source code of this file.

Macros

#define DEBUG_READ_PURE_OGG   1
 
#define MAXLINE   4096
 How much data to read in one go. More...
 
#define BUFFER_TIME   1000
 Max number of microseconds to buffer in audiosink. More...
 
#define LATENCY_TIME   1000
 Min number of microseconds to buffer in audiosink. More...
 

Functions

static void sink_child_added (GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
 
static void ogg_pad_added (GstElement *element, GstPad *pad, gpointer data)
 
static void quit ()
 
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
 
static void signalhandler (int s)
 
static int feed_buffer_to_gst (const char *audio, size_t b_len)
 
static int stdin_receiver (void *cls, const struct GNUNET_MessageHeader *msg)
 Message callback. More...
 
int main (int argc, char **argv)
 

Variables

struct GNUNET_MessageStreamTokenizerstdin_mst
 Tokenizer for the data we get from stdin. More...
 
static GstElement * pipeline
 Main pipeline. More...
 
static GstElement * source
 Appsrc instance into which we write data for the pipeline. More...
 
static GstElement * demuxer
 
static GstElement * decoder
 
static GstElement * conv
 
static GstElement * resampler
 
static GstElement * sink
 
static int abort_read
 Set to 1 to break the reading loop. More...
 

Detailed Description

program to playback audio data to the speaker (GStreamer version)

Author
LRN

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

Macro Definition Documentation

◆ DEBUG_READ_PURE_OGG

#define DEBUG_READ_PURE_OGG   1

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

◆ MAXLINE

#define MAXLINE   4096

How much data to read in one go.

Definition at line 42 of file gnunet-helper-audio-playback-gst.c.

Referenced by gnunet_read(), and main().

◆ BUFFER_TIME

#define BUFFER_TIME   1000

Max number of microseconds to buffer in audiosink.

Default is 1000

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

Referenced by autoaudiosink_child_added(), autoaudiosource_child_added(), get_audiobin(), and sink_child_added().

◆ LATENCY_TIME

#define LATENCY_TIME   1000

Min number of microseconds to buffer in audiosink.

Default is 1000

Definition at line 54 of file gnunet-helper-audio-playback-gst.c.

Referenced by autoaudiosink_child_added(), autoaudiosource_child_added(), get_audiobin(), and sink_child_added().

Function Documentation

◆ sink_child_added()

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

Definition at line 84 of file gnunet-helper-audio-playback-gst.c.

References BUFFER_TIME, and LATENCY_TIME.

Referenced by main().

88 {
89  if (GST_IS_AUDIO_BASE_SRC (object))
90  g_object_set (object,
91  "buffer-time", (gint64) BUFFER_TIME,
92  "latency-time", (gint64) LATENCY_TIME,
93  NULL);
94 }
#define LATENCY_TIME
Min number of microseconds to buffer in audiosink.
#define BUFFER_TIME
Max number of microseconds to buffer in audiosink.
Here is the caller graph for this function:

◆ ogg_pad_added()

static void ogg_pad_added ( GstElement *  element,
GstPad *  pad,
gpointer  data 
)
static

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

References conv, decoder, resampler, and sink.

Referenced by main().

101 {
102  GstPad *sinkpad;
103  GstElement *decoder = (GstElement *) data;
104 
105  /* We can now link this pad with the opus-decoder sink pad */
106  sinkpad = gst_element_get_static_pad (decoder, "sink");
107 
108  gst_pad_link (pad, sinkpad);
109 
110  gst_element_link_many (decoder, conv, resampler, sink, NULL);
111 
112  gst_object_unref (sinkpad);
113 }
static GstElement * resampler
static GstElement * conv
static GstElement * sink
static GstElement * decoder
uint32_t data
The data value.
Here is the caller graph for this function:

◆ quit()

static void quit ( )
static

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

References abort_read, pipeline, and source.

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

118 {
119  if (NULL != source)
120  gst_app_src_end_of_stream (GST_APP_SRC (source));
121  if (NULL != pipeline)
122  gst_element_set_state (pipeline, GST_STATE_NULL);
123  abort_read = 1;
124 }
static GstElement * pipeline
Main pipeline.
static GstElement * source
Appsrc instance into which we write data for the pipeline.
static int abort_read
Set to 1 to break the reading loop.
Here is the caller graph for this function:

◆ bus_call()

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

Definition at line 128 of file gnunet-helper-audio-playback-gst.c.

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

Referenced by main().

129 {
131  "Bus message\n");
132  switch (GST_MESSAGE_TYPE (msg))
133  {
134  case GST_MESSAGE_EOS:
136  "End of stream\n");
137  quit ();
138  break;
139 
140  case GST_MESSAGE_ERROR:
141  {
142  gchar *debug;
143  GError *error;
144 
145  gst_message_parse_error (msg, &error, &debug);
146  g_free (debug);
147 
149  "Error: %s\n",
150  error->message);
151  g_error_free (error);
152 
153  quit ();
154  break;
155  }
156  default:
157  break;
158  }
159 
160  return TRUE;
161 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static void quit()
#define GNUNET_log(kind,...)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ signalhandler()

static void signalhandler ( int  s)
static

Definition at line 165 of file gnunet-helper-audio-playback-gst.c.

References quit().

Referenced by main().

166 {
167  quit ();
168 }
static void quit()
Here is the call graph for this function:
Here is the caller graph for this function:

◆ feed_buffer_to_gst()

static int feed_buffer_to_gst ( const char *  audio,
size_t  b_len 
)
static

Definition at line 172 of file gnunet-helper-audio-playback-gst.c.

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_OK, GNUNET_SYSERR, and source.

Referenced by main(), and stdin_receiver().

173 {
174  GstBuffer *b;
175  gchar *bufspace;
176  GstFlowReturn flow;
177 
179  "Feeding %u bytes to GStreamer\n",
180  (unsigned int) b_len);
181 
182  bufspace = g_memdup (audio, b_len);
183  b = gst_buffer_new_wrapped (bufspace, b_len);
184  if (NULL == b)
185  {
187  "Failed to wrap a buffer\n");
188  g_free (bufspace);
189  return GNUNET_SYSERR;
190  }
191  flow = gst_app_src_push_buffer (GST_APP_SRC (source), b);
192  /* They all return GNUNET_OK, because currently player stops when
193  * data stops coming. This might need to be changed for the player
194  * to also stop when pipeline breaks.
195  */
196  switch (flow)
197  {
198  case GST_FLOW_OK:
200  "Fed %u bytes to the pipeline\n",
201  (unsigned int) b_len);
202  break;
203  case GST_FLOW_FLUSHING:
204  /* buffer was dropped, because pipeline state is not PAUSED or PLAYING */
206  "Dropped a buffer\n");
207  break;
208  case GST_FLOW_EOS:
209  /* end of stream */
211  "EOS\n");
212  break;
213  default:
215  "Unexpected push result\n");
216  break;
217  }
218  return GNUNET_OK;
219 }
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
static GstElement * source
Appsrc instance into which we write data for the pipeline.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
#define GNUNET_log(kind,...)
Here is the caller graph for this function:

◆ stdin_receiver()

static int stdin_receiver ( void *  cls,
const struct GNUNET_MessageHeader msg 
)
static

Message callback.

Parameters
msgmessage we received.
Returns
GNUNET_OK on success, GNUNET_NO to stop further processing due to disconnect (no error) GNUNET_SYSERR to stop further processing due to error

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

References feed_buffer_to_gst(), GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO, GNUNET_OK, AudioMessage::header, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by main().

233 {
234  struct AudioMessage *audio;
235  size_t b_len;
236 
237  switch (ntohs (msg->type))
238  {
240  audio = (struct AudioMessage *) msg;
241 
242  b_len = ntohs (audio->header.size) - sizeof (struct AudioMessage);
243  feed_buffer_to_gst ((const char *) &audio[1], b_len);
244  break;
245  default:
246  break;
247  }
248  return GNUNET_OK;
249 }
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO.
Definition: conversation.h:60
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
Message to transmit the audio (between client and helpers).
Definition: conversation.h:55
static int feed_buffer_to_gst(const char *audio, size_t b_len)
#define GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO
Message to transmit the audio between helper and speaker/microphone library.
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 253 of file gnunet-helper-audio-playback-gst.c.

References _, abort_read, bus_call(), conv, decoder, demuxer, feed_buffer_to_gst(), getenv(), GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_log_setup(), GNUNET_MST_create(), GNUNET_MST_destroy(), GNUNET_MST_from_buffer(), GNUNET_NO, GNUNET_OK, gst_element_factory_make, MAXLINE, ogg_pad_added(), pipeline, quit(), resampler, ret, signalhandler(), sink, sink_child_added(), source, and stdin_receiver().

254 {
255  GstBus *bus;
256  guint bus_watch_id;
257  uint64_t toff;
258 
259  typedef void (*SignalHandlerPointer) (int);
260 
261  SignalHandlerPointer inthandler, termhandler;
262 #ifdef DEBUG_READ_PURE_OGG
263  int read_pure_ogg = getenv ("GNUNET_READ_PURE_OGG") ? 1 : 0;
264 #endif
265 
266  inthandler = signal (SIGINT,
267  &signalhandler);
268  termhandler = signal (SIGTERM,
269  &signalhandler);
270 
271 #ifdef WINDOWS
272  setmode (0, _O_BINARY);
273 #endif
274 
275  /* Initialisation */
276  gst_init (&argc, &argv);
277 
279  GNUNET_log_setup ("gnunet-helper-audio-playback-gst",
280  "WARNING",
281  NULL));
282 
284  "Audio sink starts\n");
285 
287  NULL);
288 
289  /* Create gstreamer elements */
290  pipeline = gst_pipeline_new ("audio-player");
291  source = gst_element_factory_make ("appsrc", "audio-input");
292  demuxer = gst_element_factory_make ("oggdemux", "ogg-demuxer");
293  decoder = gst_element_factory_make ("opusdec", "opus-decoder");
294  conv = gst_element_factory_make ("audioconvert", "converter");
295  resampler= gst_element_factory_make ("audioresample", "resampler");
296  sink = gst_element_factory_make ("autoaudiosink", "audiosink");
297 
298  if (!pipeline || !source || !conv || !resampler || !decoder || !demuxer || !sink)
299  {
301  "One element could not be created. Exiting.\n");
302  return -1;
303  }
304 
305  g_signal_connect (sink,
306  "child-added",
307  G_CALLBACK (sink_child_added),
308  NULL);
309  g_signal_connect (demuxer,
310  "pad-added",
311  G_CALLBACK (ogg_pad_added),
312  decoder);
313 
314  /* Keep a reference to it, we operate on it */
315  gst_object_ref (GST_OBJECT (source));
316 
317  /* Set up the pipeline */
318 
319  /* we feed appsrc as fast as possible, it just blocks when it's full */
320  g_object_set (G_OBJECT (source),
321 /* "format", GST_FORMAT_TIME,*/
322  "block", TRUE,
323  "is-live", TRUE,
324  NULL);
325 
326  g_object_set (G_OBJECT (decoder),
327 /* "plc", FALSE,*/
328 /* "apply-gain", TRUE,*/
329  "use-inband-fec", TRUE,
330  NULL);
331 
332  /* we add a message handler */
333  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
334  bus_watch_id = gst_bus_add_watch (bus, bus_call, pipeline);
335  gst_object_unref (bus);
336 
337  /* we add all elements into the pipeline */
338  /* audio-input | ogg-demuxer | opus-decoder | converter | resampler | audiosink */
339  gst_bin_add_many (GST_BIN (pipeline), source, demuxer, decoder, conv,
340  resampler, sink, NULL);
341 
342  /* we link the elements together */
343  gst_element_link_many (source, demuxer, NULL);
344 
345  /* Set the pipeline to "playing" state*/
346  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now playing\n");
347  gst_element_set_state (pipeline, GST_STATE_PLAYING);
348 
349  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running...\n");
350  /* Iterate */
351  toff = 0;
352  while (!abort_read)
353  {
354  char readbuf[MAXLINE];
355  int ret;
356 
357  ret = read (0, readbuf, sizeof (readbuf));
358  if (0 > ret)
359  {
361  _("Read error from STDIN: %d %s\n"),
362  ret, strerror (errno));
363  break;
364  }
365  toff += ret;
367  "Received %d bytes of audio data (total: %llu)\n",
368  (int) ret,
369  (unsigned long long) toff);
370  if (0 == ret)
371  break;
372 #ifdef DEBUG_READ_PURE_OGG
373  if (read_pure_ogg)
374  {
375  feed_buffer_to_gst (readbuf, ret);
376  }
377  else
378 #endif
380  readbuf,
381  ret,
382  GNUNET_NO,
383  GNUNET_NO);
384  }
386 
387  signal (SIGINT, inthandler);
388  signal (SIGINT, termhandler);
389 
391  "Returned, stopping playback\n");
392  quit ();
393 
395  "Deleting pipeline\n");
396  gst_object_unref (GST_OBJECT (source));
397  source = NULL;
398  gst_object_unref (GST_OBJECT (pipeline));
399  pipeline = NULL;
400  g_source_remove (bus_watch_id);
401 
402  return 0;
403 }
static GstElement * resampler
static void ogg_pad_added(GstElement *element, GstPad *pad, gpointer data)
static GstElement * conv
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static GstElement * pipeline
Main pipeline.
struct GNUNET_MessageStreamTokenizer * stdin_mst
Tokenizer for the data we get from stdin.
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static GstElement * sink
#define MAXLINE
How much data to read in one go.
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:413
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:87
int GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition: mst.c:116
#define gst_element_factory_make(element, name)
Definition: gnunet_gst.h:36
static void signalhandler(int s)
static void quit()
static GstElement * source
Appsrc instance into which we write data for the pipeline.
static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
static GstElement * demuxer
char * getenv()
static int abort_read
Set to 1 to break the reading loop.
static void sink_child_added(GstChildProxy *child_proxy, GObject *object, gchar *name, gpointer user_data)
static int feed_buffer_to_gst(const char *audio, size_t b_len)
#define GNUNET_log(kind,...)
static int stdin_receiver(void *cls, const struct GNUNET_MessageHeader *msg)
Message callback.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
static GstElement * decoder
Here is the call graph for this function:

Variable Documentation

◆ stdin_mst

struct GNUNET_MessageStreamTokenizer* stdin_mst

Tokenizer for the data we get from stdin.

Definition at line 59 of file gnunet-helper-audio-playback-gst.c.

Referenced by main().

◆ pipeline

GstElement* pipeline
static

Main pipeline.

Definition at line 64 of file gnunet-helper-audio-playback-gst.c.

Referenced by main(), and quit().

◆ source

GstElement* source
static

Appsrc instance into which we write data for the pipeline.

Definition at line 69 of file gnunet-helper-audio-playback-gst.c.

Referenced by channel_new_cb(), feed_buffer_to_gst(), get_audiobin(), main(), and quit().

◆ demuxer

GstElement* demuxer
static

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

Referenced by get_coder(), and main().

◆ decoder

GstElement* decoder
static

◆ conv

GstElement* conv
static

◆ resampler

GstElement* resampler
static

Definition at line 74 of file gnunet-helper-audio-playback-gst.c.

Referenced by get_audiobin(), main(), and ogg_pad_added().

◆ sink

GstElement* sink
static

Definition at line 75 of file gnunet-helper-audio-playback-gst.c.

Referenced by get_audiobin(), main(), and ogg_pad_added().

◆ abort_read

int abort_read
static

Set to 1 to break the reading loop.

Definition at line 80 of file gnunet-helper-audio-playback-gst.c.

Referenced by main(), and quit().