mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-01 21:18:52 +00:00
Added clock to esdsink based on GstAudioClock
Original commit message from CVS: Added clock to esdsink based on GstAudioClock
This commit is contained in:
parent
e0cf75ee7a
commit
8da323b63d
3 changed files with 129 additions and 8 deletions
|
@ -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));
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue