source: roaraudio/plugins/gstreamer0.10/roarsink.c @ 2116:7903e67b6521

Last change on this file since 2116:7903e67b6521 was 2075:40cb5be7baaf, checked in by phi, 15 years ago

use new api

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