rpms/gstreamer-plugins-good/F-12 pulsesink-lowering-volumes.patch, NONE, 1.1 gstreamer-plugins-good.spec, 1.104, 1.105

Bastien Nocera hadess at fedoraproject.org
Sat Oct 17 01:33:41 UTC 2009


Author: hadess

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

Modified Files:
	gstreamer-plugins-good.spec 
Added Files:
	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)


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(-)

--- NEW FILE pulsesink-lowering-volumes.patch ---
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 7ead4fe..1fe2b72 100644
--- a/ext/pulse/pulsesink.c
+++ b/ext/pulse/pulsesink.c
@@ -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);
   }
 
+  /* After we passed the volume off of to PA we never want to set it
+     again, since it is PA's job to save/restore volumes.  */
+  psink->volume_set = psink->mute_set = FALSE;
+
   GST_LOG_OBJECT (psink, "stream is acquired now");
 
   /* get the actual buffering properties now */
-  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,
+          "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",
+          "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;
 
-  pulsesink->volume = 1.0;
+  pulsesink->volume = DEFAULT_VOLUME;
   pulsesink->volume_set = FALSE;
 
+  pulsesink->mute = DEFAULT_MUTE;
+  pulsesink->mute_set = FALSE;
+
   pulsesink->notify = 0;
 
   /* 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);
 
-  psink->volume = volume;
-  psink->volume_set = TRUE;
-
   pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
   if (pbuf == NULL || pbuf->stream == NULL)
     goto no_buffer;
@@ -1646,6 +1684,9 @@ unlock:
   /* ERRORS */
 no_buffer:
   {
+    psink->volume = volume;
+    psink->volume_set = TRUE;
+
     GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
     goto unlock;
   }
@@ -1664,6 +1705,61 @@ volume_failed:
 }
 
 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;
+  }
+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;
-  gdouble v;
+  gdouble v = DEFAULT_VOLUME;
   uint32_t idx;
 
   pa_threaded_mainloop_lock (psink->mainloop);
@@ -1716,11 +1814,12 @@ gst_pulsesink_get_volume (GstPulseSink * psink)
       goto unlock;
   }
 
+  v = psink->volume;
+
 unlock:
   if (o)
     pa_operation_unref (o);
 
-  v = psink->volume;
   pa_threaded_mainloop_unlock (psink->mainloop);
 
   if (v > MAX_VOLUME) {
@@ -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
 
 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);
 
+      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)
   }
 
   /* 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 -*-*/
+
 /*
  *  GStreamer pulseaudio plugin
  *
@@ -70,10 +72,10 @@ struct _GstPulseSrc
   GstPulseMixerCtrl *mixer;
   GstPulseProbe *probe;
 
-  gboolean corked;
-  gboolean operation_success;
-  gboolean paused;
-  gboolean in_read;
+  gboolean corked:1;
+  gboolean operation_success:1;
+  gboolean paused:1;
+  gboolean in_read:1;
 };
 
 struct _GstPulseSrcClass


Index: gstreamer-plugins-good.spec
===================================================================
RCS file: /cvs/pkgs/rpms/gstreamer-plugins-good/F-12/gstreamer-plugins-good.spec,v
retrieving revision 1.104
retrieving revision 1.105
diff -u -p -r1.104 -r1.105
--- gstreamer-plugins-good.spec	16 Oct 2009 10:10:29 -0000	1.104
+++ gstreamer-plugins-good.spec	17 Oct 2009 01:33:41 -0000	1.105
@@ -6,7 +6,7 @@
 
 Name: 		%{gstreamer}-plugins-good
 Version: 	0.10.16
-Release:  	2%{?dist}
+Release:  	3%{?dist}
 Summary: 	GStreamer plug-ins with good code and licensing
 
 Group: 		Applications/Multimedia
@@ -73,6 +73,10 @@ BuildRequires: automake autoconf libtool
 Provides: gstreamer-plugins-farsight = 0.12.12-1
 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
 GStreamer is a streaming media framework, based on graphs of filters which
 operate on media data. Applications using this library can do anything
@@ -111,6 +115,7 @@ This is a dummy package to make gstreame
 %patch1 -p1 -b .autoconvert-caps
 libtoolize -f
 autoreconf
+%patch2 -p1 -b .volume-lowering
 
 %build
 
@@ -274,6 +279,9 @@ export GCONF_CONFIG_SOURCE=`gconftool-2 
 gconftool-2 --makefile-install-rule %{_sysconfdir}/gconf/schemas/gstreamer-%{majorminor}.schemas > /dev/null || :
 
 %changelog
+* Sat Oct 17 2009 Bastien Nocera <bnocera at redhat.com> 0.10.16-3
+- Finally fix pulsesink volume lowering problems (#488532)
+
 * Fri Oct 16 2009 Bastien Nocera <bnocera at redhat.com> 0.10.16-2
 - Fix autoconvert caps negotiation
 




More information about the fedora-extras-commits mailing list