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