rpms/gstreamer-plugins-good/F-11 gstreamer-plugins-good.spec, 1.101, 1.102 pulsesink-lowering-volumes.patch, 1.1, 1.2

Bastien Nocera hadess at fedoraproject.org
Sat Oct 17 01:21:16 UTC 2009


Author: hadess

Update of /cvs/pkgs/rpms/gstreamer-plugins-good/F-11
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv20049

Modified Files:
	gstreamer-plugins-good.spec pulsesink-lowering-volumes.patch 
Log Message:
* Sat Oct 17 2009 Bastien Nocera <bnocera at redhat.com> 0.10.16-3
- Finally fix pulsesink volume lowering problems (#488532)



Index: gstreamer-plugins-good.spec
===================================================================
RCS file: /cvs/pkgs/rpms/gstreamer-plugins-good/F-11/gstreamer-plugins-good.spec,v
retrieving revision 1.101
retrieving revision 1.102
diff -u -p -r1.101 -r1.102
--- gstreamer-plugins-good.spec	17 Oct 2009 00:50:45 -0000	1.101
+++ gstreamer-plugins-good.spec	17 Oct 2009 01:21:16 -0000	1.102
@@ -74,6 +74,7 @@ Provides: gstreamer-plugins-farsight = 0
 Obsoletes: gstreamer-plugins-farsight < 0.12.12
 
 # http://bugzilla.gnome.org/show_bug.cgi?id=595231
+# and many others
 Patch2: pulsesink-lowering-volumes.patch
 
 %description

pulsesink-lowering-volumes.patch:
 pulsemixer.c     |   14 +-
 pulsemixerctrl.c |   77 ++++++++------
 pulsemixerctrl.h |   13 +-
 pulseprobe.c     |   27 +++-
 pulseprobe.h     |   13 +-
 pulsesink.c      |  299 +++++++++++++++++++++++++++++++++++++++++++------------
 pulsesink.h      |   14 +-
 pulsesrc.c       |   54 +++++----
 pulsesrc.h       |   10 +
 9 files changed, 374 insertions(+), 147 deletions(-)

Index: pulsesink-lowering-volumes.patch
===================================================================
RCS file: /cvs/pkgs/rpms/gstreamer-plugins-good/F-11/pulsesink-lowering-volumes.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -p -r1.1 -r1.2
--- pulsesink-lowering-volumes.patch	17 Oct 2009 00:50:45 -0000	1.1
+++ pulsesink-lowering-volumes.patch	17 Oct 2009 01:21:16 -0000	1.2
@@ -1,26 +1,630 @@
-From cee7048dcd68f1d3cca3651a5aaef11145390fa4 Mon Sep 17 00:00:00 2001
-From: Lennart Poettering <lennart at poettering.net>
-Date: Sat, 17 Oct 2009 02:18:53 +0200
-Subject: [PATCH] pulse: never apply volume more than once
-
-Generally decisions on the volume of the stream should be done inside of
-PA, not inside of Gst. Only PA knows how volumes translate between
-devices and s on.
-
-This patch makes sure that all volumes set via the volume property are
-only applied *once* to the underlying stream. After applying them the
-client side will not store them anymore. This should make sure that
-really only user-triggered volume changes are forwarded to server, but
-the client never tries to save/restore the volume internally.
----
- ext/pulse/pulsesink.c |   34 ++++++++++++++++++++--------------
- 1 files changed, 20 insertions(+), 14 deletions(-)
-
+diff --git a/ext/pulse/pulsemixer.c b/ext/pulse/pulsemixer.c
+index 99d33ae..ab99c55 100644
+--- a/ext/pulse/pulsemixer.c
++++ b/ext/pulse/pulsemixer.c
+@@ -252,6 +252,7 @@ static GstStateChangeReturn
+ gst_pulsemixer_change_state (GstElement * element, GstStateChange transition)
+ {
+   GstPulseMixer *this = GST_PULSEMIXER (element);
++  GstStateChangeReturn res;
+ 
+   switch (transition) {
+     case GST_STATE_CHANGE_NULL_TO_READY:
+@@ -260,19 +261,22 @@ gst_pulsemixer_change_state (GstElement * element, GstStateChange transition)
+             gst_pulsemixer_ctrl_new (G_OBJECT (this), this->server,
+             this->device, GST_PULSEMIXER_UNKNOWN);
+       break;
++    default:
++      ;
++  }
++
++  res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
++
++  switch (transition) {
+     case GST_STATE_CHANGE_READY_TO_NULL:
+       if (this->mixer) {
+         gst_pulsemixer_ctrl_free (this->mixer);
+         this->mixer = NULL;
+       }
+       break;
+-
+     default:
+       ;
+   }
+ 
+-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+-    return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+-
+-  return GST_STATE_CHANGE_SUCCESS;
++  return res;
+ }
+diff --git a/ext/pulse/pulsemixerctrl.c b/ext/pulse/pulsemixerctrl.c
+index ae807c6..760bd3e 100644
+--- a/ext/pulse/pulsemixerctrl.c
++++ b/ext/pulse/pulsemixerctrl.c
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
++
+ /*
+  *  GStreamer pulseaudio plugin
+  *
+@@ -74,7 +76,7 @@ gst_pulsemixer_ctrl_sink_info_cb (pa_context * context, const pa_sink_info * i,
+   }
+ 
+   if (!i && eol < 0) {
+-    c->operation_success = 0;
++    c->operation_success = FALSE;
+     pa_threaded_mainloop_signal (c->mainloop, 0);
+     return;
+   }
+@@ -89,7 +91,7 @@ gst_pulsemixer_ctrl_sink_info_cb (pa_context * context, const pa_sink_info * i,
+   c->index = i->index;
+   c->channel_map = i->channel_map;
+   c->volume = i->volume;
+-  c->muted = i->mute;
++  c->muted = !!i->mute;
+   c->type = GST_PULSEMIXER_SINK;
+ 
+   if (c->track) {
+@@ -100,7 +102,7 @@ gst_pulsemixer_ctrl_sink_info_cb (pa_context * context, const pa_sink_info * i,
+     c->track->flags = flags;
+   }
+ 
+-  c->operation_success = 1;
++  c->operation_success = TRUE;
+   pa_threaded_mainloop_signal (c->mainloop, 0);
+ }
+ 
+@@ -124,7 +126,7 @@ gst_pulsemixer_ctrl_source_info_cb (pa_context * context,
+   }
+ 
+   if (!i && eol < 0) {
+-    c->operation_success = 0;
++    c->operation_success = FALSE;
+     pa_threaded_mainloop_signal (c->mainloop, 0);
+     return;
+   }
+@@ -139,7 +141,7 @@ gst_pulsemixer_ctrl_source_info_cb (pa_context * context,
+   c->index = i->index;
+   c->channel_map = i->channel_map;
+   c->volume = i->volume;
+-  c->muted = i->mute;
++  c->muted = !!i->mute;
+   c->type = GST_PULSEMIXER_SOURCE;
+ 
+   if (c->track) {
+@@ -150,7 +152,7 @@ gst_pulsemixer_ctrl_source_info_cb (pa_context * context,
+     c->track->flags = flags;
+   }
+ 
+-  c->operation_success = 1;
++  c->operation_success = TRUE;
+   pa_threaded_mainloop_signal (c->mainloop, 0);
+ }
+ 
+@@ -193,31 +195,40 @@ gst_pulsemixer_ctrl_success_cb (pa_context * context, int success,
+ {
+   GstPulseMixerCtrl *c = (GstPulseMixerCtrl *) userdata;
+ 
+-  c->operation_success = success;
++  c->operation_success = !!success;
+   pa_threaded_mainloop_signal (c->mainloop, 0);
+ }
+ 
+-#define CHECK_DEAD_GOTO(c, label) do { \
+-if (!(c)->context || pa_context_get_state((c)->context) != PA_CONTEXT_READY) { \
+-    GST_WARNING_OBJECT (c->object, "Not connected: %s", (c)->context ? pa_strerror(pa_context_errno((c)->context)) : "NULL"); \
+-    goto label; \
+-} \
+-} while(0);
++#define CHECK_DEAD_GOTO(c, label)                                       \
++  G_STMT_START {                                                        \
++    if (!(c)->context ||                                                \
++        !PA_CONTEXT_IS_GOOD(pa_context_get_state((c)->context))) {      \
++      GST_WARNING_OBJECT ((c)->object, "Not connected: %s",             \
++                          (c)->context ? pa_strerror(pa_context_errno((c)->context)) : "NULL"); \
++      goto label;                                                       \
++    }                                                                   \
++  } G_STMT_END
+ 
+ static gboolean
+ gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+ {
+   int e;
+-  gchar *name = gst_pulse_client_name ();
++  gchar *name;
+   pa_operation *o = NULL;
+ 
+   g_assert (c);
+ 
++  GST_DEBUG_OBJECT (c->object, "ctrl open");
++
+   c->mainloop = pa_threaded_mainloop_new ();
+-  g_assert (c->mainloop);
++  if (!c->mainloop)
++    return FALSE;
+ 
+   e = pa_threaded_mainloop_start (c->mainloop);
+-  g_assert (e == 0);
++  if (e < 0)
++    return FALSE;
++
++  name = gst_pulse_client_name ();
+ 
+   pa_threaded_mainloop_lock (c->mainloop);
+ 
+@@ -239,16 +250,12 @@ gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+   }
+ 
+   /* Wait until the context is ready */
+-  pa_threaded_mainloop_wait (c->mainloop);
+-
+-  if (pa_context_get_state (c->context) != PA_CONTEXT_READY) {
+-    GST_WARNING_OBJECT (c->object, "Failed to connect context: %s",
+-        pa_strerror (pa_context_errno (c->context)));
+-    goto unlock_and_fail;
++  while (pa_context_get_state (c->context) != PA_CONTEXT_READY) {
++    CHECK_DEAD_GOTO (c, unlock_and_fail);
++    pa_threaded_mainloop_wait (c->mainloop);
+   }
+ 
+   /* Subscribe to events */
+-
+   if (!(o =
+           pa_context_subscribe (c->context,
+               PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
+@@ -258,10 +265,10 @@ gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+     goto unlock_and_fail;
+   }
+ 
+-  c->operation_success = 0;
++  c->operation_success = FALSE;
+   while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
+-    pa_threaded_mainloop_wait (c->mainloop);
+     CHECK_DEAD_GOTO (c, unlock_and_fail);
++    pa_threaded_mainloop_wait (c->mainloop);
+   }
+ 
+   if (!c->operation_success) {
+@@ -275,6 +282,7 @@ gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+   /* Get sink info */
+ 
+   if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SINK) {
++    GST_WARNING_OBJECT (c->object, "Get info for '%s'", c->device);
+     if (!(o =
+             pa_context_get_sink_info_by_name (c->context, c->device,
+                 gst_pulsemixer_ctrl_sink_info_cb, c))) {
+@@ -283,10 +291,10 @@ gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+       goto unlock_and_fail;
+     }
+ 
+-    c->operation_success = 0;
++    c->operation_success = FALSE;
+     while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
+-      pa_threaded_mainloop_wait (c->mainloop);
+       CHECK_DEAD_GOTO (c, unlock_and_fail);
++      pa_threaded_mainloop_wait (c->mainloop);
+     }
+ 
+     pa_operation_unref (o);
+@@ -309,10 +317,10 @@ gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+       goto unlock_and_fail;
+     }
+ 
+-    c->operation_success = 0;
++    c->operation_success = FALSE;
+     while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
+-      pa_threaded_mainloop_wait (c->mainloop);
+       CHECK_DEAD_GOTO (c, unlock_and_fail);
++      pa_threaded_mainloop_wait (c->mainloop);
+     }
+ 
+     pa_operation_unref (o);
+@@ -353,6 +361,8 @@ gst_pulsemixer_ctrl_close (GstPulseMixerCtrl * c)
+ {
+   g_assert (c);
+ 
++  GST_DEBUG_OBJECT (c->object, "ctrl close");
++
+   if (c->mainloop)
+     pa_threaded_mainloop_stop (c->mainloop);
+ 
+@@ -386,6 +396,7 @@ gst_pulsemixer_ctrl_new (GObject * object, const gchar * server,
+ {
+   GstPulseMixerCtrl *c = NULL;
+ 
++  GST_DEBUG_OBJECT (object, "new mixer ctrl for %s", device);
+   c = g_new (GstPulseMixerCtrl, 1);
+   c->object = g_object_ref (object);
+   c->tracklist = NULL;
+@@ -398,7 +409,7 @@ gst_pulsemixer_ctrl_new (GObject * object, const gchar * server,
+ 
+   pa_cvolume_mute (&c->volume, PA_CHANNELS_MAX);
+   pa_channel_map_init (&c->channel_map);
+-  c->muted = 0;
++  c->muted = FALSE;
+   c->index = PA_INVALID_INDEX;
+   c->type = type;
+   c->name = NULL;
+@@ -464,10 +475,10 @@ gst_pulsemixer_ctrl_timeout_event (pa_mainloop_api * a, pa_time_event * e,
+ 
+   if (c->update_mute) {
+     if (c->type == GST_PULSEMIXER_SINK)
+-      o = pa_context_set_sink_mute_by_index (c->context, c->index, !!c->muted,
++      o = pa_context_set_sink_mute_by_index (c->context, c->index, c->muted,
+           NULL, NULL);
+     else
+-      o = pa_context_set_source_mute_by_index (c->context, c->index, !!c->muted,
++      o = pa_context_set_source_mute_by_index (c->context, c->index, c->muted,
+           NULL, NULL);
+ 
+     if (!o)
+@@ -570,7 +581,7 @@ gst_pulsemixer_ctrl_set_mute (GstPulseMixerCtrl * c, GstMixerTrack * track,
+ 
+   pa_threaded_mainloop_lock (c->mainloop);
+ 
+-  c->muted = !!mute;
++  c->muted = mute;
+   c->update_mute = TRUE;
+ 
+   if (c->track) {
+diff --git a/ext/pulse/pulsemixerctrl.h b/ext/pulse/pulsemixerctrl.h
+index 0dbc139..e6b67ad 100644
+--- a/ext/pulse/pulsemixerctrl.h
++++ b/ext/pulse/pulsemixerctrl.h
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
++
+ /*
+  *  GStreamer pulseaudio plugin
+  *
+@@ -53,11 +55,17 @@ struct _GstPulseMixerCtrl
+ 
+   gchar *name, *description;
+   pa_channel_map channel_map;
++
+   pa_cvolume volume;
+-  int muted;
++  gboolean muted:1;
++
++  gboolean update_volume:1;
++  gboolean update_mute:1;
++
++  gboolean operation_success:1;
++
+   guint32 index;
+   GstPulseMixerType type;
+-  int operation_success;
+ 
+   GstMixerTrack *track;
+ 
+@@ -66,7 +74,6 @@ struct _GstPulseMixerCtrl
+   int outstandig_queries;
+   int ignore_queries;
+ 
+-  gboolean update_volume, update_mute;
+ };
+ 
+ GstPulseMixerCtrl *gst_pulsemixer_ctrl_new (GObject *object, const gchar * server,
+diff --git a/ext/pulse/pulseprobe.c b/ext/pulse/pulseprobe.c
+index 588a9c3..6ebbfb2 100644
+--- a/ext/pulse/pulseprobe.c
++++ b/ext/pulse/pulseprobe.c
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
++
+ /*
+  *  GStreamer pulseaudio plugin
+  *
+@@ -99,15 +101,21 @@ static gboolean
+ gst_pulseprobe_open (GstPulseProbe * c)
+ {
+   int e;
+-  gchar *name = gst_pulse_client_name ();
++  gchar *name;
+ 
+   g_assert (c);
+ 
++  GST_DEBUG_OBJECT (c->object, "probe open");
++
+   c->mainloop = pa_threaded_mainloop_new ();
+-  g_assert (c->mainloop);
++  if (!c->mainloop)
++    return FALSE;
+ 
+   e = pa_threaded_mainloop_start (c->mainloop);
+-  g_assert (e == 0);
++  if (e < 0)
++    return FALSE;
++
++  name = gst_pulse_client_name ();
+ 
+   pa_threaded_mainloop_lock (c->mainloop);
+ 
+@@ -184,6 +192,8 @@ gst_pulseprobe_enumerate (GstPulseProbe * c)
+ {
+   pa_operation *o = NULL;
+ 
++  GST_DEBUG_OBJECT (c->object, "probe enumerate");
++
+   pa_threaded_mainloop_lock (c->mainloop);
+ 
+   if (c->enumerate_sinks) {
+@@ -197,7 +207,7 @@ gst_pulseprobe_enumerate (GstPulseProbe * c)
+       goto unlock_and_fail;
+     }
+ 
+-    c->operation_success = 0;
++    c->operation_success = FALSE;
+ 
+     while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ 
+@@ -228,7 +238,7 @@ gst_pulseprobe_enumerate (GstPulseProbe * c)
+       goto unlock_and_fail;
+     }
+ 
+-    c->operation_success = 0;
++    c->operation_success = FALSE;
+     while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ 
+       if (gst_pulseprobe_is_dead (c))
+@@ -268,6 +278,8 @@ gst_pulseprobe_close (GstPulseProbe * c)
+ {
+   g_assert (c);
+ 
++  GST_DEBUG_OBJECT (c->object, "probe close");
++
+   if (c->mainloop)
+     pa_threaded_mainloop_stop (c->mainloop);
+ 
+@@ -302,8 +314,11 @@ gst_pulseprobe_new (GObject * object, GObjectClass * klass,
+   c->prop_id = prop_id;
+   c->properties =
+       g_list_append (NULL, g_object_class_find_property (klass, "device"));
++
+   c->devices = NULL;
+-  c->devices_valid = 0;
++  c->devices_valid = FALSE;
++
++  c->operation_success = FALSE;
+ 
+   return c;
+ }
+diff --git a/ext/pulse/pulseprobe.h b/ext/pulse/pulseprobe.h
+index bd20591..28cdbb8 100644
+--- a/ext/pulse/pulseprobe.h
++++ b/ext/pulse/pulseprobe.h
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
++
+ /*
+  *  GStreamer pulseaudio plugin
+  *
+@@ -36,17 +38,20 @@ struct _GstPulseProbe
+ {
+   GObject *object;
+   gchar *server;
++
+   GList *devices;
+-  gboolean devices_valid;
++  gboolean devices_valid:1;
++
++  gboolean operation_success:1;
++
++  gboolean enumerate_sinks:1;
++  gboolean enumerate_sources:1;
+ 
+   pa_threaded_mainloop *mainloop;
+   pa_context *context;
+ 
+   GList *properties;
+   guint prop_id;
+-
+-  int enumerate_sinks, enumerate_sources;
+-  int operation_success;
+ };
+ 
+ GstPulseProbe *gst_pulseprobe_new (GObject *object, GObjectClass * klass,
 diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c
-index dd47c33..1fe2b72 100644
+index 7ead4fe..1fe2b72 100644
 --- a/ext/pulse/pulsesink.c
 +++ b/ext/pulse/pulsesink.c
-@@ -730,6 +730,10 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
++
+ /*  GStreamer pulseaudio plugin
+  *
+  *  Copyright (c) 2004-2008 Lennart Poettering
+@@ -46,6 +48,8 @@
+ 
+ #include <gst/base/gstbasesink.h>
+ #include <gst/gsttaglist.h>
++#include <gst/interfaces/streamvolume.h>
++#include <gst/gst-i18n-plugin.h>
+ 
+ #include "pulsesink.h"
+ #include "pulseutil.h"
+@@ -62,6 +66,7 @@ GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+ #define DEFAULT_DEVICE          NULL
+ #define DEFAULT_DEVICE_NAME     NULL
+ #define DEFAULT_VOLUME          1.0
++#define DEFAULT_MUTE            FALSE
+ #define MAX_VOLUME              10.0
+ 
+ enum
+@@ -71,6 +76,7 @@ enum
+   PROP_DEVICE,
+   PROP_DEVICE_NAME,
+   PROP_VOLUME,
++  PROP_MUTE,
+   PROP_LAST
+ };
+ 
+@@ -105,12 +111,10 @@ struct _GstPulseRingBuffer
+   pa_stream *stream;
+ 
+   pa_sample_spec sample_spec;
+-  gint64 offset;
+ 
+-  gboolean corked;
+-  gboolean in_commit;
+-  gboolean paused;
+-  guint required;
++  gboolean corked:1;
++  gboolean in_commit:1;
++  gboolean paused:1;
+ };
+ 
+ struct _GstPulseRingBufferClass
+@@ -216,8 +220,9 @@ gst_pulseringbuffer_init (GstPulseRingBuffer * pbuf,
+   pbuf->sample_spec.channels = 0;
+ #endif
+ 
+-  pbuf->paused = FALSE;
+   pbuf->corked = TRUE;
++  pbuf->in_commit = FALSE;
++  pbuf->paused = FALSE;
+ }
+ 
+ static void
+@@ -543,6 +548,10 @@ gst_pulsering_stream_latency_cb (pa_stream * s, void *userdata)
+   pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+   psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+ 
++  if (!info) {
++    GST_LOG_OBJECT (psink, "latency update (information unknown)");
++    return;
++  }
+ #if HAVE_PULSE_0_9_11
+   sink_usec = info->configured_sink_usec;
+ #else
+@@ -557,6 +566,35 @@ gst_pulsering_stream_latency_cb (pa_stream * s, void *userdata)
+       info->sink_usec, sink_usec);
+ }
+ 
++#if HAVE_PULSE_0_9_15
++static void
++gst_pulsering_stream_event_cb (pa_stream * p, const char *name,
++    pa_proplist * pl, void *userdata)
++{
++  GstPulseSink *psink;
++  GstPulseRingBuffer *pbuf;
++
++  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
++  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
++
++  if (!strcmp (name, PA_STREAM_EVENT_REQUEST_CORK)) {
++    /* the stream wants to PAUSE, post a message for the application. */
++    GST_DEBUG_OBJECT (psink, "got request for CORK");
++    gst_element_post_message (GST_ELEMENT_CAST (psink),
++        gst_message_new_request_state (GST_OBJECT_CAST (psink),
++            GST_STATE_PAUSED));
++
++  } else if (!strcmp (name, PA_STREAM_EVENT_REQUEST_UNCORK)) {
++    GST_DEBUG_OBJECT (psink, "got request for UNCORK");
++    gst_element_post_message (GST_ELEMENT_CAST (psink),
++        gst_message_new_request_state (GST_OBJECT_CAST (psink),
++            GST_STATE_PLAYING));
++  } else {
++    GST_DEBUG_OBJECT (psink, "got unknown event %s", name);
++  }
++}
++#endif
++
+ /* This method should create a new stream of the given @spec. No playback should
+  * start yet so we start in the corked state. */
+ static gboolean
+@@ -564,15 +602,14 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+ {
+   GstPulseSink *psink;
+   GstPulseRingBuffer *pbuf;
+-  pa_buffer_attr buf_attr;
+-  const pa_buffer_attr *buf_attr_ptr;
++  pa_buffer_attr wanted;
++  const pa_buffer_attr *actual;
+   pa_channel_map channel_map;
+   pa_operation *o = NULL;
+   pa_cvolume v, *pv;
+   pa_stream_flags_t flags;
+   const gchar *name;
+   GstAudioClock *clock;
+-  gint64 time_offset;
+ 
+   psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+   pbuf = GST_PULSERING_BUFFER_CAST (buf);
+@@ -622,19 +659,23 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+       gst_pulsering_stream_overflow_cb, pbuf);
+   pa_stream_set_latency_update_callback (pbuf->stream,
+       gst_pulsering_stream_latency_cb, pbuf);
++#if HAVE_PULSE_0_9_15
++  pa_stream_set_event_callback (pbuf->stream,
++      gst_pulsering_stream_event_cb, pbuf);
++#endif
+ 
+   /* buffering requirements. When setting prebuf to 0, the stream will not pause
+    * when we cause an underrun, which causes time to continue. */
+-  memset (&buf_attr, 0, sizeof (buf_attr));
+-  buf_attr.tlength = spec->segtotal * spec->segsize;
+-  buf_attr.maxlength = -1;
+-  buf_attr.prebuf = 0;
+-  buf_attr.minreq = -1;
++  memset (&wanted, 0, sizeof (wanted));
++  wanted.tlength = spec->segtotal * spec->segsize;
++  wanted.maxlength = -1;
++  wanted.prebuf = 0;
++  wanted.minreq = spec->segsize;
+ 
+-  GST_INFO_OBJECT (psink, "tlength:   %d", buf_attr.tlength);
+-  GST_INFO_OBJECT (psink, "maxlength: %d", buf_attr.maxlength);
+-  GST_INFO_OBJECT (psink, "prebuf:    %d", buf_attr.prebuf);
+-  GST_INFO_OBJECT (psink, "minreq:    %d", buf_attr.minreq);
++  GST_INFO_OBJECT (psink, "tlength:   %d", wanted.tlength);
++  GST_INFO_OBJECT (psink, "maxlength: %d", wanted.maxlength);
++  GST_INFO_OBJECT (psink, "prebuf:    %d", wanted.prebuf);
++  GST_INFO_OBJECT (psink, "minreq:    %d", wanted.minreq);
+ 
+   /* configure volume when we changed it, else we leave the default */
+   if (psink->volume_set) {
+@@ -653,6 +694,11 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+ #endif
+       PA_STREAM_START_CORKED;
+ 
++#if HAVE_PULSE_0_9_12
++  if (psink->mute_set && psink->mute)
++    flags |= PA_STREAM_START_MUTED;
++#endif
++
+   /* we always start corked (see flags above) */
+   pbuf->corked = TRUE;
+ 
+@@ -660,25 +706,12 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+   GST_LOG_OBJECT (psink, "connect for playback to device %s",
+       GST_STR_NULL (psink->device));
+   if (pa_stream_connect_playback (pbuf->stream, psink->device,
+-          &buf_attr, flags, pv, NULL) < 0)
++          &wanted, flags, pv, NULL) < 0)
+     goto connect_failed;
+ 
+   /* our clock will now start from 0 again */
+   clock = GST_AUDIO_CLOCK (GST_BASE_AUDIO_SINK (psink)->provided_clock);
+   gst_audio_clock_reset (clock, 0);
+-  time_offset = clock->abidata.ABI.time_offset;
+-
+-  GST_LOG_OBJECT (psink, "got time offset %" GST_TIME_FORMAT,
+-      GST_TIME_ARGS (time_offset));
+-
+-  /* calculate the sample offset for 0 */
+-  if (time_offset > 0)
+-    pbuf->offset = gst_util_uint64_scale_int (time_offset,
+-        pbuf->sample_spec.rate, GST_SECOND);
+-  else
+-    pbuf->offset = -gst_util_uint64_scale_int (-time_offset,
+-        pbuf->sample_spec.rate, GST_SECOND);
+-  GST_LOG_OBJECT (psink, "sample offset %" G_GINT64_FORMAT, pbuf->offset);
+ 
+   for (;;) {
+     pa_stream_state_t state;
+@@ -697,20 +730,24 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
      pa_threaded_mainloop_wait (psink->mainloop);
    }
  
@@ -31,18 +635,93 @@ index dd47c33..1fe2b72 100644
    GST_LOG_OBJECT (psink, "stream is acquired now");
  
    /* get the actual buffering properties now */
-@@ -1527,8 +1531,8 @@ gst_pulsesink_class_init (GstPulseSinkClass * klass)
+-  buf_attr_ptr = pa_stream_get_buffer_attr (pbuf->stream);
++  actual = pa_stream_get_buffer_attr (pbuf->stream);
+ 
+-  GST_INFO_OBJECT (psink, "tlength:   %d (wanted: %d)", buf_attr_ptr->tlength,
+-      buf_attr.tlength);
+-  GST_INFO_OBJECT (psink, "maxlength: %d", buf_attr_ptr->maxlength);
+-  GST_INFO_OBJECT (psink, "prebuf:    %d", buf_attr_ptr->prebuf);
+-  GST_INFO_OBJECT (psink, "minreq:    %d (wanted %d)", buf_attr_ptr->minreq,
+-      buf_attr.minreq);
++  GST_INFO_OBJECT (psink, "tlength:   %d (wanted: %d)", actual->tlength,
++      wanted.tlength);
++  GST_INFO_OBJECT (psink, "maxlength: %d", actual->maxlength);
++  GST_INFO_OBJECT (psink, "prebuf:    %d", actual->prebuf);
++  GST_INFO_OBJECT (psink, "minreq:    %d (wanted %d)", actual->minreq,
++      wanted.minreq);
+ 
+-  spec->segsize = buf_attr_ptr->minreq;
+-  spec->segtotal = buf_attr_ptr->tlength / spec->segsize;
++  spec->segsize = actual->minreq;
++  spec->segtotal = actual->tlength / spec->segsize;
+ 
+   pa_threaded_mainloop_unlock (psink->mainloop);
+ 
+@@ -1096,8 +1133,10 @@ gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
+   psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+ 
+   /* FIXME post message rather than using a signal (as mixer interface) */
+-  if (g_atomic_int_compare_and_exchange (&psink->notify, 1, 0))
++  if (g_atomic_int_compare_and_exchange (&psink->notify, 1, 0)) {
+     g_object_notify (G_OBJECT (psink), "volume");
++    g_object_notify (G_OBJECT (psink), "mute");
++  }
+ 
+   /* make sure the ringbuffer is started */
+   if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
+@@ -1139,21 +1178,8 @@ gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
+   if (pbuf->paused)
+     goto was_paused;
+ 
+-  /* correct for sample offset against the internal clock */
+-  offset = *sample;
+-  if (pbuf->offset >= 0) {
+-    if (offset > pbuf->offset)
+-      offset -= pbuf->offset;
+-    else
+-      offset = 0;
+-  } else {
+-    if (offset > -pbuf->offset)
+-      offset += pbuf->offset;
+-    else
+-      offset = 0;
+-  }
+   /* offset is in bytes */
+-  offset *= bps;
++  offset = *sample * bps;
+ 
+   while (*toprocess > 0) {
+     size_t avail;
+@@ -1375,6 +1401,13 @@ gst_pulsesink_init_interfaces (GType type)
+     NULL,
+     NULL,
+   };
++#if HAVE_PULSE_0_9_12
++  static const GInterfaceInfo svol_iface_info = {
++    NULL, NULL, NULL
++  };
++
++  g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_iface_info);
++#endif
+ 
+   g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
+       &implements_iface_info);
+@@ -1498,7 +1531,12 @@ gst_pulsesink_class_init (GstPulseSinkClass * klass)
    g_object_class_install_property (gobject_class,
        PROP_VOLUME,
        g_param_spec_double ("volume", "Volume",
 -          "Volume of this stream, 1.0=100%", 0.0, MAX_VOLUME, DEFAULT_VOLUME,
--          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 +          "Linear volume of this stream, 1.0=100%", 0.0, MAX_VOLUME,
 +          DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-   g_object_class_install_property (gobject_class,
-       PROP_MUTE,
-       g_param_spec_boolean ("mute", "Mute",
-@@ -1588,10 +1592,10 @@ gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass)
++  g_object_class_install_property (gobject_class,
++      PROP_MUTE,
++      g_param_spec_boolean ("mute", "Mute",
++          "Mute state of this stream", DEFAULT_MUTE,
+           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ #endif
+ }
+@@ -1554,9 +1592,12 @@ gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass)
    pulsesink->device = NULL;
    pulsesink->device_description = NULL;
  
@@ -50,12 +729,13 @@ index dd47c33..1fe2b72 100644
 +  pulsesink->volume = DEFAULT_VOLUME;
    pulsesink->volume_set = FALSE;
  
--  pulsesink->mute = FALSE;
 +  pulsesink->mute = DEFAULT_MUTE;
-   pulsesink->mute_set = FALSE;
- 
++  pulsesink->mute_set = FALSE;
++
    pulsesink->notify = 0;
-@@ -1654,9 +1658,6 @@ gst_pulsesink_set_volume (GstPulseSink * psink, gdouble volume)
+ 
+   /* needed for conditional execution */
+@@ -1617,9 +1658,6 @@ gst_pulsesink_set_volume (GstPulseSink * psink, gdouble volume)
  
    GST_DEBUG_OBJECT (psink, "setting volume to %f", volume);
  
@@ -65,7 +745,7 @@ index dd47c33..1fe2b72 100644
    pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
    if (pbuf == NULL || pbuf->stream == NULL)
      goto no_buffer;
-@@ -1683,6 +1684,9 @@ unlock:
+@@ -1646,6 +1684,9 @@ unlock:
    /* ERRORS */
  no_buffer:
    {
@@ -75,27 +755,81 @@ index dd47c33..1fe2b72 100644
      GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
      goto unlock;
    }
-@@ -1711,9 +1715,6 @@ gst_pulsesink_set_mute (GstPulseSink * psink, gboolean mute)
- 
-   GST_DEBUG_OBJECT (psink, "setting mute state to %d", mute);
+@@ -1664,6 +1705,61 @@ volume_failed:
+ }
  
--  psink->mute = mute;
--  psink->mute_set = TRUE;
--
-   pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
-   if (pbuf == NULL || pbuf->stream == NULL)
-     goto no_buffer;
-@@ -1738,6 +1739,9 @@ unlock:
-   /* ERRORS */
- no_buffer:
-   {
+ static void
++gst_pulsesink_set_mute (GstPulseSink * psink, gboolean mute)
++{
++  pa_operation *o = NULL;
++  GstPulseRingBuffer *pbuf;
++  uint32_t idx;
++
++  pa_threaded_mainloop_lock (psink->mainloop);
++
++  GST_DEBUG_OBJECT (psink, "setting mute state to %d", mute);
++
++  pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
++  if (pbuf == NULL || pbuf->stream == NULL)
++    goto no_buffer;
++
++  if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
++    goto no_index;
++
++  if (!(o = pa_context_set_sink_input_mute (pbuf->context, idx,
++              mute, NULL, NULL)))
++    goto mute_failed;
++
++  /* We don't really care about the result of this call */
++unlock:
++
++  if (o)
++    pa_operation_unref (o);
++
++  pa_threaded_mainloop_unlock (psink->mainloop);
++
++  return;
++
++  /* ERRORS */
++no_buffer:
++  {
 +    psink->mute = mute;
 +    psink->mute_set = TRUE;
 +
-     GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
-     goto unlock;
-   }
-@@ -1788,7 +1792,7 @@ gst_pulsesink_get_volume (GstPulseSink * psink)
++    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
++    goto unlock;
++  }
++no_index:
++  {
++    GST_DEBUG_OBJECT (psink, "we don't have a stream index");
++    goto unlock;
++  }
++mute_failed:
++  {
++    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
++        ("pa_stream_set_sink_input_mute() failed: %s",
++            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
++    goto unlock;
++  }
++}
++
++static void
+ gst_pulsesink_sink_input_info_cb (pa_context * c, const pa_sink_input_info * i,
+     int eol, void *userdata)
+ {
+@@ -1682,8 +1778,10 @@ gst_pulsesink_sink_input_info_cb (pa_context * c, const pa_sink_input_info * i,
+   /* If the index doesn't match our current stream,
+    * it implies we just recreated the stream (caps change)
+    */
+-  if (i->index == pa_stream_get_index (pbuf->stream))
++  if (i->index == pa_stream_get_index (pbuf->stream)) {
+     psink->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume));
++    psink->mute = i->mute;
++  }
+ 
+ done:
+   pa_threaded_mainloop_signal (psink->mainloop, 0);
+@@ -1694,7 +1792,7 @@ gst_pulsesink_get_volume (GstPulseSink * psink)
  {
    GstPulseRingBuffer *pbuf;
    pa_operation *o = NULL;
@@ -104,7 +838,7 @@ index dd47c33..1fe2b72 100644
    uint32_t idx;
  
    pa_threaded_mainloop_lock (psink->mainloop);
-@@ -1810,11 +1814,12 @@ gst_pulsesink_get_volume (GstPulseSink * psink)
+@@ -1716,11 +1814,12 @@ gst_pulsesink_get_volume (GstPulseSink * psink)
        goto unlock;
    }
  
@@ -118,29 +852,257 @@ index dd47c33..1fe2b72 100644
    pa_threaded_mainloop_unlock (psink->mainloop);
  
    if (v > MAX_VOLUME) {
-@@ -1850,7 +1855,7 @@ gst_pulsesink_get_mute (GstPulseSink * psink)
-   GstPulseRingBuffer *pbuf;
-   pa_operation *o = NULL;
-   uint32_t idx;
--  gboolean mute;
+@@ -1749,6 +1848,63 @@ info_failed:
+     goto unlock;
+   }
+ }
++
++static gboolean
++gst_pulsesink_get_mute (GstPulseSink * psink)
++{
++  GstPulseRingBuffer *pbuf;
++  pa_operation *o = NULL;
++  uint32_t idx;
 +  gboolean mute = FALSE;
++
++  pa_threaded_mainloop_lock (psink->mainloop);
++
++  pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
++  if (pbuf == NULL || pbuf->stream == NULL)
++    goto no_buffer;
++
++  if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
++    goto no_index;
++
++  if (!(o = pa_context_get_sink_input_info (pbuf->context, idx,
++              gst_pulsesink_sink_input_info_cb, pbuf)))
++    goto info_failed;
++
++  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
++    pa_threaded_mainloop_wait (psink->mainloop);
++    if (gst_pulsering_is_dead (psink, pbuf))
++      goto unlock;
++  }
++
++  mute = psink->mute;
++
++unlock:
++  if (o)
++    pa_operation_unref (o);
++
++  pa_threaded_mainloop_unlock (psink->mainloop);
++
++  return mute;
++
++  /* ERRORS */
++no_buffer:
++  {
++    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
++    goto unlock;
++  }
++no_index:
++  {
++    GST_DEBUG_OBJECT (psink, "we don't have a stream index");
++    goto unlock;
++  }
++info_failed:
++  {
++    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
++        ("pa_context_get_sink_input_info() failed: %s",
++            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
++    goto unlock;
++  }
++}
+ #endif
  
-   pa_threaded_mainloop_lock (psink->mainloop);
+ static void
+@@ -1844,6 +2000,9 @@ gst_pulsesink_set_property (GObject * object,
+     case PROP_VOLUME:
+       gst_pulsesink_set_volume (pulsesink, g_value_get_double (value));
+       break;
++    case PROP_MUTE:
++      gst_pulsesink_set_mute (pulsesink, g_value_get_boolean (value));
++      break;
+ #endif
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+@@ -1872,6 +2031,9 @@ gst_pulsesink_get_property (GObject * object,
+     case PROP_VOLUME:
+       g_value_set_double (value, gst_pulsesink_get_volume (pulsesink));
+       break;
++    case PROP_MUTE:
++      g_value_set_boolean (value, gst_pulsesink_get_mute (pulsesink));
++      break;
+ #endif
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+@@ -1927,6 +2089,10 @@ gst_pulsesink_change_props (GstPulseSink * psink, GstTagList * l)
+ {
+   static const gchar *const map[] = {
+     GST_TAG_TITLE, PA_PROP_MEDIA_TITLE,
++
++    /* might get overriden in the next iteration by GST_TAG_ARTIST */
++    GST_TAG_PERFORMER, PA_PROP_MEDIA_ARTIST,
++
+     GST_TAG_ARTIST, PA_PROP_MEDIA_ARTIST,
+     GST_TAG_LANGUAGE_CODE, PA_PROP_MEDIA_LANGUAGE,
+     GST_TAG_LOCATION, PA_PROP_MEDIA_FILENAME,
+@@ -2015,9 +2181,12 @@ gst_pulsesink_event (GstBaseSink * sink, GstEvent * event)
+       gst_tag_list_get_string (l, GST_TAG_LOCATION, &location);
+       gst_tag_list_get_string (l, GST_TAG_DESCRIPTION, &description);
  
-@@ -1871,11 +1876,12 @@ gst_pulsesink_get_mute (GstPulseSink * psink)
-       goto unlock;
++      if (!artist)
++        gst_tag_list_get_string (l, GST_TAG_PERFORMER, &artist);
++
+       if (title && artist)
+         t = buf =
+-            g_strdup_printf ("'%s' by '%s'", g_strstrip (title),
++            g_strdup_printf (_("'%s' by '%s'"), g_strstrip (title),
+             g_strstrip (artist));
+       else if (title)
+         t = g_strstrip (title);
+diff --git a/ext/pulse/pulsesink.h b/ext/pulse/pulsesink.h
+index 8db3cbd..ae0ad95 100644
+--- a/ext/pulse/pulsesink.h
++++ b/ext/pulse/pulsesink.h
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
++
+ /*
+  *  GStreamer pulseaudio plugin
+  *
+@@ -60,12 +62,16 @@ struct _GstPulseSink
+   GstPulseProbe *probe;
+ 
+   gdouble volume;
+-  gboolean volume_set;
+-  gint notify;
+-  
++  gboolean volume_set:1;
++  gboolean mute:1;
++  gboolean mute_set:1;
++
++  gboolean pa_defer_ran:1;
++
++  gint notify; /* atomic */
++
+   const gchar *pa_version;
+ 
+-  gboolean pa_defer_ran;
+ };
+ 
+ struct _GstPulseSinkClass
+diff --git a/ext/pulse/pulsesrc.c b/ext/pulse/pulsesrc.c
+index fa60345..d53acf8 100644
+--- a/ext/pulse/pulsesrc.c
++++ b/ext/pulse/pulsesrc.c
+@@ -528,6 +528,11 @@ gst_pulsesrc_stream_latency_update_cb (pa_stream * s, void *userdata)
+ 
+   info = pa_stream_get_timing_info (s);
+ 
++  if (!info) {
++    GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
++        "latency update (information unknown)");
++    return;
++  }
+ #if HAVE_PULSE_0_9_11
+   source_usec = info->configured_source_usec;
+ #else
+@@ -945,25 +950,25 @@ no_nego_needed:
+ static gboolean
+ gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
+ {
+-  pa_buffer_attr buf_attr;
+-  const pa_buffer_attr *buf_attr_ptr;
++  pa_buffer_attr wanted;
++  const pa_buffer_attr *actual;
+   GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+ 
+   pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ 
+-  buf_attr.maxlength = -1;
+-  buf_attr.tlength = -1;
+-  buf_attr.prebuf = 0;
+-  buf_attr.minreq = -1;
+-  buf_attr.fragsize = spec->segsize;
++  wanted.maxlength = -1;
++  wanted.tlength = -1;
++  wanted.prebuf = 0;
++  wanted.minreq = -1;
++  wanted.fragsize = spec->segsize;
+ 
+-  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", buf_attr.maxlength);
+-  GST_INFO_OBJECT (pulsesrc, "tlength:   %d", buf_attr.tlength);
+-  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", buf_attr.prebuf);
+-  GST_INFO_OBJECT (pulsesrc, "minreq:    %d", buf_attr.minreq);
+-  GST_INFO_OBJECT (pulsesrc, "fragsize:  %d", buf_attr.fragsize);
++  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength);
++  GST_INFO_OBJECT (pulsesrc, "tlength:   %d", wanted.tlength);
++  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", wanted.prebuf);
++  GST_INFO_OBJECT (pulsesrc, "minreq:    %d", wanted.minreq);
++  GST_INFO_OBJECT (pulsesrc, "fragsize:  %d", wanted.fragsize);
+ 
+-  if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &buf_attr,
++  if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted,
+           PA_STREAM_INTERPOLATE_TIMING |
+           PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONOUS |
+ #if HAVE_PULSE_0_9_11
+@@ -998,20 +1003,23 @@ gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
    }
  
-+  mute = psink->mute;
+   /* get the actual buffering properties now */
+-  buf_attr_ptr = pa_stream_get_buffer_attr (pulsesrc->stream);
++  actual = pa_stream_get_buffer_attr (pulsesrc->stream);
+ 
+-  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", buf_attr_ptr->maxlength);
++  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength);
+   GST_INFO_OBJECT (pulsesrc, "tlength:   %d (wanted: %d)",
+-      buf_attr_ptr->tlength, buf_attr.tlength);
+-  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", buf_attr_ptr->prebuf);
+-  GST_INFO_OBJECT (pulsesrc, "minreq:    %d (wanted %d)", buf_attr_ptr->minreq,
+-      buf_attr.minreq);
++      actual->tlength, wanted.tlength);
++  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", actual->prebuf);
++  GST_INFO_OBJECT (pulsesrc, "minreq:    %d (wanted %d)", actual->minreq,
++      wanted.minreq);
+   GST_INFO_OBJECT (pulsesrc, "fragsize:  %d (wanted %d)",
+-      buf_attr_ptr->fragsize, buf_attr.fragsize);
++      actual->fragsize, wanted.fragsize);
+ 
+-  /* adjust latency again */
+-  spec->segsize = buf_attr_ptr->fragsize;
+-  spec->segtotal = buf_attr_ptr->maxlength / spec->segsize;
++  if (actual->fragsize >= wanted.fragsize) {
++    spec->segsize = actual->fragsize;
++  } else {
++    spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize);
++  }
++  spec->segtotal = actual->maxlength / spec->segsize;
+ 
+   pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+ 
+diff --git a/ext/pulse/pulsesrc.h b/ext/pulse/pulsesrc.h
+index 2358eba..be89434 100644
+--- a/ext/pulse/pulsesrc.h
++++ b/ext/pulse/pulsesrc.h
+@@ -1,3 +1,5 @@
++/*-*- Mode: C; c-basic-offset: 2 -*-*/
 +
- unlock:
-   if (o)
-     pa_operation_unref (o);
+ /*
+  *  GStreamer pulseaudio plugin
+  *
+@@ -70,10 +72,10 @@ struct _GstPulseSrc
+   GstPulseMixerCtrl *mixer;
+   GstPulseProbe *probe;
  
--  mute = psink->mute;
-   pa_threaded_mainloop_unlock (psink->mainloop);
+-  gboolean corked;
+-  gboolean operation_success;
+-  gboolean paused;
+-  gboolean in_read;
++  gboolean corked:1;
++  gboolean operation_success:1;
++  gboolean paused:1;
++  gboolean in_read:1;
+ };
  
-   return mute;
--- 
-1.6.3.3
-
+ struct _GstPulseSrcClass




More information about the fedora-extras-commits mailing list