Remove unused variables in _class_init
[platform/upstream/gstreamer.git] / ext / esd / esdsink.c
1 /* GStreamer
2  * Copyright (C) <2005> Arwed v. Merkatz <v.merkatz@gmx.net>
3  *
4  * Roughly based on the gstreamer 0.8 esdsink plugin:
5  * Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.org>
6  *
7  * esdsink.c: an EsounD audio sink
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /**
26  * SECTION:element-esdsink
27  * @see_also: #GstAlsaSink, #GstAutoAudioSink
28  *
29  * This element outputs sound to an already-running Enlightened Sound Daemon
30  * (ESound Daemon, esd). Note that a sound daemon will never be auto-spawned
31  * through this element (regardless of the system configuration), since this
32  * is actively prevented by the element. If you must use esd, you need to
33  * make sure it is started automatically with your session or otherwise.
34  *
35  * TODO: insert some comments about how sucky esd is and that all the cool
36  * kids use pulseaudio or whatever these days.
37  *
38  * <refsect2>
39  * <title>Example launch line</title>
40  * |[
41  * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! audioresample ! esdsink
42  * ]| play an Ogg/Vorbis audio file via esd
43  * </refsect2>
44  */
45
46 #ifdef HAVE_CONFIG_H
47 #include "config.h"
48 #endif
49
50 #include "esdsink.h"
51 #include <esd.h>
52 #include <unistd.h>
53 #include <errno.h>
54
55 #include <gst/gst-i18n-plugin.h>
56
57 /* wtay: from my esd.h (debian unstable libesd0-dev 0.2.36-3) */
58 #ifndef ESD_MAX_WRITE_SIZE
59 #define ESD_MAX_WRITE_SIZE (21 * 4096)
60 #endif
61
62 GST_DEBUG_CATEGORY_EXTERN (esd_debug);
63 #define GST_CAT_DEFAULT esd_debug
64
65 /* elementfactory information */
66 static const GstElementDetails esdsink_details =
67 GST_ELEMENT_DETAILS ("Esound audio sink",
68     "Sink/Audio",
69     "Plays audio to an esound server",
70     "Arwed von Merkatz <v.merkatz@gmx.net>");
71
72 enum
73 {
74   PROP_0,
75   PROP_HOST
76 };
77
78 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
79     GST_PAD_SINK,
80     GST_PAD_ALWAYS,
81     GST_STATIC_CAPS ("audio/x-raw-int, "
82         "endianness = (int) BYTE_ORDER, "
83         "signed = (boolean) TRUE, "
84         "width = (int) 16, "
85         "depth = (int) 16, "
86         "rate = (int) [ 1, MAX ], "
87         "channels = (int) [ 1, 2 ]; "
88         "audio/x-raw-int, "
89         "signed = (boolean) { true, false }, "
90         "width = (int) 8, "
91         "depth = (int) 8, "
92         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
93     );
94
95 static void gst_esdsink_finalize (GObject * object);
96
97 static GstCaps *gst_esdsink_getcaps (GstBaseSink * bsink);
98
99 static gboolean gst_esdsink_open (GstAudioSink * asink);
100 static gboolean gst_esdsink_close (GstAudioSink * asink);
101 static gboolean gst_esdsink_prepare (GstAudioSink * asink,
102     GstRingBufferSpec * spec);
103 static gboolean gst_esdsink_unprepare (GstAudioSink * asink);
104 static guint gst_esdsink_write (GstAudioSink * asink, gpointer data,
105     guint length);
106 static guint gst_esdsink_delay (GstAudioSink * asink);
107 static void gst_esdsink_reset (GstAudioSink * asink);
108
109 static void gst_esdsink_set_property (GObject * object, guint prop_id,
110     const GValue * value, GParamSpec * pspec);
111 static void gst_esdsink_get_property (GObject * object, guint prop_id,
112     GValue * value, GParamSpec * pspec);
113
114 GST_BOILERPLATE (GstEsdSink, gst_esdsink, GstAudioSink, GST_TYPE_AUDIO_SINK);
115
116 static void
117 gst_esdsink_base_init (gpointer g_class)
118 {
119   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
120
121   gst_element_class_add_pad_template (element_class,
122       gst_static_pad_template_get (&sink_factory));
123   gst_element_class_set_details (element_class, &esdsink_details);
124 }
125
126 static void
127 gst_esdsink_class_init (GstEsdSinkClass * klass)
128 {
129   GObjectClass *gobject_class;
130   GstBaseSinkClass *gstbasesink_class;
131   GstAudioSinkClass *gstaudiosink_class;
132
133   gobject_class = (GObjectClass *) klass;
134   gstbasesink_class = (GstBaseSinkClass *) klass;
135   gstaudiosink_class = (GstAudioSinkClass *) klass;
136
137   parent_class = g_type_class_peek_parent (klass);
138
139   gobject_class->finalize = gst_esdsink_finalize;
140
141   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_esdsink_getcaps);
142
143   gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_esdsink_open);
144   gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_esdsink_close);
145   gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_esdsink_prepare);
146   gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_esdsink_unprepare);
147   gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_esdsink_write);
148   gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_esdsink_delay);
149   gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_esdsink_reset);
150
151   gobject_class->set_property = gst_esdsink_set_property;
152   gobject_class->get_property = gst_esdsink_get_property;
153
154   /* default value is filled in the _init method */
155   g_object_class_install_property (gobject_class, PROP_HOST,
156       g_param_spec_string ("host", "Host",
157           "The host running the esound daemon", NULL, G_PARAM_READWRITE));
158 }
159
160 static void
161 gst_esdsink_init (GstEsdSink * esdsink, GstEsdSinkClass * klass)
162 {
163   esdsink->fd = -1;
164   esdsink->ctrl_fd = -1;
165   esdsink->host = g_strdup (g_getenv ("ESPEAKER"));
166 }
167
168 static void
169 gst_esdsink_finalize (GObject * object)
170 {
171   GstEsdSink *esdsink = GST_ESDSINK (object);
172
173   gst_caps_replace (&esdsink->cur_caps, NULL);
174   g_free (esdsink->host);
175
176   G_OBJECT_CLASS (parent_class)->finalize (object);
177 }
178
179 static GstCaps *
180 gst_esdsink_getcaps (GstBaseSink * bsink)
181 {
182   GstEsdSink *esdsink;
183
184   esdsink = GST_ESDSINK (bsink);
185
186   /* no fd, we're done with the template caps */
187   if (esdsink->ctrl_fd < 0 || esdsink->cur_caps == NULL) {
188     GST_LOG_OBJECT (esdsink, "getcaps called, returning template caps");
189     return NULL;
190   }
191
192   GST_LOG_OBJECT (esdsink, "returning %" GST_PTR_FORMAT, esdsink->cur_caps);
193
194   return gst_caps_ref (esdsink->cur_caps);
195 }
196
197 static gboolean
198 gst_esdsink_open (GstAudioSink * asink)
199 {
200   esd_server_info_t *server_info;
201   GstPadTemplate *pad_template;
202   GstEsdSink *esdsink;
203   gchar *saved_env;
204   gint i;
205
206   esdsink = GST_ESDSINK (asink);
207
208   GST_DEBUG_OBJECT (esdsink, "open");
209
210   /* ensure libesd doesn't auto-spawn a sound daemon if none is running yet */
211   saved_env = g_strdup (g_getenv ("ESD_NO_SPAWN"));
212   g_setenv ("ESD_NO_SPAWN", "1", TRUE);
213
214   /* now try to connect to any existing/running sound daemons */
215   esdsink->ctrl_fd = esd_open_sound (esdsink->host);
216
217   /* and restore the previous state */
218   if (saved_env != NULL) {
219     g_setenv ("ESD_NO_SPAWN", saved_env, TRUE);
220   } else {
221     g_unsetenv ("ESD_NO_SPAWN");
222   }
223   g_free (saved_env);
224
225   if (esdsink->ctrl_fd < 0)
226     goto couldnt_connect;
227
228   /* get server info */
229   server_info = esd_get_server_info (esdsink->ctrl_fd);
230   if (!server_info)
231     goto no_server_info;
232
233   GST_INFO_OBJECT (esdsink, "got server info rate: %i", server_info->rate);
234
235   pad_template = gst_static_pad_template_get (&sink_factory);
236   esdsink->cur_caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
237   gst_object_unref (pad_template);
238
239   for (i = 0; i < esdsink->cur_caps->structs->len; i++) {
240     GstStructure *s;
241
242     s = gst_caps_get_structure (esdsink->cur_caps, i);
243     gst_structure_set (s, "rate", G_TYPE_INT, server_info->rate, NULL);
244   }
245
246   esd_free_server_info (server_info);
247
248   GST_INFO_OBJECT (esdsink, "server caps: %" GST_PTR_FORMAT, esdsink->cur_caps);
249
250   return TRUE;
251
252   /* ERRORS */
253 couldnt_connect:
254   {
255     GST_ELEMENT_ERROR (esdsink, RESOURCE, OPEN_WRITE,
256         (_("Could not establish connection to sound server")),
257         ("can't open connection to esound server"));
258     return FALSE;
259   }
260 no_server_info:
261   {
262     GST_ELEMENT_ERROR (esdsink, RESOURCE, OPEN_WRITE,
263         (_("Failed to query sound server capabilities")),
264         ("couldn't get server info!"));
265     return FALSE;
266   }
267 }
268
269 static gboolean
270 gst_esdsink_close (GstAudioSink * asink)
271 {
272   GstEsdSink *esdsink = GST_ESDSINK (asink);
273
274   GST_DEBUG_OBJECT (esdsink, "close");
275
276   gst_caps_replace (&esdsink->cur_caps, NULL);
277   esd_close (esdsink->ctrl_fd);
278   esdsink->ctrl_fd = -1;
279
280   return TRUE;
281 }
282
283 static gboolean
284 gst_esdsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
285 {
286   GstEsdSink *esdsink = GST_ESDSINK (asink);
287   esd_format_t esdformat;
288
289   /* Name used by esound for this connection. */
290   const char connname[] = "GStreamer";
291
292   GST_DEBUG_OBJECT (esdsink, "prepare");
293
294   /* Bitmap describing audio format. */
295   esdformat = ESD_STREAM | ESD_PLAY;
296
297   switch (spec->depth) {
298     case 8:
299       esdformat |= ESD_BITS8;
300       break;
301     case 16:
302       esdformat |= ESD_BITS16;
303       break;
304     default:
305       goto unsupported_depth;
306   }
307
308   switch (spec->channels) {
309     case 1:
310       esdformat |= ESD_MONO;
311       break;
312     case 2:
313       esdformat |= ESD_STEREO;
314       break;
315     default:
316       goto unsupported_channels;
317   }
318
319   GST_INFO_OBJECT (esdsink,
320       "attempting to open data connection to esound server");
321
322   esdsink->fd =
323       esd_play_stream (esdformat, spec->rate, esdsink->host, connname);
324
325   if ((esdsink->fd < 0) || (esdsink->ctrl_fd < 0))
326     goto cannot_open;
327
328   esdsink->rate = spec->rate;
329
330   spec->segsize = ESD_BUF_SIZE;
331   spec->segtotal = (ESD_MAX_WRITE_SIZE / spec->segsize);
332
333   /* FIXME: this is wrong for signed ints (and the
334    * audioringbuffers should do it for us anyway) */
335   spec->silence_sample[0] = 0;
336   spec->silence_sample[1] = 0;
337   spec->silence_sample[2] = 0;
338   spec->silence_sample[3] = 0;
339
340   GST_INFO_OBJECT (esdsink, "successfully opened connection to esound server");
341
342   return TRUE;
343
344   /* ERRORS */
345 unsupported_depth:
346   {
347     GST_ELEMENT_ERROR (esdsink, STREAM, WRONG_TYPE, (NULL),
348         ("can't handle sample depth of %d, only 8 or 16 supported",
349             spec->depth));
350     return FALSE;
351   }
352 unsupported_channels:
353   {
354     GST_ELEMENT_ERROR (esdsink, STREAM, WRONG_TYPE, (NULL),
355         ("can't handle %d channels, only 1 or 2 supported", spec->channels));
356     return FALSE;
357   }
358 cannot_open:
359   {
360     GST_ELEMENT_ERROR (esdsink, RESOURCE, OPEN_WRITE,
361         (_("Could not establish connection to sound server")),
362         ("can't open connection to esound server"));
363     return FALSE;
364   }
365 }
366
367 static gboolean
368 gst_esdsink_unprepare (GstAudioSink * asink)
369 {
370   GstEsdSink *esdsink = GST_ESDSINK (asink);
371
372   if ((esdsink->fd < 0) && (esdsink->ctrl_fd < 0))
373     return TRUE;
374
375   close (esdsink->fd);
376   esdsink->fd = -1;
377
378   GST_INFO_OBJECT (esdsink, "closed sound device");
379
380   return TRUE;
381 }
382
383
384 static guint
385 gst_esdsink_write (GstAudioSink * asink, gpointer data, guint length)
386 {
387   GstEsdSink *esdsink = GST_ESDSINK (asink);
388   gint to_write = 0;
389
390   to_write = length;
391
392   while (to_write > 0) {
393     int done;
394
395     done = write (esdsink->fd, data, to_write);
396
397     if (done < 0)
398       goto write_error;
399
400     to_write -= done;
401     data = (char *) data + done;
402   }
403   return length;
404
405   /* ERRORS */
406 write_error:
407   {
408     GST_ELEMENT_ERROR (esdsink, RESOURCE, WRITE,
409         ("Failed to write data to the esound daemon"), GST_ERROR_SYSTEM);
410     return -1;
411   }
412 }
413
414 static guint
415 gst_esdsink_delay (GstAudioSink * asink)
416 {
417   GstEsdSink *esdsink = GST_ESDSINK (asink);
418   guint latency;
419
420   latency = esd_get_latency (esdsink->ctrl_fd);
421
422   if (latency == (guint) - 1) {
423     GST_WARNING_OBJECT (asink, "couldn't get latency");
424     return 0;
425   }
426
427   /* latency is measured in samples at a rate of 44100, this 
428    * cannot overflow. */
429   latency = latency * G_GINT64_CONSTANT (44100) / esdsink->rate;
430
431   GST_DEBUG_OBJECT (asink, "got latency: %u", latency);
432
433   return latency;
434 }
435
436 static void
437 gst_esdsink_reset (GstAudioSink * asink)
438 {
439   GST_DEBUG_OBJECT (asink, "reset called");
440 }
441
442 static void
443 gst_esdsink_set_property (GObject * object, guint prop_id, const GValue * value,
444     GParamSpec * pspec)
445 {
446   GstEsdSink *esdsink = GST_ESDSINK (object);
447
448   switch (prop_id) {
449     case PROP_HOST:
450       g_free (esdsink->host);
451       esdsink->host = g_value_dup_string (value);
452       break;
453     default:
454       break;
455   }
456 }
457
458 static void
459 gst_esdsink_get_property (GObject * object, guint prop_id, GValue * value,
460     GParamSpec * pspec)
461 {
462   GstEsdSink *esdsink = GST_ESDSINK (object);
463
464   switch (prop_id) {
465     case PROP_HOST:
466       g_value_set_string (value, esdsink->host);
467       break;
468     default:
469       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
470       break;
471   }
472 }