[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, stable-queue, updated. v0.9.21-109-g8036598
Colin Guthrie
gitmailer-noreply at 0pointer.de
Wed Nov 17 15:58:23 PST 2010
This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.
The stable-queue branch has been updated
from 848dd378bb7fa53be7b88016335fa89d520f2ea3 (commit)
- Log -----------------------------------------------------------------
8036598 upnp: Implement the MediaServer2 D-Bus interface
70a060d combine: Only check if the sink is h/w etc. in automatic mode
33ea7b7 combine: Handle reappearing slave sinks in non-automatic mode.
34fd605 alsa: remove redundant call to snd_pcm_nonblock()
2c9c908 doxygen: Add 'See also' linking to the overview page
f2593da doxygen: Documentation improvements
14bc454 doxygen: Fix the "all" comments regarding volume helper functions.
b7303e2 doxygen: Fix documentation typos
352ae22 sink-input: Fix comment
-----------------------------------------------------------------------
Summary of changes:
src/modules/alsa/alsa-util.c | 2 -
src/modules/module-combine.c | 30 ++-
src/modules/module-rygel-media-server.c | 662 +++++++++++++++++++++---------
src/pulse/channelmap.h | 5 +-
src/pulse/context.h | 5 +-
src/pulse/glib-mainloop.h | 9 +-
src/pulse/introspect.h | 4 +-
src/pulse/mainloop.h | 9 +-
src/pulse/sample.h | 5 +-
src/pulse/scache.h | 5 +-
src/pulse/simple.h | 7 +-
src/pulse/stream.h | 29 +-
src/pulse/subscribe.h | 5 +-
src/pulse/thread-mainloop.h | 11 +-
src/pulse/timeval.h | 4 +-
src/pulse/volume.h | 26 +-
src/pulsecore/sink-input.h | 2 +-
17 files changed, 570 insertions(+), 250 deletions(-)
-----------------------------------------------------------------------
commit 352ae22015452d730c32a7047675b820de2fbbf8
Author: Colin Guthrie <cguthrie at mandriva.org>
Date: Fri Oct 1 01:32:37 2010 +0100
sink-input: Fix comment
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 415a801..e666d4f 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -37,7 +37,7 @@ typedef struct pa_sink_input pa_sink_input;
#include <pulsecore/core.h>
typedef enum pa_sink_input_state {
- PA_SINK_INPUT_INIT, /*< The stream is not active yet, because pa_sink_put() has not been called yet */
+ PA_SINK_INPUT_INIT, /*< The stream is not active yet, because pa_sink_input_put() has not been called yet */
PA_SINK_INPUT_DRAINED, /*< The stream stopped playing because there was no data to play */
PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */
PA_SINK_INPUT_CORKED, /*< The stream was corked on user request */
commit b7303e2dd437a799bbdd4a74fb81a1472081f86a
Author: David Fries <david at fries.net>
Date: Sat Sep 18 09:07:15 2010 -0500
doxygen: Fix documentation typos
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 68cfc87..c7a8b1f 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -59,7 +59,7 @@
* Note that even if a single object is requested, and not the entire list,
* the terminating call will still be made.
*
- * If an error occurs, the callback will be called without and information
+ * If an error occurs, the callback will be called without an information
* structure and eol set to a negative value..
*
* Data members in the information structures are only valid during the
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index bc54a11..adf159c 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -486,8 +486,8 @@ int pa_stream_cancel_write(
* data is not copied. If NULL, the data is copied into an internal
* buffer. The client may freely seek around in the output buffer. For
* most applications passing 0 and PA_SEEK_RELATIVE as arguments for
- * offset and seek should be useful. Afte ther write call succeeded
- * the write index will be a the position after where this chunk of
+ * offset and seek should be useful. After the write call succeeded
+ * the write index will be at the position after where this chunk of
* data has been written to.
*
* As an optimization for avoiding needless memory copies you may call
@@ -739,8 +739,9 @@ pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[],
* 0.9.11 */
int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx);
-/** Return what has been set with pa_stream_set_monitor_stream()
- * ebfore. \since 0.9.11 */
+/** Return the sink input index previously set with
+ * pa_stream_set_monitor_stream().
+ * \since 0.9.11 */
uint32_t pa_stream_get_monitor_stream(pa_stream *s);
PA_C_DECL_END
diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h
index 3cea5d3..4201463 100644
--- a/src/pulse/timeval.h
+++ b/src/pulse/timeval.h
@@ -72,10 +72,10 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) PA_GCC_PURE
/** Return the time difference between now and the specified timestamp */
pa_usec_t pa_timeval_age(const struct timeval *tv);
-/** Add the specified time inmicroseconds to the specified timeval structure */
+/** Add the specified time in microseconds to the specified timeval structure */
struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v);
-/** Subtract the specified time inmicroseconds to the specified timeval structure. \since 0.9.11 */
+/** Subtract the specified time in microseconds to the specified timeval structure. \since 0.9.11 */
struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v);
/** Store the specified uec value in the timeval struct. \since 0.9.7 */
commit 14bc4548cedec372d9ab6a6ed7be3b826b2a6a47
Author: David Fries <david at fries.net>
Date: Tue Oct 12 18:22:27 2010 -0500
doxygen: Fix the "all" comments regarding volume helper functions.
Mostly change "Set the volume of all channels" to
"Set the volume of the first n channels" as the first is incorrect,
it doesn't set all the channels and doesn't explain what n was for.
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index c964020..ed8dff9 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -81,12 +81,12 @@
* structure are muted.
* \li pa_cvolume_is_norm() - Tests if all channels of a pa_cvolume structure
* are at a normal volume.
- * \li pa_cvolume_set() - Set all channels of a pa_cvolume structure to a
- * certain volume.
- * \li pa_cvolume_reset() - Set all channels of a pa_cvolume structure to a
- * normal volume.
- * \li pa_cvolume_mute() - Set all channels of a pa_cvolume structure to a
- * muted volume.
+ * \li pa_cvolume_set() - Set the first n channels of a pa_cvolume structure to
+ * a certain volume.
+ * \li pa_cvolume_reset() - Set the first n channels of a pa_cvolume structure
+ * to a normal volume.
+ * \li pa_cvolume_mute() - Set the first n channels of a pa_cvolume structure
+ * to a muted volume.
* \li pa_cvolume_avg() - Return the average volume of all channels.
* \li pa_cvolume_snprint() - Pretty print a pa_cvolume structure.
*/
@@ -129,13 +129,13 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE;
* pa_cvolume_valid() will fail for it. \since 0.9.13 */
pa_cvolume* pa_cvolume_init(pa_cvolume *a);
-/** Set the volume of all channels to PA_VOLUME_NORM */
+/** Set the volume of the first n channels to PA_VOLUME_NORM */
#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM)
-/** Set the volume of all channels to PA_VOLUME_MUTED */
+/** Set the volume of the first n channels to PA_VOLUME_MUTED */
#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED)
-/** Set the volume of all channels to the specified parameter */
+/** Set the volume of the specified number of channels to the volume v */
pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v);
/** Maximum length of the strings returned by
@@ -259,7 +259,8 @@ pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST;
/** Convert a volume to a decibel value (amplitude, not power). This is only valid for software volumes! */
double pa_sw_volume_to_dB(pa_volume_t v) PA_GCC_CONST;
-/** Convert a linear factor to a volume. This is only valid for software volumes! */
+/** Convert a linear factor to a volume. 0.0 and less is muted while
+ * 1.0 is PA_VOLUME_NORM. This is only valid for software volumes! */
pa_volume_t pa_sw_volume_from_linear(double v) PA_GCC_CONST;
/** Convert a volume to a linear factor. This is only valid for software volumes! */
commit f2593da3a36e1cb297a269d98205b4bdcde962f0
Author: David Fries <david at fries.net>
Date: Tue Oct 12 20:05:47 2010 -0500
doxygen: Documentation improvements
stream.h, simple.h
The words drain and flush are a little ambiguous, make it explicit as
to what happens to any existing audio.
*mainloop.h
reword *_free and *_get_api for grammar
diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h
index 67aba27..fd173d0 100644
--- a/src/pulse/glib-mainloop.h
+++ b/src/pulse/glib-mainloop.h
@@ -57,8 +57,8 @@ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c);
void pa_glib_mainloop_free(pa_glib_mainloop* g);
/** Return the abstract main loop API vtable for the GLIB main loop
- object. No need of freeing the API as it is owned by the loop and
- it is destroyed when this dies */
+ object. No need to free the API as it is owned by the loop
+ and is destroyed when the loop is freed. */
pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g);
PA_C_DECL_END
diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h
index 63abd58..213f91d 100644
--- a/src/pulse/mainloop.h
+++ b/src/pulse/mainloop.h
@@ -109,8 +109,8 @@ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval);
int pa_mainloop_run(pa_mainloop *m, int *retval);
/** Return the abstract main loop abstraction layer vtable for this
- main loop. No need of freeing the API as it is owned by the loop
- and it is destroyed when this dies */
+ main loop. No need to free the API as it is owned by the loop
+ and is destroyed when the loop is freed. */
pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m);
/** Shutdown the main loop */
diff --git a/src/pulse/simple.h b/src/pulse/simple.h
index 6f1ba41..8d0a388 100644
--- a/src/pulse/simple.h
+++ b/src/pulse/simple.h
@@ -140,7 +140,7 @@ int pa_simple_read(pa_simple *s, void*data, size_t bytes, int *error);
/** Return the playback latency. */
pa_usec_t pa_simple_get_latency(pa_simple *s, int *error);
-/** Flush the playback buffer. */
+/** Flush the playback buffer. This discards any audio in the buffer. */
int pa_simple_flush(pa_simple *s, int *error);
PA_C_DECL_END
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index adf159c..7c53937 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -529,9 +529,10 @@ size_t pa_stream_writable_size(pa_stream *p);
/** Return the number of bytes that may be read using pa_stream_peek()*/
size_t pa_stream_readable_size(pa_stream *p);
-/** Drain a playback stream. Use this for notification when the buffer
- * is empty. Please note that only one drain operation per stream may
- * be issued at a time. */
+/** Drain a playback stream. Use this for notification when the
+ * playback buffer is empty after playing all the audio in the buffer.
+ * Please note that only one drain operation per stream may be issued
+ * at a time. */
pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
/** Request a timing info structure update for a stream. Use
@@ -609,10 +610,10 @@ void pa_stream_set_buffer_attr_callback(pa_stream *p, pa_stream_notify_cb_t cb,
* of the stream it will be created in corked state. */
pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata);
-/** Flush the playback buffer of this stream. Most of the time you're
- * better off using the parameter delta of pa_stream_write() instead
- * of this function. Available on both playback and recording
- * streams. */
+/** Flush the playback buffer of this stream. This discards any audio
+ * in the buffer. Most of the time you're better off using the parameter
+ * delta of pa_stream_write() instead of this function. Available on both
+ * playback and recording streams. */
pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
/** Reenable prebuffering as specified in the pa_buffer_attr
diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h
index 2cf496e..1c98d54 100644
--- a/src/pulse/thread-mainloop.h
+++ b/src/pulse/thread-mainloop.h
@@ -250,7 +250,7 @@ typedef struct pa_threaded_mainloop pa_threaded_mainloop;
pa_threaded_mainloop *pa_threaded_mainloop_new(void);
/** Free a threaded main loop object. If the event loop thread is
- * still running, it is terminated using pa_threaded_mainloop_stop()
+ * still running, terminate it with pa_threaded_mainloop_stop()
* first. */
void pa_threaded_mainloop_free(pa_threaded_mainloop* m);
@@ -300,8 +300,8 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m);
int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m);
/** Return the abstract main loop abstraction layer vtable for this
- main loop. No need of freeing the API as it is owned by the loop
- and it is destroyed when this dies */
+ main loop. No need to free the API as it is owned by the loop
+ and is destroyed when the loop is freed. */
pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m);
/** Returns non-zero when called from withing the event loop thread. \since 0.9.7 */
commit 2c9c908e856455dac36402a22e6575af131174ac
Author: David Fries <david at fries.net>
Date: Sun Oct 3 13:41:27 2010 -0500
doxygen: Add 'See also' linking to the overview page
A good many of the header files are broken into a function
reference page and an overview page. These changes add
a direct link from each function reference page to their
overview page if one exists.
diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h
index d1d5c8b..a6b93dd 100644
--- a/src/pulse/channelmap.h
+++ b/src/pulse/channelmap.h
@@ -65,7 +65,10 @@
*/
/** \file
- * Constants and routines for channel mapping handling */
+ * Constants and routines for channel mapping handling
+ *
+ * See also \subpage channelmap
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/context.h b/src/pulse/context.h
index ecff58d..6e29325 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -145,7 +145,10 @@
/** \file
* Connection contexts for asynchrononous communication with a
* server. A pa_context object wraps a connection to a PulseAudio
- * server using its native protocol. */
+ * server using its native protocol.
+ *
+ * See also \subpage async
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h
index fd173d0..805d746 100644
--- a/src/pulse/glib-mainloop.h
+++ b/src/pulse/glib-mainloop.h
@@ -41,7 +41,10 @@
*/
/** \file
- * GLIB main loop support */
+ * GLIB main loop support
+ *
+ * See also \subpage glib-mainloop
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index c7a8b1f..e6635d7 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -187,6 +187,8 @@
/** \file
*
* Routines for daemon introspection.
+ *
+ * See also \subpage introspect
*/
PA_C_DECL_BEGIN
diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h
index 213f91d..19b17fa 100644
--- a/src/pulse/mainloop.h
+++ b/src/pulse/mainloop.h
@@ -71,7 +71,10 @@ struct pollfd;
* function. Using the routines defined herein you may create a simple
* main loop supporting the generic main loop abstraction layer as
* defined in \ref mainloop-api.h. This implementation is thread safe
- * as long as you access the main loop object from a single thread only.*/
+ * as long as you access the main loop object from a single thread only.
+ *
+ * See also \subpage mainloop
+ */
/** An opaque main loop object */
typedef struct pa_mainloop pa_mainloop;
diff --git a/src/pulse/sample.h b/src/pulse/sample.h
index 7a4a55a..c9e6fc4 100644
--- a/src/pulse/sample.h
+++ b/src/pulse/sample.h
@@ -105,7 +105,10 @@
*/
/** \file
- * Constants and routines for sample type handling */
+ * Constants and routines for sample type handling
+ *
+ * See also \subpage sample
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/scache.h b/src/pulse/scache.h
index 31cf7b0..b4fcbd0 100644
--- a/src/pulse/scache.h
+++ b/src/pulse/scache.h
@@ -74,7 +74,10 @@
*/
/** \file
- * All sample cache related routines */
+ * All sample cache related routines
+ *
+ * See also \subpage scache
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/simple.h b/src/pulse/simple.h
index 8d0a388..ba5e8fe 100644
--- a/src/pulse/simple.h
+++ b/src/pulse/simple.h
@@ -98,7 +98,10 @@
/** \file
* A simple but limited synchronous playback and recording
* API. This is a synchronous, simplified wrapper around the standard
- * asynchronous API. */
+ * asynchronous API.
+ *
+ * See also \subpage simple
+ */
/** \example pacat-simple.c
* A simple playback tool using the simple API */
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 7c53937..41e30da 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -310,7 +310,10 @@
*/
/** \file
- * Audio streams for input, output and sample upload */
+ * Audio streams for input, output and sample upload
+ *
+ * See also \subpage streams
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h
index 44ed24a..f1e17ca 100644
--- a/src/pulse/subscribe.h
+++ b/src/pulse/subscribe.h
@@ -45,7 +45,10 @@
*/
/** \file
- * Daemon introspection event subscription subsystem. */
+ * Daemon introspection event subscription subsystem.
+ *
+ * See also \subpage subscribe
+ */
PA_C_DECL_BEGIN
diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h
index 1c98d54..f911228 100644
--- a/src/pulse/thread-mainloop.h
+++ b/src/pulse/thread-mainloop.h
@@ -239,7 +239,10 @@ PA_C_DECL_BEGIN
* A thread based event loop implementation based on pa_mainloop. The
* event loop is run in a helper thread in the background. A few
* synchronization primitives are available to access the objects
- * attached to the event loop safely. */
+ * attached to the event loop safely.
+ *
+ * See also \subpage threaded_mainloop
+ */
/** An opaque threaded main loop object */
typedef struct pa_threaded_mainloop pa_threaded_mainloop;
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index ed8dff9..d98443b 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -92,7 +92,10 @@
*/
/** \file
- * Constants and routines for volume handling */
+ * Constants and routines for volume handling
+ *
+ * See also \subpage volume
+ */
PA_C_DECL_BEGIN
commit 34fd60567712cef97de04d32534f0ef841cb5cae
Author: Pierre-Louis Bossart <pierre-louis.bossart at intel.com>
Date: Thu Nov 11 10:19:25 2010 -0600
alsa: remove redundant call to snd_pcm_nonblock()
The PCM handle is already opened with the SND_PCM_NONBLOCK flag.
This additional call is useless.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at intel.com>
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 2d0d356..7ea26e1 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -399,8 +399,6 @@ success:
ret = 0;
- snd_pcm_nonblock(pcm_handle, 1);
-
finish:
return ret;
commit 33ea7b7816818113cf080e811547e1e76651109c
Author: Antti-Ville Jansson <antti-ville.jansson at digia.com>
Date: Fri Nov 12 09:52:48 2010 +0200
combine: Handle reappearing slave sinks in non-automatic mode.
Earlier, if slave sinks were unlinked in non-automatic mode, their
re-appearance was disregarded. Now they are added back to the list of outputs.
Signed-off-by: Antti-Ville Jansson <antti-ville.jansson at digia.com>
Reviewed-by: Tanu Kaskinen <tanu.kaskinen at digia.com>
diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index 5f94fdd..01d7a4e 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -47,6 +47,7 @@
#include <pulsecore/rtpoll.h>
#include <pulsecore/core-error.h>
#include <pulsecore/time-smoother.h>
+#include <pulsecore/strlist.h>
#include "module-combine-symdef.h"
@@ -125,6 +126,8 @@ struct userdata {
pa_bool_t automatic;
pa_bool_t auto_desc;
+ pa_strlist *unlinked_slaves;
+
pa_hook_slot *sink_put_slot, *sink_unlink_slot, *sink_state_changed_slot;
pa_resample_method_t resample_method;
@@ -1026,11 +1029,23 @@ static pa_hook_result_t sink_put_hook_cb(pa_core *c, pa_sink *s, struct userdata
pa_core_assert_ref(c);
pa_sink_assert_ref(s);
pa_assert(u);
- pa_assert(u->automatic);
if (!is_suitable_sink(u, s))
return PA_HOOK_OK;
+ /* Check if the sink is a previously unlinked slave (non-automatic mode) */
+ if (!u->automatic) {
+ pa_strlist *l = u->unlinked_slaves;
+
+ while (l && !pa_streq(pa_strlist_data(l), s->name))
+ l = pa_strlist_next(l);
+
+ if (l)
+ u->unlinked_slaves = pa_strlist_remove(u->unlinked_slaves, s->name);
+ else
+ return PA_HOOK_OK;
+ }
+
pa_log_info("Configuring new sink: %s", s->name);
if (!(o = output_new(u, s))) {
pa_log("Failed to create sink input on sink '%s'.", s->name);
@@ -1072,6 +1087,10 @@ static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userd
return PA_HOOK_OK;
pa_log_info("Unconfiguring sink: %s", s->name);
+
+ if (!u->automatic)
+ u->unlinked_slaves = pa_strlist_prepend(u->unlinked_slaves, s->name);
+
output_free(o);
return PA_HOOK_OK;
@@ -1297,10 +1316,9 @@ int pa__init(pa_module*m) {
goto fail;
}
}
-
- u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_cb, u);
}
+ u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_cb, u);
u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_cb, u);
u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_state_changed_hook_cb, u);
@@ -1341,6 +1359,8 @@ void pa__done(pa_module*m) {
if (!(u = m->userdata))
return;
+ pa_strlist_free(u->unlinked_slaves);
+
if (u->sink_put_slot)
pa_hook_slot_free(u->sink_put_slot);
commit 70a060db92b09f8ab3651bbaff6d8f4864a0e826
Author: Colin Guthrie <cguthrie at mandriva.org>
Date: Wed Nov 17 23:43:36 2010 +0000
combine: Only check if the sink is h/w etc. in automatic mode
diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index 01d7a4e..bcea229 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -1030,20 +1030,20 @@ static pa_hook_result_t sink_put_hook_cb(pa_core *c, pa_sink *s, struct userdata
pa_sink_assert_ref(s);
pa_assert(u);
- if (!is_suitable_sink(u, s))
- return PA_HOOK_OK;
-
- /* Check if the sink is a previously unlinked slave (non-automatic mode) */
- if (!u->automatic) {
+ if (u->automatic) {
+ if (!is_suitable_sink(u, s))
+ return PA_HOOK_OK;
+ } else {
+ /* Check if the sink is a previously unlinked slave (non-automatic mode) */
pa_strlist *l = u->unlinked_slaves;
while (l && !pa_streq(pa_strlist_data(l), s->name))
l = pa_strlist_next(l);
- if (l)
- u->unlinked_slaves = pa_strlist_remove(u->unlinked_slaves, s->name);
- else
+ if (!l)
return PA_HOOK_OK;
+
+ u->unlinked_slaves = pa_strlist_remove(u->unlinked_slaves, s->name);
}
pa_log_info("Configuring new sink: %s", s->name);
commit 803659883decc539dabedd6359238a43fd12a039
Author: Stephen Moehle <stephen.moehle at gmail.com>
Date: Sun Nov 14 12:31:15 2010 -0800
upnp: Implement the MediaServer2 D-Bus interface
This allows PulseAudio to work with versions of Rygel 0.7.1 and higher
which only support MediaServer2:
http://live.gnome.org/Rygel/MediaServer2Spec
diff --git a/src/modules/module-rygel-media-server.c b/src/modules/module-rygel-media-server.c
index 82bcd14..76b485c 100644
--- a/src/modules/module-rygel-media-server.c
+++ b/src/modules/module-rygel-media-server.c
@@ -52,33 +52,52 @@ PA_MODULE_AUTHOR("Lennart Poettering");
PA_MODULE_DESCRIPTION("UPnP MediaServer Plugin for Rygel");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(TRUE);
-PA_MODULE_USAGE(
- "display_name=<UPnP Media Server name>");
+PA_MODULE_USAGE("display_name=<UPnP Media Server name>");
-/* This implements http://live.gnome.org/Rygel/MediaServerSpec */
+/* This implements http://live.gnome.org/Rygel/MediaServer2Spec */
-#define SERVICE_NAME "org.gnome.UPnP.MediaServer1.PulseAudio"
+#define SERVICE_NAME "org.gnome.UPnP.MediaServer2.PulseAudio"
-#define OBJECT_ROOT "/org/gnome/UPnP/MediaServer1/PulseAudio"
-#define OBJECT_SINKS "/org/gnome/UPnP/MediaServer1/PulseAudio/Sinks"
-#define OBJECT_SOURCES "/org/gnome/UPnP/MediaServer1/PulseAudio/Sources"
+#define OBJECT_ROOT "/org/gnome/UPnP/MediaServer2/PulseAudio"
+#define OBJECT_SINKS "/org/gnome/UPnP/MediaServer2/PulseAudio/Sinks"
+#define OBJECT_SOURCES "/org/gnome/UPnP/MediaServer2/PulseAudio/Sources"
#define CONTAINER_INTROSPECT_XML_PREFIX \
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
"<node>" \
" <!-- If you are looking for documentation make sure to check out" \
- " http://live.gnome.org/Rygel/MediaServerSpec -->" \
- " <interface name=\"org.gnome.UPnP.MediaContainer1\">" \
+ " http://live.gnome.org/Rygel/MediaServer2Spec -->" \
+ " <interface name=\"org.gnome.UPnP.MediaContainer2\">" \
+ " <method name='ListChildren'>" \
+ " <arg direction='in' name='offset' type='u' />" \
+ " <arg direction='in' name='max' type='u' />" \
+ " <arg direction='in' name='filter' type='as' />" \
+ " <arg direction='out' type='aa{sv}' />" \
+ " </method>" \
+ " <method name='ListContainers'>" \
+ " <arg direction='in' name='offset' type='u' />" \
+ " <arg direction='in' name='max' type='u' />" \
+ " <arg direction='in' name='filter' type='as' />" \
+ " <arg direction='out' type='aa{sv}' />" \
+ " </method>" \
+ " <method name='ListItems'>" \
+ " <arg direction='in' name='offset' type='u' />" \
+ " <arg direction='in' name='max' type='u' />" \
+ " <arg direction='in' name='filter' type='as' />" \
+ " <arg direction='out' type='aa{sv}' />" \
+ " </method>" \
" <signal name=\"Updated\">" \
" <arg name=\"path\" type=\"o\"/>" \
" </signal>" \
- " <property name=\"Items\" type=\"ao\" access=\"read\"/>" \
+ " <property name=\"ChildCount\" type=\"u\" access=\"read\"/>" \
" <property name=\"ItemCount\" type=\"u\" access=\"read\"/>" \
- " <property name=\"Containers\" type=\"ao\" access=\"read\"/>" \
" <property name=\"ContainerCount\" type=\"u\" access=\"read\"/>" \
+ " <property name=\"Searchable\" type=\"b\" access=\"read\"/>" \
" </interface>" \
- " <interface name=\"org.gnome.UPnP.MediaObject1\">" \
+ " <interface name=\"org.gnome.UPnP.MediaObject2\">" \
" <property name=\"Parent\" type=\"s\" access=\"read\"/>" \
+ " <property name=\"Type\" type=\"s\" access=\"read\"/>" \
+ " <property name=\"Path\" type=\"s\" access=\"read\"/>" \
" <property name=\"DisplayName\" type=\"s\" access=\"read\"/>" \
" </interface>" \
" <interface name=\"org.freedesktop.DBus.Properties\">" \
@@ -111,14 +130,14 @@ PA_MODULE_USAGE(
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
"<node>" \
" <!-- If you are looking for documentation make sure to check out" \
- " http://live.gnome.org/Rygel/MediaProviderSpec -->" \
- " <interface name=\"org.gnome.UPnP.MediaItem1\">" \
+ " http://live.gnome.org/Rygel/MediaProvider2Spec -->" \
+ " <interface name=\"org.gnome.UPnP.MediaItem2\">" \
" <property name=\"URLs\" type=\"as\" access=\"read\"/>" \
" <property name=\"MIMEType\" type=\"s\" access=\"read\"/>" \
- " <property name=\"Type\" type=\"s\" access=\"read\"/>" \
- " </interface>" \
- " <interface name=\"org.gnome.UPnP.MediaObject1\">" \
+ " <interface name=\"org.gnome.UPnP.MediaObject2\">" \
" <property name=\"Parent\" type=\"s\" access=\"read\"/>" \
+ " <property name=\"Type\" type=\"s\" access=\"read\"/>" \
+ " <property name=\"Path\" type=\"s\" access=\"read\"/>" \
" <property name=\"DisplayName\" type=\"s\" access=\"read\"/>" \
" </interface>" \
" <interface name=\"org.freedesktop.DBus.Properties\">" \
@@ -159,6 +178,8 @@ struct userdata {
pa_http_protocol *http;
};
+static char *compute_url(const struct userdata *u, const char *name);
+
static void send_signal(struct userdata *u, pa_source *s) {
DBusMessage *m;
const char *parent;
@@ -174,7 +195,7 @@ static void send_signal(struct userdata *u, pa_source *s) {
else
parent = OBJECT_SOURCES;
- pa_assert_se(m = dbus_message_new_signal(parent, "org.gnome.UPnP.MediaContainer1", "Updated"));
+ pa_assert_se(m = dbus_message_new_signal(parent, "org.gnome.UPnP.MediaContainer2", "Updated"));
pa_assert_se(dbus_connection_send(pa_dbus_connection_get(u->bus), m, NULL));
dbus_message_unref(m);
@@ -296,6 +317,69 @@ static void append_variant_unsigned(DBusMessage *m, DBusMessageIter *iter, unsig
pa_assert_se(dbus_message_iter_close_container(iter, &sub));
}
+static void append_variant_boolean(DBusMessage *m, DBusMessageIter *iter, dbus_bool_t b) {
+ DBusMessageIter _iter, sub;
+
+ pa_assert(m);
+
+ if (!iter) {
+ dbus_message_iter_init_append(m, &_iter);
+ iter = &_iter;
+ }
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "b", &sub));
+ pa_assert_se(dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b));
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
+static void append_variant_urls(DBusMessage *m, DBusMessageIter *iter, const struct userdata *u, pa_sink *sink, pa_source *source) {
+ DBusMessageIter _iter, sub, array;
+ char *url;
+
+ pa_assert(m);
+ pa_assert(u);
+ pa_assert(sink || source);
+
+ if (!iter) {
+ dbus_message_iter_init_append(m, &_iter);
+ iter = &_iter;
+ }
+
+ url = compute_url(u, sink ? sink->monitor_source->name : source->name);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "as", &sub));
+ pa_assert_se(dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "s", &array));
+ pa_assert_se(dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &url));
+ pa_assert_se(dbus_message_iter_close_container(&sub, &array));
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+
+ pa_xfree(url);
+}
+
+static void append_variant_mime_type(DBusMessage *m, DBusMessageIter *iter, pa_sink *sink, pa_source *source) {
+ char *mime_type;
+
+ pa_assert(sink || source);
+
+ if (sink)
+ mime_type = pa_sample_spec_to_mime_type_mimefy(&sink->sample_spec, &sink->channel_map);
+ else
+ mime_type = pa_sample_spec_to_mime_type_mimefy(&source->sample_spec, &source->channel_map);
+
+ append_variant_string(m, iter, mime_type);
+
+ pa_xfree(mime_type);
+}
+
+static void append_variant_item_display_name(DBusMessage *m, DBusMessageIter *iter, pa_sink *sink, pa_source *source) {
+ const char *display_name;
+
+ pa_assert(sink || source);
+
+ display_name = pa_strna(pa_proplist_gets(sink ? sink->proplist : source->proplist, PA_PROP_DEVICE_DESCRIPTION));
+ append_variant_string(m, iter, display_name);
+}
+
static void append_property_dict_entry_object_array(DBusMessage *m, DBusMessageIter *iter, const char *name, const char *path[], unsigned n) {
DBusMessageIter sub;
@@ -340,6 +424,195 @@ static void append_property_dict_entry_unsigned(DBusMessage *m, DBusMessageIter
pa_assert_se(dbus_message_iter_close_container(iter, &sub));
}
+static void append_property_dict_entry_boolean(DBusMessage *m, DBusMessageIter *iter, const char *name, dbus_bool_t b) {
+ DBusMessageIter sub;
+
+ pa_assert(iter);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub));
+ pa_assert_se(dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name));
+ append_variant_boolean(m, &sub, b);
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
+static void append_property_dict_entry_urls(DBusMessage *m, DBusMessageIter *iter, const struct userdata *u, pa_sink *sink, pa_source *source) {
+ DBusMessageIter sub;
+ const char *property_name = "URLs";
+
+ pa_assert(iter);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub));
+ pa_assert_se(dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property_name));
+ append_variant_urls(m, &sub, u, sink, source);
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
+static void append_property_dict_entry_mime_type(DBusMessage *m, DBusMessageIter *iter, pa_sink *sink, pa_source *source) {
+ DBusMessageIter sub;
+ const char *property_name = "MIMEType";
+
+ pa_assert(iter);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub));
+ pa_assert_se(dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property_name));
+ append_variant_mime_type(m, &sub, sink, source);
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
+static void append_property_dict_entry_item_display_name(DBusMessage *m, DBusMessageIter *iter, pa_sink *sink, pa_source *source) {
+ DBusMessageIter sub;
+ const char *property_name = "DisplayName";
+
+ pa_assert(iter);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &sub));
+ pa_assert_se(dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property_name));
+ append_variant_item_display_name(m, &sub, sink, source);
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
+static pa_bool_t get_mediacontainer2_list_args(DBusMessage *m, unsigned *offset, unsigned *max_entries, char ***filter, int *filter_len) {
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ pa_assert(m);
+ pa_assert(offset);
+ pa_assert(max_entries);
+ pa_assert(filter);
+
+ if (!dbus_message_get_args(m, &error, DBUS_TYPE_UINT32, offset, DBUS_TYPE_UINT32, max_entries, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, filter, filter_len, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static unsigned get_sinks_or_sources_count(const char *path, const struct userdata *u) {
+ unsigned n, k;
+
+ n = pa_idxset_size(u->core->sinks);
+ k = pa_idxset_size(u->core->sources);
+ pa_assert(k >= n);
+
+ return pa_streq(path, OBJECT_SINKS) ? n : k - n;
+}
+
+static void append_sink_or_source_container_mediaobject2_properties(DBusMessage *r, DBusMessageIter *sub, const char *path) {
+ append_property_dict_entry_object(r, sub, "Parent", OBJECT_ROOT);
+ append_property_dict_entry_string(r, sub, "Type", "container");
+ append_property_dict_entry_object(r, sub, "Path", path);
+ append_property_dict_entry_string(r, sub, "DisplayName",
+ pa_streq(path, OBJECT_SINKS) ?
+ _("Output Devices") :
+ _("Input Devices"));
+}
+
+static void append_sink_or_source_container_properties(
+ DBusMessage *r, DBusMessageIter *iter,
+ const char *path, const struct userdata *user_data,
+ char * const * filter, int filter_len) {
+
+ DBusMessageIter sub;
+
+ pa_assert(r);
+ pa_assert(iter);
+ pa_assert(path);
+ pa_assert(filter);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
+
+ if (filter_len == 1 && (*filter)[0] == '*' && (*filter)[1] == '\0') {
+ append_sink_or_source_container_mediaobject2_properties(r, &sub, path);
+ append_property_dict_entry_unsigned(r, &sub, "ChildCount", get_sinks_or_sources_count(path, user_data));
+ append_property_dict_entry_boolean(r, &sub, "Searchable", FALSE);
+ }
+ else {
+ for (int i = 0; i < filter_len; ++i) {
+ const char *property_name = filter[i];
+ if (pa_streq(property_name, "Parent")) {
+ append_property_dict_entry_object(r, &sub, "Parent", OBJECT_ROOT);
+ }
+ else if (pa_streq(property_name, "Type")) {
+ append_property_dict_entry_string(r, &sub, "Type", "container");
+ }
+ else if (pa_streq(property_name, "Path")) {
+ append_property_dict_entry_object(r, &sub, "Path", path);
+ }
+ else if (pa_streq(property_name, "DisplayName")) {
+ append_property_dict_entry_string(r, &sub, "DisplayName",
+ pa_streq(path, OBJECT_SINKS) ?
+ _("Output Devices") :
+ _("Input Devices"));
+ }
+ else if (pa_streq(property_name, "ChildCount")) {
+ append_property_dict_entry_unsigned(r, &sub, "ChildCount", get_sinks_or_sources_count(path, user_data));
+ }
+ else if (pa_streq(property_name, "Searchable")) {
+ append_property_dict_entry_boolean(r, &sub, "Searchable", FALSE);
+ }
+ }
+ }
+
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
+static void append_sink_or_source_item_mediaobject2_properties(DBusMessage *r, DBusMessageIter *sub, const char *path, pa_sink *sink, pa_source *source) {
+ append_property_dict_entry_object(r, sub, "Parent", sink ? OBJECT_SINKS : OBJECT_SOURCES);
+ append_property_dict_entry_string(r, sub, "Type", "audio");
+ append_property_dict_entry_object(r, sub, "Path", path);
+ append_property_dict_entry_item_display_name(r, sub, sink, source);
+}
+
+static void append_sink_or_source_item_properties(
+ DBusMessage *r, DBusMessageIter *iter,
+ const char *path, const struct userdata *user_data,
+ pa_sink *sink, pa_source *source,
+ char * const * filter, int filter_len) {
+
+ DBusMessageIter sub;
+
+ pa_assert(r);
+ pa_assert(iter);
+ pa_assert(path);
+ pa_assert(filter);
+ pa_assert(sink || source);
+
+ pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
+
+ if (filter_len == 1 && (*filter)[0] == '*' && (*filter)[1] == '\0') {
+ append_sink_or_source_item_mediaobject2_properties(r, &sub, path, sink, source);
+ append_property_dict_entry_urls(r, &sub, user_data, sink, source);
+ append_property_dict_entry_mime_type(r, &sub, sink, source);
+ }
+ else {
+ for (int i = 0; i < filter_len; ++i) {
+ const char *property_name = filter[i];
+ if (pa_streq(property_name, "Parent")) {
+ append_property_dict_entry_object(r, &sub, "Parent", sink ? OBJECT_SINKS : OBJECT_SOURCES);
+ }
+ else if (pa_streq(property_name, "Type")) {
+ append_property_dict_entry_string(r, &sub, "Type", "audio");
+ }
+ else if (pa_streq(property_name, "Path")) {
+ append_property_dict_entry_object(r, &sub, "Path", path);
+ }
+ else if (pa_streq(property_name, "DisplayName")) {
+ append_property_dict_entry_item_display_name(r, &sub, sink, source);
+ }
+ else if (pa_streq(property_name, "URLs")) {
+ append_property_dict_entry_urls(r, &sub, user_data, sink, source);
+ }
+ else if (pa_streq(property_name, "MIMEType")) {
+ append_property_dict_entry_mime_type(r, &sub, sink, source);
+ }
+ }
+ }
+
+ pa_assert_se(dbus_message_iter_close_container(iter, &sub));
+}
+
static const char *array_root_containers[] = { OBJECT_SINKS, OBJECT_SOURCES };
static const char *array_no_children[] = { };
@@ -349,50 +622,100 @@ static DBusHandlerResult root_handler(DBusConnection *c, DBusMessage *m, void *u
pa_assert(u);
- if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "Containers")) {
+ if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "ChildCount")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_object_array(r, NULL, (const char**) array_root_containers, PA_ELEMENTSOF(array_root_containers));
+ append_variant_unsigned(r, NULL, PA_ELEMENTSOF(array_root_containers));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "ContainerCount")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "ItemCount")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_unsigned(r, NULL, PA_ELEMENTSOF(array_root_containers));
+ append_variant_unsigned(r, NULL, PA_ELEMENTSOF(array_no_children));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "Items")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "ContainerCount")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_object_array(r, NULL, array_no_children, PA_ELEMENTSOF(array_no_children));
+ append_variant_unsigned(r, NULL, PA_ELEMENTSOF(array_root_containers));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "ItemCount")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "Searchable")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_unsigned(r, NULL, PA_ELEMENTSOF(array_no_children));
+ append_variant_boolean(r, NULL, FALSE);
- } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaContainer1")) {
+ } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaContainer2")) {
DBusMessageIter iter, sub;
pa_assert_se(r = dbus_message_new_method_return(m));
dbus_message_iter_init_append(r, &iter);
pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
- append_property_dict_entry_object_array(r, &sub, "Containers", array_root_containers, PA_ELEMENTSOF(array_root_containers));
- append_property_dict_entry_unsigned(r, &sub, "ContainerCount", PA_ELEMENTSOF(array_root_containers));
- append_property_dict_entry_object_array(r, &sub, "Items", array_no_children, PA_ELEMENTSOF(array_no_children));
+ append_property_dict_entry_unsigned(r, &sub, "ChildCount", PA_ELEMENTSOF(array_root_containers));
append_property_dict_entry_unsigned(r, &sub, "ItemCount", PA_ELEMENTSOF(array_no_children));
+ append_property_dict_entry_unsigned(r, &sub, "ContainerCount", PA_ELEMENTSOF(array_root_containers));
+ append_property_dict_entry_boolean(r, &sub, "Searchable", FALSE);
+ pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
+
+ } else if (dbus_message_is_method_call(m, "org.gnome.UPnP.MediaContainer2", "ListChildren")
+ || dbus_message_is_method_call(m, "org.gnome.UPnP.MediaContainer2", "ListContainers")) {
+ DBusMessageIter iter, sub;
+ unsigned offset, max;
+ char ** filter;
+ int filter_len;
+
+ pa_assert_se(r = dbus_message_new_method_return(m));
+
+ dbus_message_iter_init_append(r, &iter);
+ pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", &sub));
+
+ if (get_mediacontainer2_list_args(m, &offset, &max, &filter, &filter_len)) {
+ unsigned end = (max != 0 && offset + max < PA_ELEMENTSOF(array_root_containers))
+ ? max + offset
+ : PA_ELEMENTSOF(array_root_containers);
+
+ for (unsigned i = offset; i < end; ++i) {
+ const char *container_path = array_root_containers[i];
+ append_sink_or_source_container_properties(r, &sub, container_path, u, filter, filter_len);
+ }
+
+ dbus_free_string_array(filter);
+ }
+
+ pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
+
+ } else if (dbus_message_is_method_call(m, "org.gnome.UPnP.MediaContainer2", "ListItems")) {
+ DBusMessageIter iter, sub;
+
+ pa_assert_se(r = dbus_message_new_method_return(m));
+
+ dbus_message_iter_init_append(r, &iter);
+ pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", &sub));
pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject1", "Parent")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Parent")) {
pa_assert_se(r = dbus_message_new_method_return(m));
append_variant_object(r, NULL, OBJECT_ROOT);
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject1", "DisplayName")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Type")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_string(r, NULL, "container");
+
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Path")) {
+ const char *path = dbus_message_get_path(m);
+
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_object(r, NULL, path);
+
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "DisplayName")) {
pa_assert_se(r = dbus_message_new_method_return(m));
append_variant_string(r, NULL, u->display_name);
- } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaObject1")) {
+ } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaObject2")) {
DBusMessageIter iter, sub;
+ const char *path = dbus_message_get_path(m);
pa_assert_se(r = dbus_message_new_method_return(m));
dbus_message_iter_init_append(r, &iter);
pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
+ append_property_dict_entry_object(r, &sub, "Parent", OBJECT_ROOT);
+ append_property_dict_entry_string(r, &sub, "Type", "container");
+ append_property_dict_entry_object(r, &sub, "Path", path);
append_property_dict_entry_string(r, &sub, "DisplayName", u->display_name);
pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
@@ -416,7 +739,7 @@ static DBusHandlerResult root_handler(DBusConnection *c, DBusMessage *m, void *u
return DBUS_HANDLER_RESULT_HANDLED;
}
-static char *compute_url(struct userdata *u, const char *name) {
+static char *compute_url(const struct userdata *u, const char *name) {
pa_strlist *i;
pa_assert(u);
@@ -453,65 +776,6 @@ static char *compute_url(struct userdata *u, const char *name) {
return pa_sprintf_malloc("http://@ADDRESS@:4714/listen/source/%s", name);
}
-static char **child_array(struct userdata *u, const char *path, unsigned *n) {
- unsigned m;
- uint32_t idx;
- char **array;
-
- pa_assert(u);
- pa_assert(path);
- pa_assert(n);
-
- if (pa_streq(path, OBJECT_SINKS))
- m = pa_idxset_size(u->core->sinks);
- else {
- unsigned k;
-
- m = pa_idxset_size(u->core->sources);
- k = pa_idxset_size(u->core->sinks);
-
- pa_assert(m >= k);
-
- /* Subtract the monitor sources from the numbers of
- * sources. There is one monitor source for each sink */
- m -= k;
- }
-
- array = pa_xnew(char*, m);
- *n = 0;
-
- if (pa_streq(path, OBJECT_SINKS)) {
- pa_sink *sink;
-
- PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
- pa_assert((*n) < m);
- array[(*n)++] = pa_sprintf_malloc(OBJECT_SINKS "/%u", sink->index);
- }
- } else {
- pa_source *source;
-
- PA_IDXSET_FOREACH(source, u->core->sources, idx) {
-
- if (!source->monitor_of) {
- pa_assert((*n) < m);
- array[(*n)++] = pa_sprintf_malloc(OBJECT_SOURCES "/%u", source->index);
- }
- }
- }
-
- pa_assert((*n) <= m);
-
- return array;
-}
-
-static void free_child_array(char **array, unsigned n) {
-
- for (; n >= 1; n--)
- pa_xfree(array[n-1]);
-
- pa_xfree(array);
-}
-
static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
struct userdata *u = userdata;
DBusMessage *r = NULL;
@@ -525,66 +789,114 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag
/* Container nodes */
- if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "Containers")) {
+ if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "ChildCount")
+ || message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "ItemCount")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_object_array(r, NULL, array_no_children, PA_ELEMENTSOF(array_no_children));
+ append_variant_unsigned(r, NULL, get_sinks_or_sources_count(path, u));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "ContainerCount")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "ContainerCount")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_unsigned(r, NULL, PA_ELEMENTSOF(array_no_children));
+ append_variant_unsigned(r, NULL, 0);
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "Items")) {
- char ** array;
- unsigned n;
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer2", "Searchable")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_boolean(r, NULL, FALSE);
- array = child_array(u, path, &n);
+ } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaContainer2")) {
+ DBusMessageIter iter, sub;
+ unsigned item_count;
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_object_array(r, NULL, (const char**) array, n);
+ dbus_message_iter_init_append(r, &iter);
- free_child_array(array, n);
+ pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaContainer1", "ItemCount")) {
- unsigned n, k;
+ item_count = get_sinks_or_sources_count(path, u);
- n = pa_idxset_size(u->core->sinks);
- k = pa_idxset_size(u->core->sources);
- pa_assert(k >= n);
+ append_property_dict_entry_unsigned(r, &sub, "ChildCount", item_count);
+ append_property_dict_entry_unsigned(r, &sub, "ItemCount", item_count);
+ append_property_dict_entry_unsigned(r, &sub, "ContainerCount", 0);
+ append_property_dict_entry_boolean(r, &sub, "Searchable", FALSE);
- pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_unsigned(r, NULL,
- pa_streq(path, OBJECT_SINKS) ? n : k - n);
+ pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
- } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaContainer1")) {
+ } else if (dbus_message_is_method_call(m, "org.gnome.UPnP.MediaContainer2", "ListChildren")
+ || dbus_message_is_method_call(m, "org.gnome.UPnP.MediaContainer2", "ListItems")) {
DBusMessageIter iter, sub;
- char **array;
- unsigned n, k;
+ unsigned offset, max;
+ char **filter;
+ int filter_len;
pa_assert_se(r = dbus_message_new_method_return(m));
- dbus_message_iter_init_append(r, &iter);
- pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
- append_property_dict_entry_object_array(r, &sub, "Containers", array_no_children, PA_ELEMENTSOF(array_no_children));
- append_property_dict_entry_unsigned(r, &sub, "ContainerCount", 0);
+ dbus_message_iter_init_append(r, &iter);
+ pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", &sub));
+
+ if (get_mediacontainer2_list_args(m, &offset, &max, &filter, &filter_len)) {
+ unsigned end = (max != 0) ? max + offset : UINT_MAX;
+
+ if (pa_streq(path, OBJECT_SINKS)) {
+ pa_sink *sink;
+ char sink_path[sizeof(OBJECT_SINKS) + 32];
+ char *path_end = sink_path + sizeof(OBJECT_SINKS);
+ unsigned item_index = 0;
+ uint32_t idx;
+
+ strcpy(sink_path, OBJECT_SINKS "/");
+
+ PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
+ if (item_index >= offset && item_index < end) {
+ sprintf(path_end, "%u", sink->index);
+ append_sink_or_source_item_properties(r, &sub, sink_path, u, sink, NULL, filter, filter_len);
+ }
+ ++item_index;
+ }
+ } else {
+ pa_source *source;
+ char source_path[sizeof(OBJECT_SOURCES) + 32];
+ char *path_end = source_path + sizeof(OBJECT_SOURCES);
+ unsigned item_index = 0;
+ uint32_t idx;
+
+ strcpy(source_path, OBJECT_SOURCES "/");
+
+ PA_IDXSET_FOREACH(source, u->core->sources, idx)
+ if (!source->monitor_of) {
+ if (item_index >= offset && item_index < end) {
+ sprintf(path_end, "%u", source->index);
+ append_sink_or_source_item_properties(r, &sub, source_path, u, NULL, source, filter, filter_len);
+ }
+ ++item_index;
+ }
+ }
+
+ dbus_free_string_array(filter);
+ }
- array = child_array(u, path, &n);
- append_property_dict_entry_object_array(r, &sub, "Items", (const char**) array, n);
- free_child_array(array, n);
+ pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
- n = pa_idxset_size(u->core->sinks);
- k = pa_idxset_size(u->core->sources);
- pa_assert(k >= n);
+ } else if (dbus_message_is_method_call(m, "org.gnome.UPnP.MediaContainer2", "ListContainers")) {
+ DBusMessageIter iter, sub;
- append_property_dict_entry_unsigned(r, &sub, "ItemCount",
- pa_streq(path, OBJECT_SINKS) ? n : k - n);
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ dbus_message_iter_init_append(r, &iter);
+ pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", &sub));
pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject1", "Parent")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Parent")) {
pa_assert_se(r = dbus_message_new_method_return(m));
append_variant_object(r, NULL, OBJECT_ROOT);
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject1", "DisplayName")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Type")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_string(r, NULL, "container");
+
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Path")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_object(r, NULL, path);
+
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "DisplayName")) {
pa_assert_se(r = dbus_message_new_method_return(m));
append_variant_string(r,
NULL,
@@ -592,20 +904,14 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag
_("Output Devices") :
_("Input Devices"));
- } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaObject1")) {
+ } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaObject2")) {
DBusMessageIter iter, sub;
pa_assert_se(r = dbus_message_new_method_return(m));
dbus_message_iter_init_append(r, &iter);
-
pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
- append_property_dict_entry_object(m, &sub, "Parent", OBJECT_ROOT);
- append_property_dict_entry_string(m, &sub, "DisplayName",
- pa_streq(path, OBJECT_SINKS) ?
- _("Output Devices") :
- _("Input Devices"));
- pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
+ append_sink_or_source_container_mediaobject2_properties(r, &sub, path);
} else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
pa_strbuf *sb;
@@ -655,91 +961,49 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag
if (!sink && !source)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (message_is_property_get(m, "org.gnome.UPnP.MediaObject1", "Parent")) {
+ if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Parent")) {
pa_assert_se(r = dbus_message_new_method_return(m));
append_variant_object(r, NULL, sink ? OBJECT_SINKS : OBJECT_SOURCES);
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject1", "DisplayName")) {
- pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_string(r, NULL, pa_strna(pa_proplist_gets(sink ? sink->proplist : source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
-
- } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaObject1")) {
- DBusMessageIter iter, sub;
-
- pa_assert_se(r = dbus_message_new_method_return(m));
- dbus_message_iter_init_append(r, &iter);
-
- pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
- append_property_dict_entry_object(r, &sub, "Parent", sink ? OBJECT_SINKS : OBJECT_SOURCES);
- append_property_dict_entry_string(r, &sub, "DisplayName", pa_strna(pa_proplist_gets(sink ? sink->proplist : source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
- pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
-
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaItem1", "Type")) {
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Type")) {
pa_assert_se(r = dbus_message_new_method_return(m));
append_variant_string(r, NULL, "audio");
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaItem1", "MIMEType")) {
- char *t;
-
- if (sink)
- t = pa_sample_spec_to_mime_type_mimefy(&sink->sample_spec, &sink->channel_map);
- else
- t = pa_sample_spec_to_mime_type_mimefy(&source->sample_spec, &source->channel_map);
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "Path")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_object(r, NULL, path);
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaObject2", "DisplayName")) {
pa_assert_se(r = dbus_message_new_method_return(m));
- append_variant_string(r, NULL, t);
- pa_xfree(t);
+ append_variant_item_display_name(r, NULL, sink, source);
- } else if (message_is_property_get(m, "org.gnome.UPnP.MediaItem1", "URLs")) {
- DBusMessageIter iter, sub, array;
- char *url;
+ } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaObject2")) {
+ DBusMessageIter iter, sub;
pa_assert_se(r = dbus_message_new_method_return(m));
-
dbus_message_iter_init_append(r, &iter);
- url = compute_url(u, sink ? sink->monitor_source->name : source->name);
+ pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
+ append_sink_or_source_item_mediaobject2_properties(r, &sub, path, sink, source);
- pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "as", &sub));
- pa_assert_se(dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "s", &array));
- pa_assert_se(dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &url));
- pa_assert_se(dbus_message_iter_close_container(&sub, &array));
- pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaItem2", "MIMEType")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_mime_type(r, NULL, sink, source);
- pa_xfree(url);
+ } else if (message_is_property_get(m, "org.gnome.UPnP.MediaItem2", "URLs")) {
+ pa_assert_se(r = dbus_message_new_method_return(m));
+ append_variant_urls(r, NULL, u, sink, source);
- } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaItem1")) {
- DBusMessageIter iter, sub, dict, variant, array;
- char *url, *t;
- const char *un = "URLs";
+ } else if (message_is_property_get_all(m, "org.gnome.UPnP.MediaItem2")) {
+ DBusMessageIter iter, sub;
pa_assert_se(r = dbus_message_new_method_return(m));
dbus_message_iter_init_append(r, &iter);
pa_assert_se(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub));
- append_property_dict_entry_string(r, &sub, "Type", "audio");
-
- if (sink)
- t = pa_sample_spec_to_mime_type_mimefy(&sink->sample_spec, &sink->channel_map);
- else
- t = pa_sample_spec_to_mime_type_mimefy(&source->sample_spec, &source->channel_map);
-
- append_property_dict_entry_string(r, &sub, "MIMEType", t);
- pa_xfree(t);
-
- pa_assert_se(dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &dict));
- pa_assert_se(dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &un));
-
- url = compute_url(u, sink ? sink->monitor_source->name : source->name);
-
- pa_assert_se(dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "as", &variant));
- pa_assert_se(dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "s", &array));
- pa_assert_se(dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &url));
- pa_assert_se(dbus_message_iter_close_container(&variant, &array));
- pa_assert_se(dbus_message_iter_close_container(&dict, &variant));
- pa_assert_se(dbus_message_iter_close_container(&sub, &dict));
- pa_xfree(url);
+ append_property_dict_entry_mime_type(r, &sub, sink, source);
+ append_property_dict_entry_urls(r, &sub, u, sink, source);
pa_assert_se(dbus_message_iter_close_container(&iter, &sub));
--
hooks/post-receive
PulseAudio Sound Server
More information about the pulseaudio-commits
mailing list