From 8da323b63d7e9b5fa14f45081c00b29a50a77adc Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 17 Jul 2003 08:08:09 +0000 Subject: [PATCH] Added clock to esdsink based on GstAudioClock Original commit message from CVS: Added clock to esdsink based on GstAudioClock --- ext/esd/esdsink.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++---- ext/esd/esdsink.h | 7 +++ ext/esd/gstesd.c | 2 + 3 files changed, 129 insertions(+), 8 deletions(-) diff --git a/ext/esd/esdsink.c b/ext/esd/esdsink.c index 3d985b5..f455738 100644 --- a/ext/esd/esdsink.c +++ b/ext/esd/esdsink.c @@ -26,6 +26,7 @@ #include "esdsink.h" #include #include +#include /* elementfactory information */ static GstElementDetails esdsink_details = { @@ -48,6 +49,8 @@ enum { ARG_0, ARG_MUTE, ARG_HOST, + ARG_SYNC, + ARG_FALLBACK, }; GST_PAD_TEMPLATE_FACTORY (sink_factory, @@ -87,6 +90,8 @@ static void gst_esdsink_close_audio (GstEsdsink *sink); static GstElementStateReturn gst_esdsink_change_state (GstElement *element); static GstPadLinkReturn gst_esdsink_sinkconnect (GstPad *pad, GstCaps *caps); +static GstClockTime gst_esdsink_get_time (GstClock *clock, gpointer data); +static GstClock * gst_esdsink_get_clock (GstElement *element); static void gst_esdsink_set_clock (GstElement *element, GstClock *clock); static void gst_esdsink_chain (GstPad *pad, GstBuffer *buf); @@ -136,13 +141,19 @@ gst_esdsink_class_init (GstEsdsinkClass *klass) g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HOST, g_param_spec_string("host","host","host", NULL, G_PARAM_READWRITE)); /* CHECKME */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SYNC, + g_param_spec_boolean("sync","sync","Synchronize output to clock", + FALSE,G_PARAM_READWRITE)); + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FALLBACK, + g_param_spec_boolean("fallback","fallback","Fall back to using OSS if Esound daemon is not present", + FALSE,G_PARAM_READWRITE)); gobject_class->set_property = gst_esdsink_set_property; gobject_class->get_property = gst_esdsink_get_property; gstelement_class->change_state = gst_esdsink_change_state; gstelement_class->set_clock = gst_esdsink_set_clock; - //gstelement_class->get_clock = gst_esdsink_get_clock; + gstelement_class->get_clock = gst_esdsink_get_clock; } static void @@ -165,6 +176,10 @@ gst_esdsink_init(GstEsdsink *esdsink) esdsink->channels = -1; esdsink->frequency = -1; esdsink->host = getenv ("ESPEAKER"); + esdsink->provided_clock = gst_audio_clock_new("esdclock", gst_esdsink_get_time, esdsink); + gst_object_set_parent(GST_OBJECT(esdsink->provided_clock), GST_OBJECT(esdsink)); + esdsink->sync = FALSE; + esdsink->fallback = FALSE; } static GstPadLinkReturn @@ -183,6 +198,8 @@ gst_esdsink_sinkconnect (GstPad *pad, GstCaps *caps) gst_caps_get_int (caps, "channels", &esdsink->channels); gst_caps_get_int (caps, "rate", &esdsink->frequency); + esdsink->bytes_per_sample = esdsink->channels * (esdsink->depth/8); + /* only u8/s16 */ if ((sign == FALSE && esdsink->depth != 8) || (sign == TRUE && esdsink->depth != 16)) { @@ -198,17 +215,38 @@ gst_esdsink_sinkconnect (GstPad *pad, GstCaps *caps) return GST_PAD_LINK_REFUSED; } +static int +gst_esdsink_get_latency (GstEsdsink *esdsink) +{ + /* esd_get_latency() doesn't actually work. So we return a + * fake value */ + return 44100/2; #if 0 + return esd_get_latency (esdsink->fd); +#endif +} + +static GstClockTime +gst_esdsink_get_time (GstClock *clock, gpointer data) +{ + GstEsdsink *esdsink = GST_ESDSINK(data); + GstClockTime res; + + res = (esdsink->handled - gst_esdsink_get_latency(esdsink)) + * GST_SECOND / esdsink->frequency; + + return res; +} + static GstClock * gst_esdsink_get_clock (GstElement *element) { GstEsdsink *esdsink; - esdsink = GET_ESDSINK (element); + esdsink = GST_ESDSINK (element); return GST_CLOCK(esdsink->provided_clock); } -#endif static void gst_esdsink_set_clock (GstElement *element, GstClock *clock) @@ -239,6 +277,9 @@ gst_esdsink_chain (GstPad *pad, GstBuffer *buf) switch(GST_EVENT_TYPE(event)){ case GST_EVENT_EOS: + gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock), + FALSE); + gst_pad_event_default (pad, event); break; case GST_EVENT_DISCONTINUOUS: { @@ -246,11 +287,12 @@ gst_esdsink_chain (GstPad *pad, GstBuffer *buf) if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { if (!gst_clock_handle_discont (esdsink->clock, value)){ - //gst_esdsink_clock_set_active (osssink->provided_clock, FALSE); + gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock), + FALSE); } - //esdsink->handled = 0; + esdsink->handled = 0; } - //esdsink->resync = TRUE; + esdsink->resync = TRUE; break; } default: @@ -263,11 +305,62 @@ gst_esdsink_chain (GstPad *pad, GstBuffer *buf) if (GST_BUFFER_DATA (buf) != NULL) { if (!esdsink->mute && esdsink->fd >= 0) { + guchar *data = GST_BUFFER_DATA (buf); + gint size = GST_BUFFER_SIZE (buf); + gint to_write = 0; + + if (esdsink->clock){ + gint delay = 0; + gint64 queued; + GstClockTimeDiff jitter; + + delay = gst_esdsink_get_latency (esdsink); + queued = delay * GST_SECOND / esdsink->frequency; + + if (esdsink->resync && esdsink->sync) { + GstClockID id = gst_clock_new_single_shot_id (esdsink->clock, + GST_BUFFER_TIMESTAMP (buf) - queued); + + gst_element_clock_wait (GST_ELEMENT (esdsink), id, &jitter); + gst_clock_id_free (id); + + if (jitter >= 0){ + gst_clock_handle_discont (esdsink->clock, + GST_BUFFER_TIMESTAMP (buf) - queued + jitter); + to_write = size; + gst_audio_clock_set_active ((GstAudioClock *)esdsink->provided_clock, TRUE); + esdsink->resync = FALSE; + } + }else{ + to_write = size; + } + } + GST_DEBUG ("esdsink: fd=%d data=%p size=%d", esdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - write (esdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + while (to_write > 0){ + int done; + + done = write (esdsink->fd, data, to_write); + + if(done < 0){ + if(errno==EINTR){ + goto done; + } + g_assert_not_reached(); + } + + to_write -= done; + data += done; + esdsink->handled += done / esdsink->bytes_per_sample; + } + } } + + gst_audio_clock_update_time ((GstAudioClock *)esdsink->provided_clock, + GST_BUFFER_TIMESTAMP (buf)); + done: gst_buffer_unref (buf); } @@ -292,6 +385,12 @@ gst_esdsink_set_property (GObject *object, guint prop_id, const GValue *value, G else esdsink->host = g_strdup (g_value_get_string (value)); break; + case ARG_SYNC: + esdsink->sync = g_value_get_boolean (value); + break; + case ARG_FALLBACK: + esdsink->fallback = g_value_get_boolean (value); + break; default: break; } @@ -311,6 +410,12 @@ gst_esdsink_get_property (GObject *object, guint prop_id, GValue *value, GParamS case ARG_HOST: g_value_set_string (value, esdsink->host); break; + case ARG_SYNC: + g_value_set_boolean (value, esdsink->sync); + break; + case ARG_FALLBACK: + g_value_set_boolean (value, esdsink->fallback); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -360,7 +465,11 @@ gst_esdsink_open_audio (GstEsdsink *sink) } GST_DEBUG ("esdsink: attempting to open connection to esound server"); - sink->fd = esd_play_stream_fallback(esdformat, sink->frequency, sink->host, connname); + if(sink->fallback){ + sink->fd = esd_play_stream_fallback(esdformat, sink->frequency, sink->host, connname); + }else{ + sink->fd = esd_play_stream(esdformat, sink->frequency, sink->host, connname); + } if ( sink->fd < 0 ) { GST_DEBUG ("esdsink: can't open connection to esound server"); return FALSE; @@ -396,6 +505,9 @@ gst_esdsink_change_state (GstElement *element) case GST_STATE_PAUSED_TO_PLAYING: break; case GST_STATE_PLAYING_TO_PAUSED: + gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock), + FALSE); + esdsink->resync = TRUE; break; case GST_STATE_PAUSED_TO_READY: gst_esdsink_close_audio (GST_ESDSINK (element)); diff --git a/ext/esd/esdsink.h b/ext/esd/esdsink.h index c418386..9bf8164 100644 --- a/ext/esd/esdsink.h +++ b/ext/esd/esdsink.h @@ -22,6 +22,7 @@ #define __GST_ESDSINK_H__ #include +#include G_BEGIN_DECLS @@ -44,6 +45,7 @@ struct _GstEsdsink { GstPad *sinkpad; + GstClock *provided_clock; GstClock *clock; gboolean mute; @@ -54,6 +56,11 @@ struct _GstEsdsink { gint frequency; gboolean negotiated; gchar *host; + int handled; + int bytes_per_sample; + gboolean sync; + gboolean resync; + gboolean fallback; }; struct _GstEsdsinkClass { diff --git a/ext/esd/gstesd.c b/ext/esd/gstesd.c index 3f01632..24a9842 100644 --- a/ext/esd/gstesd.c +++ b/ext/esd/gstesd.c @@ -30,6 +30,8 @@ plugin_init (GModule *module, GstPlugin *plugin) { gboolean ret; + if (!gst_library_load ("gstaudio")) return FALSE; + ret = gst_esdsink_factory_init(plugin); if(ret == FALSE) return FALSE; -- 2.7.4