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 <esd.h>
#include <unistd.h>
#include <errno.h>
/* 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");
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));

View file

@ -22,6 +22,7 @@
#define __GST_ESDSINK_H__
#include <gst/gst.h>
#include <gst/audio/audioclock.h>
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 {

View file

@ -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;