Added clock to esdsink based on GstAudioClock

Original commit message from CVS:
Added clock to esdsink based on GstAudioClock
This commit is contained in:
David Schleef 2003-07-17 08:08:09 +00:00
parent e0cf75ee7a
commit 8da323b63d
3 changed files with 129 additions and 8 deletions

View file

@ -26,6 +26,7 @@
#include "esdsink.h" #include "esdsink.h"
#include <esd.h> #include <esd.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
/* elementfactory information */ /* elementfactory information */
static GstElementDetails esdsink_details = { static GstElementDetails esdsink_details = {
@ -48,6 +49,8 @@ enum {
ARG_0, ARG_0,
ARG_MUTE, ARG_MUTE,
ARG_HOST, ARG_HOST,
ARG_SYNC,
ARG_FALLBACK,
}; };
GST_PAD_TEMPLATE_FACTORY (sink_factory, 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 GstElementStateReturn gst_esdsink_change_state (GstElement *element);
static GstPadLinkReturn gst_esdsink_sinkconnect (GstPad *pad, GstCaps *caps); 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_set_clock (GstElement *element, GstClock *clock);
static void gst_esdsink_chain (GstPad *pad, GstBuffer *buf); 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_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HOST,
g_param_spec_string("host","host","host", g_param_spec_string("host","host","host",
NULL, G_PARAM_READWRITE)); /* CHECKME */ 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->set_property = gst_esdsink_set_property;
gobject_class->get_property = gst_esdsink_get_property; gobject_class->get_property = gst_esdsink_get_property;
gstelement_class->change_state = gst_esdsink_change_state; gstelement_class->change_state = gst_esdsink_change_state;
gstelement_class->set_clock = gst_esdsink_set_clock; 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 static void
@ -165,6 +176,10 @@ gst_esdsink_init(GstEsdsink *esdsink)
esdsink->channels = -1; esdsink->channels = -1;
esdsink->frequency = -1; esdsink->frequency = -1;
esdsink->host = getenv ("ESPEAKER"); 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 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, "channels", &esdsink->channels);
gst_caps_get_int (caps, "rate", &esdsink->frequency); gst_caps_get_int (caps, "rate", &esdsink->frequency);
esdsink->bytes_per_sample = esdsink->channels * (esdsink->depth/8);
/* only u8/s16 */ /* only u8/s16 */
if ((sign == FALSE && esdsink->depth != 8) || if ((sign == FALSE && esdsink->depth != 8) ||
(sign == TRUE && esdsink->depth != 16)) { (sign == TRUE && esdsink->depth != 16)) {
@ -198,17 +215,38 @@ gst_esdsink_sinkconnect (GstPad *pad, GstCaps *caps)
return GST_PAD_LINK_REFUSED; 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 #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 * static GstClock *
gst_esdsink_get_clock (GstElement *element) gst_esdsink_get_clock (GstElement *element)
{ {
GstEsdsink *esdsink; GstEsdsink *esdsink;
esdsink = GET_ESDSINK (element); esdsink = GST_ESDSINK (element);
return GST_CLOCK(esdsink->provided_clock); return GST_CLOCK(esdsink->provided_clock);
} }
#endif
static void static void
gst_esdsink_set_clock (GstElement *element, GstClock *clock) gst_esdsink_set_clock (GstElement *element, GstClock *clock)
@ -239,6 +277,9 @@ gst_esdsink_chain (GstPad *pad, GstBuffer *buf)
switch(GST_EVENT_TYPE(event)){ switch(GST_EVENT_TYPE(event)){
case GST_EVENT_EOS: case GST_EVENT_EOS:
gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock),
FALSE);
gst_pad_event_default (pad, event);
break; break;
case GST_EVENT_DISCONTINUOUS: 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_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
if (!gst_clock_handle_discont (esdsink->clock, 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; break;
} }
default: default:
@ -263,11 +305,62 @@ gst_esdsink_chain (GstPad *pad, GstBuffer *buf)
if (GST_BUFFER_DATA (buf) != NULL) { if (GST_BUFFER_DATA (buf) != NULL) {
if (!esdsink->mute && esdsink->fd >= 0) { 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", GST_DEBUG ("esdsink: fd=%d data=%p size=%d",
esdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); 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: done:
gst_buffer_unref (buf); gst_buffer_unref (buf);
} }
@ -292,6 +385,12 @@ gst_esdsink_set_property (GObject *object, guint prop_id, const GValue *value, G
else else
esdsink->host = g_strdup (g_value_get_string (value)); esdsink->host = g_strdup (g_value_get_string (value));
break; break;
case ARG_SYNC:
esdsink->sync = g_value_get_boolean (value);
break;
case ARG_FALLBACK:
esdsink->fallback = g_value_get_boolean (value);
break;
default: default:
break; break;
} }
@ -311,6 +410,12 @@ gst_esdsink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_HOST: case ARG_HOST:
g_value_set_string (value, esdsink->host); g_value_set_string (value, esdsink->host);
break; break;
case ARG_SYNC:
g_value_set_boolean (value, esdsink->sync);
break;
case ARG_FALLBACK:
g_value_set_boolean (value, esdsink->fallback);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -360,7 +465,11 @@ gst_esdsink_open_audio (GstEsdsink *sink)
} }
GST_DEBUG ("esdsink: attempting to open connection to esound server"); 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 ) { if ( sink->fd < 0 ) {
GST_DEBUG ("esdsink: can't open connection to esound server"); GST_DEBUG ("esdsink: can't open connection to esound server");
return FALSE; return FALSE;
@ -396,6 +505,9 @@ gst_esdsink_change_state (GstElement *element)
case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PAUSED_TO_PLAYING:
break; break;
case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PLAYING_TO_PAUSED:
gst_audio_clock_set_active (GST_AUDIO_CLOCK (esdsink->provided_clock),
FALSE);
esdsink->resync = TRUE;
break; break;
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
gst_esdsink_close_audio (GST_ESDSINK (element)); gst_esdsink_close_audio (GST_ESDSINK (element));

View file

@ -22,6 +22,7 @@
#define __GST_ESDSINK_H__ #define __GST_ESDSINK_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/audio/audioclock.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -44,6 +45,7 @@ struct _GstEsdsink {
GstPad *sinkpad; GstPad *sinkpad;
GstClock *provided_clock;
GstClock *clock; GstClock *clock;
gboolean mute; gboolean mute;
@ -54,6 +56,11 @@ struct _GstEsdsink {
gint frequency; gint frequency;
gboolean negotiated; gboolean negotiated;
gchar *host; gchar *host;
int handled;
int bytes_per_sample;
gboolean sync;
gboolean resync;
gboolean fallback;
}; };
struct _GstEsdsinkClass { struct _GstEsdsinkClass {

View file

@ -30,6 +30,8 @@ plugin_init (GModule *module, GstPlugin *plugin)
{ {
gboolean ret; gboolean ret;
if (!gst_library_load ("gstaudio")) return FALSE;
ret = gst_esdsink_factory_init(plugin); ret = gst_esdsink_factory_init(plugin);
if(ret == FALSE) return FALSE; if(ret == FALSE) return FALSE;