source: roaraudio/plugins/gstreamer0.10/roarsink.c @ 4708:c9d40761088a

Last change on this file since 4708:c9d40761088a was 4708:c9d40761088a, checked in by phi, 13 years ago

updated copyright statements

File size: 15.5 KB
Line 
1//roarsink.c:
2/* GStreamer
3 * Copyright (C) <2005>      Arwed v. Merkatz <v.merkatz@gmx.net>
4 * Copyright (C) <2008-2011> Philipp 'ph3-der-loewe' Schafft
5 *                            <lion@lion.leolix.org>
6 *
7 * Roughly based on the gstreamer 0.8 esdsink plugin:
8 * Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.org>
9 *
10 * roarsink.c: an RoarAudio audio sink
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02111-1307, USA.
26 */
27
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "roarsink.h"
34#include <unistd.h>
35#include <errno.h>
36
37#define _(x) (x)
38
39//#include <gst/gst-i18n-plugin.h>
40
41#ifndef ROAR_MAX_WRITE_SIZE
42#define ROAR_MAX_WRITE_SIZE (21 * 4096)
43#endif
44#define ROAR_BUF_SIZE 1764 /* this is dynamic for RoarAudio, use the most common value here for the moment */
45
46//GST_DEBUG_CATEGORY_EXTERN (roar_debug);
47//#define GST_CAT_DEFAULT roar_debug
48
49/* elementfactory information */
50static const GstElementDetails roarsink_details =
51GST_ELEMENT_DETAILS("RoarAudio audio sink",
52    "Sink/Audio",
53    "Plays audio to an RoarAudio server",
54    "Philipp 'ph3-der-loewe' Schafft <lion@lion.leolix.org>");
55
56enum
57{
58  PROP_0,
59  PROP_HOST,
60  PROP_ROLE,
61  PROP_VOLUME,
62  PROP_MUTE
63};
64
65#define _QM(x) #x
66#define  QM(x) _QM(x)
67
68static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE("sink",
69    GST_PAD_SINK,
70    GST_PAD_ALWAYS,
71    GST_STATIC_CAPS(
72        "audio/x-alaw, "
73        "rate = (int) [ 1, MAX ], "
74        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
75
76        "audio/x-mulaw, "
77        "rate = (int) [ 1, MAX ], "
78        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
79
80//        "audio/x-flac; "
81
82        "audio/x-gsm; "
83
84//        "application/ogg; "
85
86//        "audio/x-wav; "
87
88/*
89        "audio/x-raw-int, "
90        "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
91        "signed = (boolean) { true, false }, "
92        "width = (int) 32, "
93        "depth = (int) 32, "
94        "rate = (int) [ 1, MAX ], "
95        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
96*/
97
98/*
99        "audio/x-raw-int, "
100        "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
101        "signed = (boolean) { true, false }, "
102        "width = (int) 24, "
103        "depth = (int) 24, "
104        "rate = (int) [ 1, MAX ], "
105        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
106*/
107
108        "audio/x-raw-int, "
109        "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
110        "signed = (boolean) { true, false }, "
111        "width = (int) 16, "
112        "depth = (int) 16, "
113        "rate = (int) [ 1, MAX ], "
114        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
115
116        "audio/x-raw-int, "
117        "signed = (boolean) { true, false }, "
118        "width = (int) 8, "
119        "depth = (int) 8, "
120        "rate = (int) [ 1, MAX ], "
121        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]"
122       )
123    );
124
125#undef _QM
126#undef  QM
127
128static void gst_roarsink_finalize (GObject * object);
129
130static GstCaps *gst_roarsink_getcaps (GstBaseSink * bsink);
131
132static gboolean gst_roarsink_open (GstAudioSink * asink);
133static gboolean gst_roarsink_close (GstAudioSink * asink);
134static gboolean gst_roarsink_prepare (GstAudioSink * asink,
135    GstRingBufferSpec * spec);
136static gboolean gst_roarsink_unprepare (GstAudioSink * asink);
137static guint gst_roarsink_write (GstAudioSink * asink, gpointer data,
138    guint length);
139static guint gst_roarsink_delay (GstAudioSink * asink);
140static void gst_roarsink_reset (GstAudioSink * asink);
141
142static void gst_roarsink_set_property (GObject * object, guint prop_id,
143    const GValue * value, GParamSpec * pspec);
144static void gst_roarsink_get_property (GObject * object, guint prop_id,
145    GValue * value, GParamSpec * pspec);
146
147GST_BOILERPLATE (GstRoarSink, gst_roarsink, GstAudioSink, GST_TYPE_AUDIO_SINK);
148
149static void gst_roarsink_base_init (gpointer g_class) {
150  GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
151
152  gst_element_class_add_pad_template(element_class,
153      gst_static_pad_template_get(&sink_factory));
154  gst_element_class_set_details(element_class, &roarsink_details);
155}
156
157static void gst_roarsink_class_init (GstRoarSinkClass * klass) {
158  GObjectClass *gobject_class;
159  GstBaseSinkClass *gstbasesink_class;
160  GstBaseAudioSinkClass *gstbaseaudiosink_class;
161  GstAudioSinkClass *gstaudiosink_class;
162
163  gobject_class          = (GObjectClass *) klass;
164  gstbasesink_class      = (GstBaseSinkClass *) klass;
165  gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
166  gstaudiosink_class     = (GstAudioSinkClass *) klass;
167
168  parent_class = g_type_class_peek_parent(klass);
169
170  gobject_class->finalize = gst_roarsink_finalize;
171
172  gstbasesink_class->get_caps   = GST_DEBUG_FUNCPTR(gst_roarsink_getcaps);
173
174  gstaudiosink_class->open      = GST_DEBUG_FUNCPTR(gst_roarsink_open);
175  gstaudiosink_class->close     = GST_DEBUG_FUNCPTR(gst_roarsink_close);
176  gstaudiosink_class->prepare   = GST_DEBUG_FUNCPTR(gst_roarsink_prepare);
177  gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR(gst_roarsink_unprepare);
178  gstaudiosink_class->write     = GST_DEBUG_FUNCPTR(gst_roarsink_write);
179  gstaudiosink_class->delay     = GST_DEBUG_FUNCPTR(gst_roarsink_delay);
180  gstaudiosink_class->reset     = GST_DEBUG_FUNCPTR(gst_roarsink_reset);
181
182  gobject_class->set_property   = gst_roarsink_set_property;
183  gobject_class->get_property   = gst_roarsink_get_property;
184
185  /* default value is filled in the _init method */
186  g_object_class_install_property(gobject_class, PROP_HOST,
187      g_param_spec_string("host", "Host",
188          "The server/host running the RoarAudio daemon", NULL, G_PARAM_READWRITE));
189  g_object_class_install_property(gobject_class, PROP_HOST,
190      g_param_spec_string("server", "Server",
191          "The server/host running the RoarAudio daemon", NULL, G_PARAM_READWRITE));
192  g_object_class_install_property(gobject_class, PROP_ROLE,
193      g_param_spec_string("role", "Role",
194          "The stream role", NULL, G_PARAM_READWRITE));
195  g_object_class_install_property(gobject_class, PROP_VOLUME,
196      g_param_spec_float("volume", "Volume",
197          "The stream volume (0.0 to 1.0)", 0.0, 1.0, 1.0, G_PARAM_READWRITE));
198  g_object_class_install_property(gobject_class, PROP_MUTE,
199      g_param_spec_boolean("mute", "Mute",
200          "The mute state of the stream", FALSE, G_PARAM_READWRITE));
201}
202
203static void gst_roarsink_init (GstRoarSink * roarsink, GstRoarSinkClass * klass) {
204  roarsink->vss    = NULL;
205  roarsink->host   = NULL;
206  roarsink->role   = NULL;
207  roarsink->volume = -1;
208  roarsink->mute   = ROAR_VS_ASK;
209}
210
211static void gst_roarsink_finalize (GObject * object) {
212  GstRoarSink *roarsink = GST_ROARSINK(object);
213
214  gst_caps_replace(&roarsink->cur_caps, NULL);
215  if ( roarsink->host != NULL )
216   g_free(roarsink->host);
217  if ( roarsink->role != NULL )
218   g_free(roarsink->role);
219
220  G_OBJECT_CLASS(parent_class)->finalize(object);
221}
222
223static GstCaps * gst_roarsink_getcaps (GstBaseSink * bsink) {
224  GstRoarSink *roarsink;
225
226  roarsink = GST_ROARSINK(bsink);
227
228  /* no fd, we're done with the template caps */
229  if (roarsink->vss == NULL || roarsink->cur_caps == NULL) {
230    GST_LOG_OBJECT(roarsink, "getcaps called, returning template caps");
231    return NULL;
232  }
233
234  GST_LOG_OBJECT(roarsink, "returning %" GST_PTR_FORMAT, roarsink->cur_caps);
235
236  return gst_caps_ref(roarsink->cur_caps);
237}
238
239static gboolean gst_roarsink_open(GstAudioSink * asink) {
240  GstPadTemplate *pad_template;
241  GstRoarSink *roarsink;
242  gint i;
243  struct roar_stream oinfo;
244
245  roarsink = GST_ROARSINK(asink);
246
247  GST_DEBUG_OBJECT(roarsink, "open");
248
249  /* now try to connect to any existing/running sound daemons */
250  if ( (roarsink->vss = roar_vs_new(roarsink->host, "gstreamer client", NULL)) == NULL )
251    goto couldnt_connect;
252
253  if ( roar_server_oinfo(roar_vs_connection_obj(roarsink->vss, NULL), &oinfo) == -1 )
254    goto no_server_info;
255
256  GST_INFO_OBJECT(roarsink, "got server info rate: %i", oinfo.info.rate);
257
258  pad_template = gst_static_pad_template_get(&sink_factory);
259  roarsink->cur_caps = gst_caps_copy(gst_pad_template_get_caps(pad_template));
260
261  for (i = 0; i < roarsink->cur_caps->structs->len; i++) {
262    GstStructure *s;
263
264    s = gst_caps_get_structure(roarsink->cur_caps, i);
265    gst_structure_set(s, "rate", G_TYPE_INT, oinfo.info.rate, NULL);
266  }
267
268  GST_INFO_OBJECT(roarsink, "server caps: %" GST_PTR_FORMAT, roarsink->cur_caps);
269
270  return TRUE;
271
272  /* ERRORS */
273couldnt_connect:
274  {
275    GST_ELEMENT_ERROR(roarsink, RESOURCE, OPEN_WRITE,
276        (_("Could not establish connection to sound server")),
277        ("can't open connection to RoarAudio server"));
278    return FALSE;
279  }
280no_server_info:
281  {
282    GST_ELEMENT_ERROR(roarsink, RESOURCE, OPEN_WRITE,
283        (_("Failed to query sound server capabilities")),
284        ("couldn't get server info!"));
285    return FALSE;
286  }
287}
288
289static gboolean gst_roarsink_close (GstAudioSink * asink) {
290  GstRoarSink *roarsink = GST_ROARSINK(asink);
291
292  GST_DEBUG_OBJECT(roarsink, "close");
293
294  gst_caps_replace(&roarsink->cur_caps, NULL);
295
296  roar_vs_close(roarsink->vss, ROAR_VS_FALSE, NULL);
297  roarsink->vss = NULL;
298
299  return TRUE;
300}
301
302static gboolean gst_roarsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) {
303  GstRoarSink *roarsink = GST_ROARSINK(asink);
304  struct roar_audio_info info;
305
306  info.codec    = ROAR_CODEC_DEFAULT;
307  info.bits     = spec->depth;
308  info.rate     = spec->rate;
309  info.channels = spec->channels;
310
311  GST_DEBUG_OBJECT(roarsink, "prepare");
312
313 
314  GST_INFO_OBJECT(roarsink, "attempting to open data connection to RoarAudio server");
315
316  switch (spec->type) {
317   case GST_BUFTYPE_LINEAR:
318     switch (spec->sign) {
319      case TRUE:
320        switch (spec->bigend) {
321         case TRUE:  info.codec = ROAR_CODEC_PCM_S_BE; break;
322         case FALSE: info.codec = ROAR_CODEC_PCM_S_LE; break;
323         default: return FALSE; break;
324        }
325       break;
326      case FALSE:
327        switch (spec->bigend) {
328         case TRUE:  info.codec = ROAR_CODEC_PCM_U_BE; break;
329         case FALSE: info.codec = ROAR_CODEC_PCM_U_LE; break;
330         default: return FALSE; break;
331        }
332       break;
333      default: return FALSE; break;
334     }
335    break;
336   case GST_BUFTYPE_A_LAW:
337     info.codec = ROAR_CODEC_ALAW;
338     info.bits  = 8;
339    break;
340   case GST_BUFTYPE_MU_LAW:
341     info.codec = ROAR_CODEC_MULAW;
342     info.bits  = 8;
343    break;
344   case GST_BUFTYPE_GSM:
345     info.codec = ROAR_CODEC_GSM;
346     info.bits  = 0;
347    break;
348   default:
349     return FALSE;
350  }
351
352  if ( roar_vs_stream(roarsink->vss, &info, ROAR_DIR_PLAY, NULL) == -1 )
353    goto cannot_open;
354
355  // apply parameters:
356  if ( roarsink->mute != ROAR_VS_ASK && roar_vs_mute(roarsink->vss, roarsink->mute, NULL) == -1 ) {
357    goto cannot_open;
358  }
359  if ( roarsink->volume >= 0.0 && roar_vs_volume_mono(roarsink->vss, roarsink->volume, NULL) == -1 ) {
360    goto cannot_open;
361  }
362
363  /* get server info */
364  spec->segsize  = ROAR_BUF_SIZE;
365  spec->segtotal = (ROAR_MAX_WRITE_SIZE / spec->segsize);
366
367  /* FIXME: this is wrong for signed ints (and the
368   * audioringbuffers should do it for us anyway) */
369  spec->bytes_per_sample = roar_info2framesize(&info) / 8;
370  memset(&(spec->silence_sample), 0, sizeof(spec->silence_sample));
371
372  GST_INFO_OBJECT(roarsink, "successfully opened connection to RoarAudio server");
373
374  return TRUE;
375
376  /* ERRORS */
377cannot_open:
378  {
379    GST_ELEMENT_ERROR(roarsink, RESOURCE, OPEN_WRITE,
380        (_("Could not establish connection to sound server")),
381        ("can't open connection to RoarAudio server"));
382    return FALSE;
383  }
384}
385
386static gboolean gst_roarsink_unprepare (GstAudioSink * asink) {
387  GstRoarSink *roarsink = GST_ROARSINK(asink);
388
389  if (roarsink->vss == NULL)
390    return TRUE;
391
392  roar_vs_close(roarsink->vss, ROAR_VS_FALSE, NULL);
393  roarsink->vss = NULL;
394
395  GST_INFO_OBJECT(roarsink, "closed sound device");
396
397  return TRUE;
398}
399
400
401static guint gst_roarsink_write (GstAudioSink * asink, gpointer data, guint length) {
402  GstRoarSink *roarsink = GST_ROARSINK(asink);
403  gint to_write = 0;
404
405  to_write = length;
406
407  while (to_write > 0) {
408    ssize_t done;
409
410    done = roar_vs_write(roarsink->vss, data, to_write, NULL);
411
412    if (done < 0)
413      goto write_error;
414
415    to_write -= done;
416    data += done;
417  }
418  return length;
419
420  /* ERRORS */
421write_error:
422  {
423    GST_ELEMENT_ERROR(roarsink, RESOURCE, WRITE,
424        ("Failed to write data to the RoarAudio daemon"), GST_ERROR_SYSTEM);
425    return 0;
426  }
427}
428
429static guint gst_roarsink_delay (GstAudioSink * asink) {
430//  GstRoarSink *roarsink = GST_ROARSINK (asink);
431  guint latency;
432
433  latency = 441; // compile type depending and link level deppendent,
434                 // use default value for local operations here for the moment
435
436  GST_DEBUG_OBJECT(asink, "got latency: %u", latency);
437
438  return latency;
439}
440
441static void gst_roarsink_reset (GstAudioSink * asink) {
442  GST_DEBUG_OBJECT(asink, "reset called");
443}
444
445static void gst_roarsink_set_property (GObject * object, guint prop_id, const GValue * value,
446                                       GParamSpec * pspec) {
447  GstRoarSink *roarsink = GST_ROARSINK(object);
448
449  switch (prop_id) {
450    case PROP_HOST:
451      if ( roarsink->host != NULL )
452       g_free(roarsink->host);
453      roarsink->host = g_value_dup_string(value);
454     break;
455    case PROP_ROLE:
456      if ( roarsink->role != NULL )
457       g_free(roarsink->role);
458      roarsink->role = g_value_dup_string(value);
459     break;
460    case PROP_VOLUME:
461      roarsink->volume = (float)g_value_get_float(value);
462
463      if ( roarsink->vss == NULL )
464       return;
465
466      roar_vs_volume_mono(roarsink->vss, roarsink->volume, NULL);
467     break;
468    case PROP_MUTE:
469      if ( g_value_get_boolean(value) ) {
470       roarsink->mute = ROAR_VS_TRUE;
471      } else {
472       roarsink->mute = ROAR_VS_FALSE;
473      }
474
475      if ( roarsink->vss == NULL )
476       return;
477
478      roar_vs_mute(roarsink->vss, roarsink->mute, NULL);
479     break;
480    default:
481      break;
482  }
483}
484
485static void gst_roarsink_get_property (GObject * object, guint prop_id, GValue * value,
486                                       GParamSpec * pspec) {
487  GstRoarSink *roarsink = GST_ROARSINK(object);
488  float l, r;
489  int ret;
490
491  switch (prop_id) {
492    case PROP_HOST:
493      g_value_set_string(value, roarsink->host);
494     break;
495    case PROP_ROLE:
496      g_value_set_string(value, roarsink->role);
497     break;
498    case PROP_VOLUME:
499      if ( roarsink->vss == NULL || roar_vs_volume_get(roarsink->vss, &l, &r, NULL) == -1 ) {
500       l = roarsink->volume >= 0.0 ? roarsink->volume : 1.0;
501      } else {
502       l = (l + r)/2;
503       roarsink->volume = l;
504      }
505      g_value_set_float(value, l);
506     break;
507    case PROP_MUTE:
508      if ( roarsink->vss == NULL || (ret = roar_vs_mute(roarsink->vss, ROAR_VS_ASK, NULL)) == -1 ) {
509       ret = roarsink->mute != ROAR_VS_ASK ? roarsink->mute : ROAR_VS_FALSE;
510      } else {
511       roarsink->mute = ret;
512      }
513
514      g_value_set_boolean(value, ret == ROAR_VS_TRUE ? TRUE : FALSE);
515     break;
516    default:
517      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
518     break;
519  }
520}
521
522gboolean gst_roarsink_factory_init (GstPlugin * plugin) {
523  if (!gst_element_register(plugin, "roarsink", GST_RANK_MARGINAL,
524                            GST_TYPE_ROARSINK))
525    return FALSE;
526
527  return TRUE;
528}
Note: See TracBrowser for help on using the repository browser.