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