2 * Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.org>
5 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
31 GST_DEBUG_CATEGORY_EXTERN (esd_debug);
32 #define GST_CAT_DEFAULT esd_debug
34 /* elementfactory information */
35 static GstElementDetails esdsink_details = {
38 "Plays audio to an esound server",
39 "Richard Boulton <richard-gst@tartarus.org>",
42 /* Signals and args */
58 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
61 GST_STATIC_CAPS ("audio/x-raw-int, "
62 "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
63 "signed = (boolean) TRUE, "
65 "depth = (int) 16, " "rate = 44100, " "channels = 2")
68 static void gst_esdsink_base_init (gpointer g_class);
69 static void gst_esdsink_class_init (gpointer g_class, gpointer class_data);
70 static void gst_esdsink_init (GTypeInstance * instance, gpointer g_class);
72 static gboolean gst_esdsink_open_audio (GstEsdsink * sink);
73 static void gst_esdsink_close_audio (GstEsdsink * sink);
74 static GstElementStateReturn gst_esdsink_change_state (GstElement * element);
76 static GstClockTime gst_esdsink_get_time (GstClock * clock, gpointer data);
77 static GstClock *gst_esdsink_get_clock (GstElement * element);
78 static void gst_esdsink_set_clock (GstElement * element, GstClock * clock);
79 static void gst_esdsink_chain (GstPad * pad, GstData * _data);
81 static void gst_esdsink_set_property (GObject * object, guint prop_id,
82 const GValue * value, GParamSpec * pspec);
83 static void gst_esdsink_get_property (GObject * object, guint prop_id,
84 GValue * value, GParamSpec * pspec);
86 static GstElementClass *parent_class = NULL;
88 /*static guint gst_esdsink_signals[LAST_SIGNAL] = { 0 }; */
91 gst_esdsink_get_type (void)
93 static GType esdsink_type = 0;
96 static const GTypeInfo esdsink_info = {
97 sizeof (GstEsdsinkClass),
98 gst_esdsink_base_init,
100 gst_esdsink_class_init,
108 g_type_register_static (GST_TYPE_ELEMENT, "GstEsdsink", &esdsink_info,
115 gst_esdsink_base_init (gpointer g_class)
117 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
119 gst_element_class_add_pad_template (element_class,
120 gst_static_pad_template_get (&sink_factory));
121 gst_element_class_set_details (element_class, &esdsink_details);
125 gst_esdsink_class_init (gpointer g_class, gpointer class_data)
127 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
128 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
130 parent_class = g_type_class_peek_parent (g_class);
132 g_object_class_install_property (gobject_class, ARG_MUTE, g_param_spec_boolean ("mute", "mute", "mute", TRUE, G_PARAM_READWRITE)); /* CHECKME */
133 g_object_class_install_property (gobject_class, ARG_HOST, g_param_spec_string ("host", "host", "host", NULL, G_PARAM_READWRITE)); /* CHECKME */
134 g_object_class_install_property (gobject_class, ARG_SYNC,
135 g_param_spec_boolean ("sync", "sync", "Synchronize output to clock",
136 TRUE, G_PARAM_READWRITE));
138 /* This option is disabled because it is dumb in GStreamer's architecture. */
139 g_object_class_install_property (gobject_class, ARG_FALLBACK,
140 g_param_spec_boolean ("fallback", "fallback",
141 "Fall back to using OSS if Esound daemon is not present", FALSE,
145 gobject_class->set_property = gst_esdsink_set_property;
146 gobject_class->get_property = gst_esdsink_get_property;
148 gstelement_class->change_state = gst_esdsink_change_state;
149 gstelement_class->set_clock = gst_esdsink_set_clock;
150 gstelement_class->get_clock = gst_esdsink_get_clock;
154 gst_esdsink_init (GTypeInstance * instance, gpointer g_class)
156 GstEsdsink *esdsink = GST_ESDSINK (instance);
159 gst_pad_new_from_template (gst_element_class_get_pad_template
160 (GST_ELEMENT_GET_CLASS (instance), "sink"), "sink");
161 gst_element_add_pad (GST_ELEMENT (esdsink), esdsink->sinkpad);
162 gst_pad_set_chain_function (esdsink->sinkpad,
163 GST_DEBUG_FUNCPTR (gst_esdsink_chain));
165 GST_FLAG_SET (esdsink, GST_ELEMENT_EVENT_AWARE);
167 esdsink->mute = FALSE;
169 /* FIXME: get default from somewhere better than just putting them inline. */
170 /*esdsink->negotiated = FALSE; */
171 /* we have static caps on our template, so it always is negotiated */
172 esdsink->negotiated = TRUE;
173 esdsink->format = 16;
175 esdsink->channels = 2;
176 esdsink->frequency = 44100;
177 esdsink->bytes_per_sample = esdsink->channels * (esdsink->depth / 8);
178 esdsink->host = getenv ("ESPEAKER");
179 esdsink->provided_clock =
180 gst_audio_clock_new ("esdclock", gst_esdsink_get_time, esdsink);
181 gst_object_set_parent (GST_OBJECT (esdsink->provided_clock),
182 GST_OBJECT (esdsink));
183 esdsink->sync = TRUE;
184 esdsink->fallback = FALSE;
188 static GstPadLinkReturn
189 gst_esdsink_link (GstPad * pad, const GstCaps * caps)
192 GstStructure *structure;
194 esdsink = GST_ESDSINK (gst_pad_get_parent (pad));
196 structure = gst_caps_get_structure (caps, 0);
197 gst_structure_get_int (structure, "depth", &esdsink->depth);
198 gst_structure_get_int (structure, "channels", &esdsink->channels);
199 gst_structure_get_int (structure, "rate", &esdsink->frequency);
201 esdsink->bytes_per_sample = esdsink->channels * (esdsink->depth / 8);
203 gst_esdsink_close_audio (esdsink);
204 if (gst_esdsink_open_audio (esdsink)) {
205 esdsink->negotiated = TRUE;
206 return GST_PAD_LINK_OK;
208 /* FIXME: is it supposed to be correct to have closed audio when caps nego
211 GST_DEBUG ("esd link function could not negotiate, returning delayed");
212 return GST_PAD_LINK_REFUSED;
217 gst_esdsink_get_time (GstClock * clock, gpointer data)
219 GstEsdsink *esdsink = GST_ESDSINK (data);
222 res = (esdsink->handled * GST_SECOND) / esdsink->frequency;
229 gst_esdsink_get_clock (GstElement * element)
233 esdsink = GST_ESDSINK (element);
235 return GST_CLOCK (esdsink->provided_clock);
239 gst_esdsink_set_clock (GstElement * element, GstClock * clock)
243 esdsink = GST_ESDSINK (element);
245 esdsink->clock = clock;
249 gst_esdsink_chain (GstPad * pad, GstData * _data)
251 GstBuffer *buf = GST_BUFFER (_data);
254 esdsink = GST_ESDSINK (gst_pad_get_parent (pad));
256 if (!esdsink->negotiated) {
257 GST_ELEMENT_ERROR (esdsink, CORE, NEGOTIATION, (NULL),
258 ("element wasn't negotiated before chain function"));
262 if (GST_IS_EVENT (buf)) {
263 GstEvent *event = GST_EVENT (buf);
265 switch (GST_EVENT_TYPE (event)) {
267 gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock),
269 gst_pad_event_default (pad, event);
272 gst_pad_event_default (pad, event);
275 gst_event_unref (event);
279 if (GST_BUFFER_DATA (buf) != NULL) {
280 if (!esdsink->mute && esdsink->fd >= 0) {
281 guchar *data = GST_BUFFER_DATA (buf);
282 gint size = GST_BUFFER_SIZE (buf);
287 GST_LOG ("fd=%d data=%p size=%d",
288 esdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
289 while (to_write > 0) {
292 done = write (esdsink->fd, data, to_write);
295 if (errno == EINTR) {
298 g_assert_not_reached ();
303 esdsink->handled += done / esdsink->bytes_per_sample;
309 gst_audio_clock_update_time ((GstAudioClock *) esdsink->provided_clock,
310 gst_esdsink_get_time (esdsink->provided_clock, esdsink));
313 gst_buffer_unref (buf);
317 gst_esdsink_set_property (GObject * object, guint prop_id, const GValue * value,
322 /* it's not null if we got it, but it might not be ours */
323 g_return_if_fail (GST_IS_ESDSINK (object));
324 esdsink = GST_ESDSINK (object);
328 esdsink->mute = g_value_get_boolean (value);
331 g_free (esdsink->host);
332 if (g_value_get_string (value) == NULL)
333 esdsink->host = NULL;
335 esdsink->host = g_strdup (g_value_get_string (value));
338 esdsink->sync = g_value_get_boolean (value);
341 esdsink->fallback = g_value_get_boolean (value);
349 gst_esdsink_get_property (GObject * object, guint prop_id, GValue * value,
354 esdsink = GST_ESDSINK (object);
358 g_value_set_boolean (value, esdsink->mute);
361 g_value_set_string (value, esdsink->host);
364 g_value_set_boolean (value, esdsink->sync);
367 g_value_set_boolean (value, esdsink->fallback);
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
376 gst_esdsink_factory_init (GstPlugin * plugin)
378 if (!gst_element_register (plugin, "esdsink", GST_RANK_NONE,
386 gst_esdsink_open_audio (GstEsdsink * sink)
388 /* Name used by esound for this connection. */
389 const char *connname = "GStreamer";
391 /* Bitmap describing audio format. */
392 esd_format_t esdformat = ESD_STREAM | ESD_PLAY;
394 g_return_val_if_fail (sink->fd == -1, FALSE);
396 if (sink->depth == 16)
397 esdformat |= ESD_BITS16;
398 else if (sink->depth == 8)
399 esdformat |= ESD_BITS8;
401 GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL),
402 ("invalid bit depth (%d)", sink->depth));
406 if (sink->channels == 2)
407 esdformat |= ESD_STEREO;
408 else if (sink->channels == 1)
409 esdformat |= ESD_MONO;
411 GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL),
412 ("invalid number of channels (%d)", sink->channels));
416 GST_INFO ("attempting to open connection to esound server");
417 if (sink->fallback) {
419 esd_play_stream_fallback (esdformat, sink->frequency, sink->host,
423 esd_play_stream (esdformat, sink->frequency, sink->host, connname);
426 GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
427 ("can't open connection to esound server"));
430 GST_INFO ("successfully opened connection to esound server");
436 gst_esdsink_close_audio (GstEsdsink * sink)
444 GST_INFO ("esdsink: closed sound device");
447 static GstElementStateReturn
448 gst_esdsink_change_state (GstElement * element)
452 esdsink = GST_ESDSINK (element);
454 switch (GST_STATE_TRANSITION (element)) {
455 case GST_STATE_NULL_TO_READY:
456 if (!gst_esdsink_open_audio (GST_ESDSINK (element))) {
457 return GST_STATE_FAILURE;
460 case GST_STATE_READY_TO_PAUSED:
462 case GST_STATE_PAUSED_TO_PLAYING:
463 gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock),
466 case GST_STATE_PLAYING_TO_PAUSED:
467 gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock),
469 esdsink->resync = TRUE;
471 case GST_STATE_PAUSED_TO_READY:
473 case GST_STATE_READY_TO_NULL:
474 gst_esdsink_close_audio (GST_ESDSINK (element));
480 if (GST_ELEMENT_CLASS (parent_class)->change_state)
481 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
483 return GST_STATE_SUCCESS;