From eff37b9e21e47b8a16a5fc4477589b21508720e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 8 May 2006 23:34:10 +0000 Subject: * use streamed tagging metadata to name the playback stream in polypaudio * minor cleanups git-svn-id: file:///home/lennart/svn/public/gst-pulse/trunk@15 bb39ca4e-bce3-0310-b5d4-eea78a553289 --- src/polypsink.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++------- src/polypsink.h | 2 +- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/src/polypsink.c b/src/polypsink.c index 96c0c9f..d9e7b5f 100644 --- a/src/polypsink.c +++ b/src/polypsink.c @@ -23,12 +23,15 @@ #include "config.h" #endif -#include #include #include +#include +#include + #include "polypsink.h" + GST_DEBUG_CATEGORY_EXTERN(polyp_debug); #define GST_CAT_DEFAULT polyp_debug @@ -46,6 +49,7 @@ static void gst_polypsink_destroy_context(GstPolypSink *polypsink); static void gst_polypsink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_polypsink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gst_polypsink_finalize(GObject *object); +static void gst_polypsink_dispose(GObject *object); static gboolean gst_polypsink_open(GstAudioSink *asink); static gboolean gst_polypsink_close(GstAudioSink *asink); @@ -57,6 +61,8 @@ static guint gst_polypsink_write(GstAudioSink *asink, gpointer data, guint lengt static guint gst_polypsink_delay(GstAudioSink *asink); static void gst_polypsink_reset(GstAudioSink *asink); +static gboolean gst_polypsink_event(GstBaseSink *sink, GstEvent *event); + #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) # define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN" #else @@ -109,7 +115,7 @@ static void gst_polypsink_base_init(gpointer g_class) { "Lennart Poettering"); GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); - + gst_element_class_set_details(element_class, &details); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&pad_template)); } @@ -119,14 +125,17 @@ static void gst_polypsink_class_init( gpointer class_data) { GObjectClass *gobject_class = G_OBJECT_CLASS(g_class); -// GstElementClass *gstelement_class = GST_ELEMENT_CLASS(g_class); + GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS(g_class); GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS(g_class); parent_class = g_type_class_peek_parent(g_class); - gobject_class->set_property = gst_polypsink_set_property; - gobject_class->get_property = gst_polypsink_get_property; - gobject_class->finalize = gst_polypsink_finalize; + gobject_class->dispose = GST_DEBUG_FUNCPTR(gst_polypsink_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_polypsink_finalize); + gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_polypsink_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_polypsink_get_property); + gstbasesink_class->event = GST_DEBUG_FUNCPTR(gst_polypsink_event); + gstaudiosink_class->open = GST_DEBUG_FUNCPTR(gst_polypsink_open); gstaudiosink_class->close = GST_DEBUG_FUNCPTR(gst_polypsink_close); gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR(gst_polypsink_prepare); @@ -153,7 +162,7 @@ static void gst_polypsink_init( GstPolypSink *polypsink = GST_POLYPSINK(instance); int e; - polypsink->server = polypsink->device = NULL; + polypsink->server = polypsink->device = polypsink->stream_name = NULL; polypsink->context = NULL; polypsink->stream = NULL; @@ -171,6 +180,9 @@ static void gst_polypsink_destroy_stream(GstPolypSink* polypsink) { pa_stream_unref(polypsink->stream); polypsink->stream = NULL; } + + g_free(polypsink->stream_name); + polypsink->stream_name = NULL; } static void gst_polypsink_destroy_context(GstPolypSink* polypsink) { @@ -193,12 +205,17 @@ static void gst_polypsink_finalize(GObject * object) { g_free(polypsink->server); g_free(polypsink->device); + g_free(polypsink->stream_name); pa_threaded_mainloop_free(polypsink->mainloop); G_OBJECT_CLASS(parent_class)->finalize(object); } +static void gst_polypsink_dispose(GObject * object) { + G_OBJECT_CLASS(parent_class)->dispose(object); +} + static void gst_polypsink_set_property( GObject * object, guint prop_id, @@ -377,7 +394,7 @@ static gboolean gst_polypsink_prepare(GstAudioSink *asink, GstRingBufferSpec *sp goto unlock_and_fail; } - if (!(polypsink->stream = pa_stream_new(polypsink->context, "the stream", &polypsink->sample_spec, NULL))) { + if (!(polypsink->stream = pa_stream_new(polypsink->context, polypsink->stream_name ? polypsink->stream_name : "Playback Stream", &polypsink->sample_spec, NULL))) { GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to create stream: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL)); goto unlock_and_fail; } @@ -463,8 +480,6 @@ static guint gst_polypsink_write(GstAudioSink *asink, gpointer data, guint lengt pa_threaded_mainloop_unlock(polypsink->mainloop); - GST_WARNING("Write"); - return l; unlock_and_fail: @@ -491,8 +506,6 @@ static guint gst_polypsink_delay(GstAudioSink *asink) { t = 0; } - GST_WARNING("Latency %0.3f ms", (double) t / 1000); - pa_threaded_mainloop_unlock(polypsink->mainloop); return (guint) ((t * polypsink->sample_spec.rate) / 1000000LL); @@ -530,8 +543,6 @@ static void gst_polypsink_reset(GstAudioSink *asink) { pa_threaded_mainloop_wait(polypsink->mainloop); } - GST_WARNING("Reset"); - if (!polypsink->operation_success) { GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Flush failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL)); goto unlock_and_fail; @@ -547,6 +558,78 @@ unlock_and_fail: pa_threaded_mainloop_unlock(polypsink->mainloop); } +static void gst_polypsink_change_title(GstPolypSink *polypsink, const gchar *t) { + pa_operation *o = NULL; + + pa_threaded_mainloop_lock(polypsink->mainloop); + + g_free(polypsink->stream_name); + polypsink->stream_name = g_strdup(t); + + if (!(polypsink)->context || pa_context_get_state((polypsink)->context) != PA_CONTEXT_READY || + !(polypsink)->stream || pa_stream_get_state((polypsink)->stream) != PA_STREAM_READY) { + goto unlock_and_fail; + } + + if (!(o = pa_stream_set_name(polypsink->stream, polypsink->stream_name, NULL, polypsink))) { + GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("pa_stream_set_name() failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL)); + goto unlock_and_fail; + } + + /* We're not interested if this operation failed or not */ + +unlock_and_fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(polypsink->mainloop); +} + +static gboolean gst_polypsink_event(GstBaseSink *sink, GstEvent *event) { + GstPolypSink *polypsink = GST_POLYPSINK(sink); + + switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_TAG: { + gchar *title = NULL, *artist = NULL, *location = NULL, *description = NULL, *t = NULL, *buf = NULL; + GstTagList *l; + + gst_event_parse_tag(event, &l); + + gst_tag_list_get_string(l, GST_TAG_TITLE, &title); + gst_tag_list_get_string(l, GST_TAG_ARTIST, &artist); + gst_tag_list_get_string(l, GST_TAG_LOCATION, &location); + gst_tag_list_get_string(l, GST_TAG_DESCRIPTION, &description); + + gst_tag_list_free(l); + + if (title && artist) + t = buf = g_strdup_printf("'%s' by '%s'", title, artist); + else if (title) + t = title; + else if (description) + t = description; + else if (location) + t = location; + + if (t) + gst_polypsink_change_title(polypsink, t); + + g_free(title); + g_free(artist); + g_free(location); + g_free(description); + g_free(buf); + + break; + } + default: + ; + } + + return GST_BASE_SINK_CLASS(parent_class)->event(sink, event); +} + GType gst_polypsink_get_type(void) { static GType polypsink_type = 0; diff --git a/src/polypsink.h b/src/polypsink.h index 4b9a76b..e5e98d0 100644 --- a/src/polypsink.h +++ b/src/polypsink.h @@ -47,7 +47,7 @@ typedef struct _GstPolypSinkClass GstPolypSinkClass; struct _GstPolypSink { GstAudioSink sink; - gchar *server, *device; + gchar *server, *device, *stream_name; pa_threaded_mainloop *mainloop; -- cgit