source: roaraudio/plugins/gstreamer0.10/roarsink.c @ 2565:7f52d2a00d57

Last change on this file since 2565:7f52d2a00d57 was 2565:7f52d2a00d57, checked in by phi, 15 years ago

esound -> ROarAudio

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