[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v1.0-dev-285-g495c1ed

Colin Guthrie gitmailer-noreply at 0pointer.de
Thu Apr 28 06:12:58 PDT 2011


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 master branch has been updated
      from  fd14a9af359657c5c3b9bd8b031c4b7cacd6e357 (commit)

- Log -----------------------------------------------------------------
495c1ed core: Drop empty gaps in the memblockq when playing data from it.
fea4942 stream-restore: Enable database dumping if DEBUG_VOLUME is defined.
4c3f7b0 module-null-source: New null-source module
88e6078 x11: Fix build errors with newest xcb-util.
-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am                                    |    6 +
 .../{module-sine-source.c => module-null-source.c} |  190 ++++++++------------
 src/modules/module-stream-restore.c                |    4 +-
 src/pulsecore/play-memblockq.c                     |   13 +-
 src/pulsecore/x11prop.c                            |   26 ++-
 5 files changed, 109 insertions(+), 130 deletions(-)
 copy src/modules/{module-sine-source.c => module-null-source.c} (59%)

-----------------------------------------------------------------------

commit 88e6078f3b74002c58b69f8b69f6c043d65ef80b
Author: Maciej Grela <maciej.grela at gmail.com>
Date:   Tue Mar 29 22:56:28 2011 +0159

    x11: Fix build errors with newest xcb-util.
    
    The xcb_atom_get functions were removed from xcb-util. Changed these to
    xcb_intern_atom/xcb_intern_atom_reply. Also, STRING is now
    XCB_ATOM_STRING.

diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c
index 8df3278..99ea55d 100644
--- a/src/pulsecore/x11prop.c
+++ b/src/pulsecore/x11prop.c
@@ -49,28 +49,34 @@ static xcb_screen_t *screen_of_display(xcb_connection_t *xcb, int screen) {
 
 void pa_x11_set_prop(xcb_connection_t *xcb, int screen, const char *name, const char *data) {
     xcb_screen_t *xs;
-    xcb_atom_t a;
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply;
 
     pa_assert(xcb);
     pa_assert(name);
     pa_assert(data);
 
     if ((xs = screen_of_display(xcb, screen))) {
-        a = xcb_atom_get(xcb, name);
-        xcb_change_property(xcb, XCB_PROP_MODE_REPLACE, xs->root, a, STRING, PA_XCB_FORMAT, (int) strlen(data), (const void*) data);
+        cookie = xcb_intern_atom(xcb, 0, strlen(name), name);
+        reply = xcb_intern_atom_reply(xcb, cookie, NULL);
+
+        xcb_change_property(xcb, XCB_PROP_MODE_REPLACE, xs->root, reply->atom, XCB_ATOM_STRING, PA_XCB_FORMAT, (int) strlen(data), (const void*) data);
     }
 }
 
 void pa_x11_del_prop(xcb_connection_t *xcb, int screen, const char *name) {
     xcb_screen_t *xs;
-    xcb_atom_t a;
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply;
 
     pa_assert(xcb);
     pa_assert(name);
 
     if ((xs = screen_of_display(xcb, screen))) {
-        a = xcb_atom_get(xcb, name);
-        xcb_delete_property(xcb, xs->root, a);
+        cookie = xcb_intern_atom(xcb, 0, strlen(name), name);
+        reply = xcb_intern_atom_reply(xcb, cookie, NULL);
+
+        xcb_delete_property(xcb, xs->root, reply->atom);
     }
 }
 
@@ -80,7 +86,8 @@ char* pa_x11_get_prop(xcb_connection_t *xcb, int screen, const char *name, char
     xcb_get_property_cookie_t req;
     xcb_get_property_reply_t* prop = NULL;
     xcb_screen_t *xs;
-    xcb_atom_t a;
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply;
 
     pa_assert(xcb);
     pa_assert(name);
@@ -98,9 +105,10 @@ char* pa_x11_get_prop(xcb_connection_t *xcb, int screen, const char *name, char
         xs = screen_of_display(xcb, 0);
 
     if (xs) {
-        a = xcb_atom_get(xcb, name);
+        cookie = xcb_intern_atom(xcb, 0, strlen(name), name);
+        reply = xcb_intern_atom_reply(xcb, cookie, NULL);
 
-        req = xcb_get_property(xcb, 0, xs->root, a, STRING, 0, (uint32_t)(l-1));
+        req = xcb_get_property(xcb, 0, xs->root, reply->atom, XCB_ATOM_STRING, 0, (uint32_t)(l-1));
         prop = xcb_get_property_reply(xcb, req, NULL);
 
         if (!prop)

commit 4c3f7b0f30a6ca4f29458e7d455da7ba6f1dddfb
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Wed Apr 27 14:50:00 2011 +0300

    module-null-source: New null-source module

diff --git a/src/Makefile.am b/src/Makefile.am
index cfa2e1f..a6a16ea 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1022,6 +1022,7 @@ modlibexec_LTLIBRARIES += \
 		module-cli-protocol-tcp.la \
 		module-simple-protocol-tcp.la \
 		module-null-sink.la \
+		module-null-source.la \
 		module-sine-source.la \
 		module-detect.la \
 		module-volume-restore.la \
@@ -1287,6 +1288,7 @@ SYMDEF_FILES = \
 		module-tunnel-sink-symdef.h \
 		module-tunnel-source-symdef.h \
 		module-null-sink-symdef.h \
+		module-null-source-symdef.h \
 		module-sine-source-symdef.h \
 		module-esound-sink-symdef.h \
 		module-zeroconf-publish-symdef.h \
@@ -1476,6 +1478,10 @@ module_null_sink_la_SOURCES = modules/module-null-sink.c
 module_null_sink_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_null_sink_la_LIBADD = $(MODULE_LIBADD)
 
+module_null_source_la_SOURCES = modules/module-null-source.c
+module_null_source_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_null_source_la_LIBADD = $(MODULE_LIBADD)
+
 module_sine_source_la_SOURCES = modules/module-sine-source.c
 module_sine_source_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_sine_source_la_LIBADD = $(MODULE_LIBADD)
diff --git a/src/modules/module-null-source.c b/src/modules/module-null-source.c
new file mode 100644
index 0000000..358ffc6
--- /dev/null
+++ b/src/modules/module-null-source.c
@@ -0,0 +1,294 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2008 Lennart Poettering
+  Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <pulse/rtclock.h>
+#include <pulse/timeval.h>
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/core-error.h>
+#include <pulsecore/core-rtclock.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/module.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/source.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/thread.h>
+
+#include "module-null-source-symdef.h"
+
+PA_MODULE_AUTHOR("Lennart Poettering & Marc-Andre Lureau");
+PA_MODULE_DESCRIPTION("Clocked NULL source");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(FALSE);
+PA_MODULE_USAGE(
+        "format=<sample format> "
+        "channels=<number of channels> "
+        "rate=<sample rate> "
+        "source_name=<name of source> "
+        "channel_map=<channel map> "
+        "description=<description for the source> "
+        "latency_time=<latency time in ms>");
+
+#define DEFAULT_SOURCE_NAME "source.null"
+#define DEFAULT_LATENCY_TIME 20
+#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2)
+
+struct userdata {
+    pa_core *core;
+    pa_module *module;
+    pa_source *source;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
+    size_t block_size;
+
+    pa_usec_t block_usec;
+    pa_usec_t timestamp;
+    pa_usec_t latency_time;
+};
+
+static const char* const valid_modargs[] = {
+    "rate",
+    "format",
+    "channels",
+    "source_name",
+    "channel_map",
+    "description",
+    "latency_time",
+    NULL
+};
+
+static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SOURCE(o)->userdata;
+
+    switch (code) {
+        case PA_SOURCE_MESSAGE_SET_STATE:
+
+            if (PA_PTR_TO_UINT(data) == PA_SOURCE_RUNNING)
+                u->timestamp = pa_rtclock_now();
+
+            break;
+
+        case PA_SOURCE_MESSAGE_GET_LATENCY: {
+            pa_usec_t now;
+
+            now = pa_rtclock_now();
+            *((pa_usec_t*) data) = u->timestamp > now ? u->timestamp - now : 0;
+
+            return 0;
+        }
+    }
+
+    return pa_source_process_msg(o, code, data, offset, chunk);
+}
+
+static void source_update_requested_latency_cb(pa_source *s) {
+    struct userdata *u;
+
+    pa_source_assert_ref(s);
+    u = s->userdata;
+    pa_assert(u);
+
+    u->block_usec = pa_source_get_requested_latency_within_thread(s);
+}
+
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    pa_thread_mq_install(&u->thread_mq);
+
+    u->timestamp = pa_rtclock_now();
+
+    for (;;) {
+        int ret;
+
+        /* Generate some null data */
+        if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
+            pa_usec_t now;
+            pa_memchunk chunk;
+
+            now = pa_rtclock_now();
+
+            if ((chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec)) > 0) {
+
+                chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1); /* or chunk.length? */
+                chunk.index = 0;
+                pa_source_post(u->source, &chunk);
+                pa_memblock_unref(chunk.memblock);
+
+                u->timestamp = now;
+            }
+
+            pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->latency_time * PA_USEC_PER_MSEC);
+        } else
+            pa_rtpoll_set_timer_disabled(u->rtpoll);
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+int pa__init(pa_module*m) {
+    struct userdata *u = NULL;
+    pa_sample_spec ss;
+    pa_channel_map map;
+    pa_modargs *ma = NULL;
+    pa_source_new_data data;
+    uint32_t latency_time = DEFAULT_LATENCY_TIME;
+
+    pa_assert(m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments.");
+        goto fail;
+    }
+
+    ss = m->core->default_sample_spec;
+    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
+        pa_log("Invalid sample format specification or channel map");
+        goto fail;
+    }
+
+    m->userdata = u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
+    u->rtpoll = pa_rtpoll_new();
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
+
+    pa_source_new_data_init(&data);
+    data.driver = __FILE__;
+    data.module = m;
+    pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
+    pa_source_new_data_set_sample_spec(&data, &ss);
+    pa_source_new_data_set_channel_map(&data, &map);
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Input"));
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
+
+    u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY);
+    pa_source_new_data_done(&data);
+
+    if (!u->source) {
+        pa_log("Failed to create source object.");
+        goto fail;
+    }
+
+    u->latency_time = DEFAULT_LATENCY_TIME;
+    if (pa_modargs_get_value_u32(ma, "latency_time", &latency_time) < 0) {
+        pa_log("Failed to parse latency_time value.");
+        goto fail;
+    }
+    u->latency_time = latency_time;
+
+    u->source->parent.process_msg = source_process_msg;
+    u->source->update_requested_latency = source_update_requested_latency_cb;
+    u->source->userdata = u;
+
+    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+    pa_source_set_rtpoll(u->source, u->rtpoll);
+
+    pa_source_set_latency_range(u->source, 0, MAX_LATENCY_USEC);
+    u->block_usec = u->source->thread_info.max_latency;
+
+    u->source->thread_info.max_rewind =
+        pa_usec_to_bytes(u->block_usec, &u->source->sample_spec);
+
+    if (!(u->thread = pa_thread_new("null-source", thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+
+    pa_source_put(u->source);
+
+    pa_modargs_free(ma);
+
+    return 0;
+
+fail:
+    if (ma)
+        pa_modargs_free(ma);
+
+    pa__done(m);
+
+    return -1;
+}
+
+void pa__done(pa_module*m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
+        return;
+
+    if (u->source)
+        pa_source_unlink(u->source);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->source)
+        pa_source_unref(u->source);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    pa_xfree(u);
+}

commit fea4942aa2b99ee71a1e854bbdab64c6766cd770
Author: Tanu Kaskinen <ext-tanu.kaskinen at nokia.com>
Date:   Wed Apr 27 13:08:38 2011 +0300

    stream-restore: Enable database dumping if DEBUG_VOLUME is defined.

diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index 4d1ea04..77b6949 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -1690,8 +1690,8 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
     }
 }
 
-#if 0
-static void dump_database(struct userdata *u) {
+#ifdef DEBUG_VOLUME
+PA_GCC_UNUSED static void stream_restore_dump_database(struct userdata *u) {
     pa_datum key;
     pa_bool_t done;
 

commit 495c1ed2361f7bab5eaa6978d2fda624a2944bb9
Author: Antti-Ville Jansson <antti-ville.jansson at digia.com>
Date:   Wed Apr 20 15:56:29 2011 +0300

    core: Drop empty gaps in the memblockq when playing data from it.
    
    It's possible that the memblockq of a sink input is rewound to a negative read
    index if the sink input is moved between sinks shortly after its creation. When
    this happens, pa_memblockq_peek() returns a memchunk whose 'memblock' field is
    NULL and whose 'length' field indicates the length of the gap caused by the
    negative read index. This will trigger an assert in play-memblockq.c.
    
    If the memblockq had a silence memchunk, pa_memblockq_peek() would return
    silence for the duration of the gap and the assert would be avoided. However,
    this approach would prevent the sink input from being drained and is thus not
    possible. Instead, we handle the aforementioned situation by dropping the gap
    indicated by the 'length' field of the memchunk and by peeking the actual data
    that comes after the gap.
    
    This scenario seems to be quite rare in everyday use, but it causes a severe
    bug in the handheld world. The assert can be triggered e.g. by loading two null
    sinks, playing a sample from the cache to one of them and then moving the
    created sink input between the two sinks. The rewinds done by the null sinks
    seem to be quite long (I don't know if this is normal behaviour or something
    fishy in module-null-sink).
    
    See also:
    
        6bd34156b130c07b130de10111a12ef6dab18b52
        virtual-sink: Fix a crash when moving the sink to a new master right after setup.
    
        https://tango.0pointer.de/pipermail/pulseaudio-discuss/2011-February/009105.html
    
    Reproduce:
    
    This problem can be reproduced with the following script:
    
    SAMPLE_PATH="/usr/share/sounds/alsa/"
    SAMPLE="Front_Left"
    
    pactl remove-sample $SAMPLE 2> /dev/null
    pactl upload-sample $SAMPLE_PATH$SAMPLE.wav
    
    mod1=`pactl load-module module-null-sink sink_name=null1`
    mod2=`pactl load-module module-null-sink sink_name=null2`
    
    pactl play-sample $SAMPLE null1
    
    input=`pactl list | grep "Sink Input #" | tail -n 1 | cut -d# -f2`
    
    echo "Sample $SAMPLE playing as Sink Input #$input"
    
    pactl move-sink-input $input null2
    pactl move-sink-input $input null1
    
    pactl unload-module $mod1
    pactl unload-module $mod2

diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index f075a5b..66e47ea 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -135,11 +135,14 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
         return -1;
     }
 
-    /* FIXME: u->memblockq doesn't have a silence memchunk set, so
-     * pa_memblockq_peek() will return 0 without returning any memblock if the
-     * read index points to a hole. If the memblockq is rewound beyond index 0,
-     * then there will be a hole. */
-    pa_assert(chunk->memblock);
+    /* If there's no memblock, there's going to be data in the memblockq after
+     * a gap with length chunk->length. Drop the the gap and peek the actual
+     * data. There should always be some data coming - hence the assert. The
+     * gap will occur if the memblockq is rewound beyond index 0.*/
+    if (!chunk->memblock) {
+        pa_memblockq_drop(u->memblockq, chunk->length);
+        pa_assert_se(pa_memblockq_peek(u->memblockq, chunk) >= 0);
+    }
 
     chunk->length = PA_MIN(chunk->length, nbytes);
     pa_memblockq_drop(u->memblockq, chunk->length);

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list