source: roaraudio/plugins/gstreamer0.10/roarsink.c @ 4661:4da148f3eb1e

Last change on this file since 4661:4da148f3eb1e was 4661:4da148f3eb1e, checked in by phi, 13 years ago

updated copyright

File size: 12.9 KB
Line 
1//roarsink.c:
2/* GStreamer
3 * Copyright (C) <2005>      Arwed v. Merkatz <v.merkatz@gmx.net>
4 * Copyright (C) <2008-2010> 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};
61
62#define _QM(x) #x
63#define  QM(x) _QM(x)
64
65static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE("sink",
66    GST_PAD_SINK,
67    GST_PAD_ALWAYS,
68    GST_STATIC_CAPS(
69        "audio/x-alaw, "
70        "rate = (int) [ 1, MAX ], "
71        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
72
73        "audio/x-mulaw, "
74        "rate = (int) [ 1, MAX ], "
75        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
76
77/*
78        "audio/x-raw-int, "
79        "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
80        "signed = (boolean) { true, false }, "
81        "width = (int) 32, "
82        "depth = (int) 32, "
83        "rate = (int) [ 1, MAX ], "
84        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
85*/
86
87/*
88        "audio/x-raw-int, "
89        "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
90        "signed = (boolean) { true, false }, "
91        "width = (int) 24, "
92        "depth = (int) 24, "
93        "rate = (int) [ 1, MAX ], "
94        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
95*/
96
97        "audio/x-raw-int, "
98        "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
99        "signed = (boolean) { true, false }, "
100        "width = (int) 16, "
101        "depth = (int) 16, "
102        "rate = (int) [ 1, MAX ], "
103        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]; "
104
105        "audio/x-raw-int, "
106        "signed = (boolean) { true, false }, "
107        "width = (int) 8, "
108        "depth = (int) 8, "
109        "rate = (int) [ 1, MAX ], "
110        "channels = (int) [ 1, " QM(ROAR_MAX_CHANNELS) " ]"
111       )
112    );
113
114#undef _QM
115#undef  QM
116
117static void gst_roarsink_finalize (GObject * object);
118
119static GstCaps *gst_roarsink_getcaps (GstBaseSink * bsink);
120
121static gboolean gst_roarsink_open (GstAudioSink * asink);
122static gboolean gst_roarsink_close (GstAudioSink * asink);
123static gboolean gst_roarsink_prepare (GstAudioSink * asink,
124    GstRingBufferSpec * spec);
125static gboolean gst_roarsink_unprepare (GstAudioSink * asink);
126static guint gst_roarsink_write (GstAudioSink * asink, gpointer data,
127    guint length);
128static guint gst_roarsink_delay (GstAudioSink * asink);
129static void gst_roarsink_reset (GstAudioSink * asink);
130
131static void gst_roarsink_set_property (GObject * object, guint prop_id,
132    const GValue * value, GParamSpec * pspec);
133static void gst_roarsink_get_property (GObject * object, guint prop_id,
134    GValue * value, GParamSpec * pspec);
135
136GST_BOILERPLATE (GstRoarSink, gst_roarsink, GstAudioSink, GST_TYPE_AUDIO_SINK);
137
138static void gst_roarsink_base_init (gpointer g_class) {
139  GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
140
141  gst_element_class_add_pad_template(element_class,
142      gst_static_pad_template_get(&sink_factory));
143  gst_element_class_set_details(element_class, &roarsink_details);
144}
145
146static void gst_roarsink_class_init (GstRoarSinkClass * klass) {
147  GObjectClass *gobject_class;
148  GstBaseSinkClass *gstbasesink_class;
149  GstBaseAudioSinkClass *gstbaseaudiosink_class;
150  GstAudioSinkClass *gstaudiosink_class;
151
152  gobject_class          = (GObjectClass *) klass;
153  gstbasesink_class      = (GstBaseSinkClass *) klass;
154  gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
155  gstaudiosink_class     = (GstAudioSinkClass *) klass;
156
157  parent_class = g_type_class_peek_parent(klass);
158
159  gobject_class->finalize = gst_roarsink_finalize;
160
161  gstbasesink_class->get_caps   = GST_DEBUG_FUNCPTR(gst_roarsink_getcaps);
162
163  gstaudiosink_class->open      = GST_DEBUG_FUNCPTR(gst_roarsink_open);
164  gstaudiosink_class->close     = GST_DEBUG_FUNCPTR(gst_roarsink_close);
165  gstaudiosink_class->prepare   = GST_DEBUG_FUNCPTR(gst_roarsink_prepare);
166  gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR(gst_roarsink_unprepare);
167  gstaudiosink_class->write     = GST_DEBUG_FUNCPTR(gst_roarsink_write);
168  gstaudiosink_class->delay     = GST_DEBUG_FUNCPTR(gst_roarsink_delay);
169  gstaudiosink_class->reset     = GST_DEBUG_FUNCPTR(gst_roarsink_reset);
170
171  gobject_class->set_property   = gst_roarsink_set_property;
172  gobject_class->get_property   = gst_roarsink_get_property;
173
174  /* default value is filled in the _init method */
175  g_object_class_install_property(gobject_class, PROP_HOST,
176      g_param_spec_string("host", "Host",
177          "The host running the RoarAudio daemon", NULL, G_PARAM_READWRITE));
178}
179
180static void gst_roarsink_init (GstRoarSink * roarsink, GstRoarSinkClass * klass) {
181  memset(&(roarsink->con), 0, sizeof(roarsink->con));
182  roar_connect_fh(&(roarsink->con), -1);
183  roarsink->fd     = -1;
184  roarsink->host   = NULL;
185}
186
187static void gst_roarsink_finalize (GObject * object) {
188  GstRoarSink *roarsink = GST_ROARSINK(object);
189
190  gst_caps_replace(&roarsink->cur_caps, NULL);
191  if ( roarsink->host != NULL )
192   g_free(roarsink->host);
193
194  G_OBJECT_CLASS(parent_class)->finalize(object);
195}
196
197static GstCaps * gst_roarsink_getcaps (GstBaseSink * bsink) {
198  GstRoarSink *roarsink;
199
200  roarsink = GST_ROARSINK(bsink);
201
202  /* no fd, we're done with the template caps */
203  if (roar_get_connection_fh(&(roarsink->con)) < 0 || roarsink->cur_caps == NULL) {
204    GST_LOG_OBJECT(roarsink, "getcaps called, returning template caps");
205    return NULL;
206  }
207
208  GST_LOG_OBJECT(roarsink, "returning %" GST_PTR_FORMAT, roarsink->cur_caps);
209
210  return gst_caps_ref(roarsink->cur_caps);
211}
212
213static gboolean gst_roarsink_open(GstAudioSink * asink) {
214  GstPadTemplate *pad_template;
215  GstRoarSink *roarsink;
216  gint i;
217  struct roar_stream oinfo;
218
219  roarsink = GST_ROARSINK(asink);
220
221  GST_DEBUG_OBJECT(roarsink, "open");
222
223  /* now try to connect to any existing/running sound daemons */
224  if ( roar_simple_connect(&(roarsink->con), roarsink->host, "gstreamer client") == -1 )
225    goto couldnt_connect;
226
227  /* get server info */
228  if ( roar_server_oinfo(&(roarsink->con), &oinfo) == -1 )
229    goto no_server_info;
230
231  GST_INFO_OBJECT(roarsink, "got server info rate: %i", oinfo.info.rate);
232
233  pad_template = gst_static_pad_template_get(&sink_factory);
234  roarsink->cur_caps = gst_caps_copy(gst_pad_template_get_caps(pad_template));
235
236  for (i = 0; i < roarsink->cur_caps->structs->len; i++) {
237    GstStructure *s;
238
239    s = gst_caps_get_structure(roarsink->cur_caps, i);
240    gst_structure_set(s, "rate", G_TYPE_INT, oinfo.info.rate, NULL);
241  }
242
243  GST_INFO_OBJECT(roarsink, "server caps: %" GST_PTR_FORMAT, roarsink->cur_caps);
244
245  return TRUE;
246
247  /* ERRORS */
248couldnt_connect:
249  {
250    GST_ELEMENT_ERROR(roarsink, RESOURCE, OPEN_WRITE,
251        (_("Could not establish connection to sound server")),
252        ("can't open connection to RoarAudio server"));
253    return FALSE;
254  }
255no_server_info:
256  {
257    GST_ELEMENT_ERROR(roarsink, RESOURCE, OPEN_WRITE,
258        (_("Failed to query sound server capabilities")),
259        ("couldn't get server info!"));
260    return FALSE;
261  }
262}
263
264static gboolean gst_roarsink_close (GstAudioSink * asink) {
265  GstRoarSink *roarsink = GST_ROARSINK(asink);
266
267  GST_DEBUG_OBJECT(roarsink, "close");
268
269  gst_caps_replace(&roarsink->cur_caps, NULL);
270
271  roar_disconnect(&(roarsink->con));
272
273  if ( roarsink->fd != -1 )
274   close(roarsink->fd);
275
276  return TRUE;
277}
278
279static gboolean gst_roarsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) {
280  GstRoarSink *roarsink = GST_ROARSINK(asink);
281  int codec = ROAR_CODEC_DEFAULT;
282  int bits  = spec->depth;
283
284  GST_DEBUG_OBJECT(roarsink, "prepare");
285
286 
287  GST_INFO_OBJECT(roarsink, "attempting to open data connection to RoarAudio server");
288
289  switch (spec->type) {
290   case GST_BUFTYPE_LINEAR:
291     switch (spec->sign) {
292      case TRUE:
293        switch (spec->bigend) {
294         case TRUE:  codec = ROAR_CODEC_PCM_S_BE; break;
295         case FALSE: codec = ROAR_CODEC_PCM_S_LE; break;
296         default: return FALSE; break;
297        }
298       break;
299      case FALSE:
300        switch (spec->bigend) {
301         case TRUE:  codec = ROAR_CODEC_PCM_U_BE; break;
302         case FALSE: codec = ROAR_CODEC_PCM_U_LE; break;
303         default: return FALSE; break;
304        }
305       break;
306      default: return FALSE; break;
307     }
308    break;
309   case GST_BUFTYPE_A_LAW:
310     codec = ROAR_CODEC_ALAW;
311     bits  = 8;
312    break;
313   case GST_BUFTYPE_MU_LAW:
314     codec = ROAR_CODEC_MULAW;
315     bits  = 8;
316    break;
317   default:
318     return FALSE;
319  }
320
321  roarsink->fd = roar_simple_new_stream(&(roarsink->con), spec->rate, spec->channels, bits,
322                                        codec, ROAR_DIR_PLAY);
323
324  if ( roarsink->fd == -1 )
325    goto cannot_open;
326
327  roarsink->rate = spec->rate;
328
329  spec->segsize  = ROAR_BUF_SIZE;
330  spec->segtotal = (ROAR_MAX_WRITE_SIZE / spec->segsize);
331
332  /* FIXME: this is wrong for signed ints (and the
333   * audioringbuffers should do it for us anyway) */
334  spec->bytes_per_sample = spec->channels * bits / 8;
335  memset(&(spec->silence_sample), 0, sizeof(spec->silence_sample));
336
337  GST_INFO_OBJECT(roarsink, "successfully opened connection to RoarAudio server");
338
339  return TRUE;
340
341  /* ERRORS */
342cannot_open:
343  {
344    GST_ELEMENT_ERROR(roarsink, RESOURCE, OPEN_WRITE,
345        (_("Could not establish connection to sound server")),
346        ("can't open connection to RoarAudio server"));
347    return FALSE;
348  }
349}
350
351static gboolean gst_roarsink_unprepare (GstAudioSink * asink) {
352  GstRoarSink *roarsink = GST_ROARSINK(asink);
353
354  if ((roarsink->fd == -1) && (roar_get_connection_fh(&(roarsink->con)) == -1))
355    return TRUE;
356
357  close(roarsink->fd);
358  roarsink->fd = -1;
359
360  GST_INFO_OBJECT(roarsink, "closed sound device");
361
362  return TRUE;
363}
364
365
366static guint gst_roarsink_write (GstAudioSink * asink, gpointer data, guint length) {
367  GstRoarSink *roarsink = GST_ROARSINK(asink);
368  gint to_write = 0;
369
370  to_write = length;
371
372  while (to_write > 0) {
373    int done;
374
375    done = write(roarsink->fd, data, to_write);
376
377    if (done < 0)
378      goto write_error;
379
380    to_write -= done;
381    data += done;
382  }
383  return length;
384
385  /* ERRORS */
386write_error:
387  {
388    GST_ELEMENT_ERROR(roarsink, RESOURCE, WRITE,
389        ("Failed to write data to the RoarAudio daemon"), GST_ERROR_SYSTEM);
390    return 0;
391  }
392}
393
394static guint gst_roarsink_delay (GstAudioSink * asink) {
395//  GstRoarSink *roarsink = GST_ROARSINK (asink);
396  guint latency;
397
398  latency = 441; // compile type depending and link level deppendent,
399                 // use default value for local operations here for the moment
400
401  GST_DEBUG_OBJECT(asink, "got latency: %u", latency);
402
403  return latency;
404}
405
406static void gst_roarsink_reset (GstAudioSink * asink) {
407  GST_DEBUG_OBJECT(asink, "reset called");
408}
409
410static void gst_roarsink_set_property (GObject * object, guint prop_id, const GValue * value,
411                                       GParamSpec * pspec) {
412  GstRoarSink *roarsink = GST_ROARSINK(object);
413
414  switch (prop_id) {
415    case PROP_HOST:
416      if ( roarsink->host != NULL )
417       g_free(roarsink->host);
418      roarsink->host = g_value_dup_string(value);
419     break;
420    default:
421      break;
422  }
423}
424
425static void gst_roarsink_get_property (GObject * object, guint prop_id, GValue * value,
426                                       GParamSpec * pspec) {
427  GstRoarSink *roarsink = GST_ROARSINK(object);
428
429  switch (prop_id) {
430    case PROP_HOST:
431      g_value_set_string(value, roarsink->host);
432     break;
433    default:
434      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
435     break;
436  }
437}
438
439gboolean gst_roarsink_factory_init (GstPlugin * plugin) {
440  if (!gst_element_register(plugin, "roarsink", GST_RANK_MARGINAL,
441                            GST_TYPE_ROARSINK))
442    return FALSE;
443
444  return TRUE;
445}
Note: See TracBrowser for help on using the repository browser.