[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.13-111-gef9f3f6

Lennart Poettering gitmailer-noreply at 0pointer.de
Tue Oct 21 11:01:44 PDT 2008


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

- Log -----------------------------------------------------------------
ef9f3f6... Try to catch certain driver errors
1647191... make log meta, time, backtrace configurable using command line
496499c... Make log meta, time, backtrace configurable using config file
651a451... support changing logging parameters during runtime using the CLI
f4320d8... Support showing a backtrace on log messages
f92a814... include log.h near the end so that macro.h can be included in log.h and defines pa_bool_t properly
d4c6342... add pa_config_parse_unsigned()
c7ed771... fix arguments to format string
7fecb23... convert argument to boolean int in PA_UNLIKELY, too
519bb55... fix return value of pa_frame_aligned()
4ee5e06... implement may_move_to for ladspa/remap sinks
358824b... add new virtual function may_move_to to sink inputs/source outputs to allow modules to forbid certain connections
309bc71... fix invalid validity check
-----------------------------------------------------------------------

Summary of changes:
 configure.ac                        |    1 +
 src/daemon/cmdline.c                |   27 +++++++
 src/daemon/daemon-conf.c            |  133 ++++++++++++++++-------------------
 src/daemon/daemon-conf.h            |    5 +-
 src/daemon/daemon.conf.in           |    3 +
 src/daemon/main.c                   |    3 +
 src/modules/alsa-util.c             |   60 ++++++++++++++++
 src/modules/alsa-util.h             |    3 +
 src/modules/module-alsa-sink.c      |    6 +-
 src/modules/module-alsa-source.c    |    6 +-
 src/modules/module-ladspa-sink.c    |   11 +++
 src/modules/module-remap-sink.c     |   11 +++
 src/modules/module-stream-restore.c |    2 +-
 src/pulsecore/cli-command.c         |  104 +++++++++++++++++++++++++++
 src/pulsecore/conf-parser.c         |   18 +++++
 src/pulsecore/conf-parser.h         |    1 +
 src/pulsecore/log.c                 |  133 +++++++++++++++++++++++++++++++----
 src/pulsecore/log.h                 |    7 ++-
 src/pulsecore/macro.h               |    6 +-
 src/pulsecore/sample-util.c         |    2 +-
 src/pulsecore/sample-util.h         |    2 +-
 src/pulsecore/sink-input.c          |   46 +++++++++----
 src/pulsecore/sink-input.h          |    8 ++-
 src/pulsecore/source-output.c       |   37 +++++++---
 src/pulsecore/source-output.h       |    8 ++-
 25 files changed, 518 insertions(+), 125 deletions(-)

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

commit 309bc71f07bdb00ecf050d7a4b1734accafcb95f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:22:28 2008 +0200

    fix invalid validity check

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 8505c63..1384116 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -157,10 +157,10 @@ pa_sink_input* pa_sink_input_new(
     }
 
     pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
-    pa_return_null_if_fail(pa_cvolume_compatible(&data->volume.channels, &data->sample_spec));
+    pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
 
     pa_return_null_if_fail(pa_cvolume_valid(&data->virtual_volume));
-    pa_return_null_if_fail(pa_cvolume_compatible(&data->virtual_volume.channels, &data->sample_spec));
+    pa_return_null_if_fail(pa_cvolume_compatible(&data->virtual_volume, &data->sample_spec));
 
     if (!data->muted_is_set)
         data->muted = FALSE;

commit 358824b330e20b9e6472fdefc4613e03b20c9abb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:24:45 2008 +0200

    add new virtual function may_move_to to sink inputs/source outputs to allow modules to forbid certain connections

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 1384116..0e1224f 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -108,6 +108,7 @@ static void reset_callbacks(pa_sink_input *i) {
     i->kill = NULL;
     i->get_latency = NULL;
     i->state_change = NULL;
+    i->may_move_to = NULL;
 }
 
 /* Called from main context */
@@ -911,6 +912,35 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
 }
 
 /* Called from main context */
+pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+    pa_sink_assert_ref(dest);
+
+    if (dest == i->sink)
+        return TRUE;
+
+    if (i->flags & PA_SINK_INPUT_DONT_MOVE)
+        return FALSE;
+
+    if (i->sync_next || i->sync_prev) {
+        pa_log_warn("Moving synchronised streams not supported.");
+        return FALSE;
+    }
+
+    if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
+        pa_log_warn("Failed to move sink input: too many inputs per sink.");
+        return FALSE;
+    }
+
+    if (i->may_move_to)
+        if (!i->may_move_to(i, dest))
+            return FALSE;
+
+    return TRUE;
+}
+
+/* Called from main context */
 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
     pa_resampler *new_resampler;
     pa_sink *origin;
@@ -926,19 +956,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
     if (dest == origin)
         return 0;
 
-    if (i->flags & PA_SINK_INPUT_DONT_MOVE)
+    if (!pa_sink_input_may_move_to(i, dest))
         return -1;
 
-    if (i->sync_next || i->sync_prev) {
-        pa_log_warn("Moving synchronised streams not supported.");
-        return -1;
-    }
-
-    if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
-        pa_log_warn("Failed to move sink input: too many inputs per sink.");
-        return -1;
-    }
-
     /* Kill directly connected outputs */
     while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
         pa_assert(o != p);
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index ed95fe4..97668c5 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -156,10 +156,15 @@ struct pa_sink_input {
     returns */
     pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */
 
-    /* If non_NULL this function is called from thread context if the
+    /* If non-NULL this function is called from thread context if the
      * state changes. The old state is found in thread_info.state.  */
     void (*state_change) (pa_sink_input *i, pa_sink_input_state_t state); /* may be NULL */
 
+    /* If non-NULL this function is called before this sink input is
+     * move to a sink and if it returns FALSE the move will not
+     * be allowed */
+    pa_bool_t (*may_move_to) (pa_sink_input *i, pa_sink *s); /* may be NULL */
+
     struct {
         pa_sink_input_state_t state;
         pa_atomic_t drained;
@@ -292,6 +297,7 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i);
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
 
 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest);
+pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest);
 
 pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i);
 
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 7adc757..376402f 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -90,6 +90,7 @@ static void reset_callbacks(pa_source_output *o) {
     o->kill = NULL;
     o->get_latency = NULL;
     o->state_change = NULL;
+    o->may_move_to = NULL;
 }
 
 /* Called from main context */
@@ -593,6 +594,32 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
     return o->resample_method;
 }
 
+pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) {
+    pa_source_output_assert_ref(o);
+    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
+    pa_source_assert_ref(dest);
+
+    if (dest == o->source)
+        return TRUE;
+
+    if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
+        return FALSE;
+
+    if (o->direct_on_input)
+        return FALSE;
+
+    if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
+        pa_log_warn("Failed to move source output: too many outputs per source.");
+        return FALSE;
+    }
+
+    if (o->may_move_to)
+        if (!o->may_move_to(o, dest))
+            return FALSE;
+
+    return TRUE;
+}
+
 /* Called from main context */
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
     pa_source *origin;
@@ -608,16 +635,8 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
     if (dest == origin)
         return 0;
 
-    if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
-        return -1;
-
-    if (o->direct_on_input)
-        return -1;
-
-    if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
-        pa_log_warn("Failed to move source output: too many outputs per source.");
+    if (!pa_source_output_may_move_to(o, dest))
         return -1;
-    }
 
     if (o->thread_info.resampler &&
         pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index a7aac81..6ae10c6 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -126,10 +126,15 @@ struct pa_source_output {
     returns */
     pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */
 
-    /* If non_NULL this function is called from thread context if the
+    /* If non-NULL this function is called from thread context if the
      * state changes. The old state is found in thread_info.state.  */
     void (*state_change) (pa_source_output *o, pa_source_output_state_t state); /* may be NULL */
 
+    /* If non-NULL this function is called before this source output
+     * is moved to a source and if it returns FALSE the move
+     * will not be allowed */
+    pa_bool_t (*may_move_to) (pa_source_output *o, pa_source *s); /* may be NULL */
+
     struct {
         pa_source_output_state_t state;
 
@@ -220,6 +225,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *i, pa_usec_t *source_la
 
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o);
 
+pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest);
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest);
 
 #define pa_source_output_get_state(o) ((o)->state)

commit 4ee5e06f386c91d436f1702c51484130c1e2f413
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:25:26 2008 +0200

    implement may_move_to for ladspa/remap sinks

diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index 9127af0..a27ed71 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -359,6 +359,16 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
     }
 }
 
+/* Called from main context */
+static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
+    struct userdata *u;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(u = i->userdata);
+
+    return u->sink != dest;
+}
+
 int pa__init(pa_module*m) {
     struct userdata *u;
     pa_sample_spec ss;
@@ -737,6 +747,7 @@ int pa__init(pa_module*m) {
     u->sink_input->attach = sink_input_attach_cb;
     u->sink_input->detach = sink_input_detach_cb;
     u->sink_input->state_change = sink_input_state_change_cb;
+    u->sink_input->may_move_to = sink_input_may_move_to_cb;
     u->sink_input->userdata = u;
 
     pa_sink_put(u->sink);
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index 5b2be11..976a8ce 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -274,6 +274,16 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
     }
 }
 
+/* Called from main context */
+static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
+    struct userdata *u;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(u = i->userdata);
+
+    return u->sink != dest;
+}
+
 int pa__init(pa_module*m) {
     struct userdata *u;
     pa_sample_spec ss;
@@ -386,6 +396,7 @@ int pa__init(pa_module*m) {
     u->sink_input->detach = sink_input_detach_cb;
     u->sink_input->kill = sink_input_kill_cb;
     u->sink_input->state_change = sink_input_state_change_cb;
+    u->sink_input->may_move_to = sink_input_may_move_to_cb;
     u->sink_input->userdata = u;
 
     pa_sink_put(u->sink);

commit 519bb556cd2ca47e62247a87d5d76cde1ca2c18b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:26:24 2008 +0200

    fix return value of pa_frame_aligned()

diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c
index 7b9ac7b..9f0f795 100644
--- a/src/pulsecore/sample-util.c
+++ b/src/pulsecore/sample-util.c
@@ -777,7 +777,7 @@ size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
     return (l/fs) * fs;
 }
 
-int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
+pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
     size_t fs;
 
     pa_assert(ss);
diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h
index 06ecb72..2fe2c81 100644
--- a/src/pulsecore/sample-util.h
+++ b/src/pulsecore/sample-util.h
@@ -71,7 +71,7 @@ void pa_volume_memchunk(
 
 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
 
-int pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
+pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
 
 void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n);
 void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n);

commit 7fecb2340e0ffa3f7ec2c9542cbcdefa70786120
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:27:25 2008 +0200

    convert argument to boolean int in PA_UNLIKELY, too

diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h
index 39e9b58..2d031da 100644
--- a/src/pulsecore/macro.h
+++ b/src/pulsecore/macro.h
@@ -40,7 +40,7 @@
 #ifndef PA_LIKELY
 #ifdef __GNUC__
 #define PA_LIKELY(x) (__builtin_expect(!!(x),1))
-#define PA_UNLIKELY(x) (__builtin_expect((x),0))
+#define PA_UNLIKELY(x) (__builtin_expect(!!(x),0))
 #else
 #define PA_LIKELY(x) (x)
 #define PA_UNLIKELY(x) (x)

commit c7ed771a98dab63bb954942d20297bb93aed76af
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:28:19 2008 +0200

    fix arguments to format string

diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index e1381a5..5589700 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -134,7 +134,7 @@ static char *get_name(pa_proplist *p, const char *prefix) {
     else if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_NAME)))
         return pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
 
-    return pa_sprintf_malloc("%s-fallback:%s", prefix);
+    return pa_sprintf_malloc("%s-fallback:%s", prefix, r);
 }
 
 static struct entry* read_entry(struct userdata *u, char *name) {

commit d4c63420320da18a6223554976dec1b02ee9ac90
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:38:55 2008 +0200

    add pa_config_parse_unsigned()

diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c
index 58ceab9..ef6d6bb 100644
--- a/src/pulsecore/conf-parser.c
+++ b/src/pulsecore/conf-parser.c
@@ -166,6 +166,24 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue,
     return 0;
 }
 
+int pa_config_parse_unsigned(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+    unsigned *u = data;
+    uint32_t k;
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
+
+    if (pa_atou(rvalue, &k) < 0) {
+        pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+        return -1;
+    }
+
+    *u = (unsigned) k;
+    return 0;
+}
+
 int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
     size_t *i = data;
     uint32_t k;
diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h
index a5174fc..48a0fd2 100644
--- a/src/pulsecore/conf-parser.h
+++ b/src/pulsecore/conf-parser.h
@@ -41,6 +41,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
 
 /* Generic parsers for integers, size_t, booleans and strings */
 int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int pa_config_parse_unsigned(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
 int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
 int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
 int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);

commit f92a8141188236f07c95a5912e905acab0f75e7d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 18:40:01 2008 +0200

    include log.h near the end so that macro.h can be included in log.h and defines pa_bool_t properly

diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h
index 2d031da..cf02696 100644
--- a/src/pulsecore/macro.h
+++ b/src/pulsecore/macro.h
@@ -30,7 +30,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <pulsecore/log.h>
 #include <pulse/gccmacro.h>
 
 #ifndef PACKAGE
@@ -221,4 +220,7 @@ typedef int pa_bool_t;
 
 #endif
 
+/* We include this at the very last place */
+#include <pulsecore/log.h>
+
 #endif

commit f4320d83a2f801af34e577585c1abba3a14b9e4c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 19:13:15 2008 +0200

    Support showing a backtrace on log messages

diff --git a/configure.ac b/configure.ac
index 2a04076..f93903d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -297,6 +297,7 @@ AC_CHECK_HEADERS([sys/ioctl.h])
 AC_CHECK_HEADERS([byteswap.h])
 AC_CHECK_HEADERS([sys/syscall.h])
 AC_CHECK_HEADERS([sys/eventfd.h])
+AC_CHECK_HEADERS([execinfo.h])
 
 #### Typdefs, structures, etc. ####
 
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index b1de696..adf2f11 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -30,6 +30,10 @@
 #include <string.h>
 #include <errno.h>
 
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
 #ifdef HAVE_SYSLOG_H
 #include <syslog.h>
 #endif
@@ -49,11 +53,15 @@
 #define ENV_LOGLEVEL "PULSE_LOG"
 #define ENV_LOGMETA "PULSE_LOG_META"
 #define ENV_LOGTIME "PULSE_LOG_TIME"
+#define ENV_LOGBACKTRACE "PULSE_LOG_BACKTRACE"
 
 static char *log_ident = NULL, *log_ident_local = NULL;
 static pa_log_target_t log_target = PA_LOG_STDERR;
 static pa_log_func_t user_log_func = NULL;
 static pa_log_level_t maximal_level = PA_LOG_ERROR;
+static unsigned show_backtrace = 0;
+static pa_bool_t show_meta = FALSE;
+static pa_bool_t show_time = FALSE;
 
 #ifdef HAVE_SYSLOG_H
 static const int level_to_syslog[] = {
@@ -105,6 +113,74 @@ void pa_log_set_target(pa_log_target_t t, pa_log_func_t func) {
     user_log_func = func;
 }
 
+void pa_log_set_show_meta(pa_bool_t b) {
+    show_meta = b;
+}
+
+void pa_log_set_show_time(pa_bool_t b) {
+    show_time = b;
+}
+
+void pa_log_set_show_backtrace(unsigned nlevels) {
+    show_backtrace = nlevels;
+}
+
+#ifdef HAVE_EXECINFO_H
+
+static char* get_backtrace(unsigned show_nframes) {
+    void* trace[32];
+    int n_frames;
+    char **symbols, *e, *r;
+    unsigned j, n;
+    size_t a;
+
+    if (show_nframes <= 0)
+        return NULL;
+
+    n_frames = backtrace(trace, PA_ELEMENTSOF(trace));
+
+    if (n_frames <= 0)
+        return NULL;
+
+    symbols = backtrace_symbols(trace, n_frames);
+
+    if (!symbols)
+        return NULL;
+
+    n = PA_MIN((unsigned) n_frames, show_nframes);
+
+    a = 4;
+
+    for (j = 0; j < n; j++) {
+        if (j > 0)
+            a += 2;
+        a += strlen(symbols[j]);
+    }
+
+    r = pa_xnew(char, a);
+
+    strcpy(r, " (");
+    e = r + 2;
+
+    for (j = 0; j < n; j++) {
+        if (j > 0) {
+            strcpy(e, "<<");
+            e += 2;
+        }
+
+        strcpy(e, symbols[j]);
+        e += strlen(symbols[j]);
+    }
+
+    strcpy(e, ")");
+
+    free(symbols);
+
+    return r;
+}
+
+#endif
+
 void pa_log_levelv_meta(
         pa_log_level_t level,
         const char*file,
@@ -116,32 +192,43 @@ void pa_log_levelv_meta(
     const char *e;
     char *t, *n;
     int saved_errno = errno;
+    char *bt = NULL;
+    pa_log_level_t ml;
+#ifdef HAVE_EXECINFO_H
+    unsigned show_bt;
+#endif
 
     /* We don't use dynamic memory allocation here to minimize the hit
      * in RT threads */
-    char text[1024], location[128], timestamp[32];
+    char text[4096], location[128], timestamp[32];
 
     pa_assert(level < PA_LOG_LEVEL_MAX);
     pa_assert(format);
 
-    if ((e = getenv(ENV_LOGLEVEL)))
-        maximal_level = atoi(e);
+    ml = maximal_level;
+
+    if (PA_UNLIKELY((e = getenv(ENV_LOGLEVEL)))) {
+        pa_log_level_t eml = (pa_log_level_t) atoi(e);
 
-    if (level > maximal_level) {
+        if (eml > ml)
+            ml = eml;
+    }
+
+    if (PA_LIKELY(level > ml)) {
         errno = saved_errno;
         return;
     }
 
     pa_vsnprintf(text, sizeof(text), format, ap);
 
-    if (getenv(ENV_LOGMETA) && file && line > 0 && func)
+    if ((show_meta || getenv(ENV_LOGMETA)) && file && line > 0 && func)
         pa_snprintf(location, sizeof(location), "[%s:%i %s()] ", file, line, func);
     else if (file)
         pa_snprintf(location, sizeof(location), "%s: ", pa_path_get_filename(file));
     else
         location[0] = 0;
 
-    if (getenv(ENV_LOGTIME)) {
+    if (show_time || getenv(ENV_LOGTIME)) {
         static pa_usec_t start, last;
         pa_usec_t u, a, r;
 
@@ -168,6 +255,19 @@ void pa_log_levelv_meta(
     } else
         timestamp[0] = 0;
 
+#ifdef HAVE_EXECINFO_H
+    show_bt = show_backtrace;
+
+    if ((e = getenv(ENV_LOGBACKTRACE))) {
+        unsigned ebt = (unsigned) atoi(e);
+
+        if (ebt > show_bt)
+            show_bt = ebt;
+    }
+
+    bt = get_backtrace(show_bt);
+#endif
+
     if (!pa_utf8_valid(text))
         pa_log_level(level, __FILE__": invalid UTF-8 string following below:");
 
@@ -182,19 +282,22 @@ void pa_log_levelv_meta(
 
         switch (log_target) {
             case PA_LOG_STDERR: {
-                const char *prefix = "", *suffix = "";
+                const char *prefix = "", *suffix = "", *grey = "";
                 char *local_t;
 
 #ifndef OS_IS_WIN32
                 /* Yes indeed. Useless, but fun! */
                 if (isatty(STDERR_FILENO)) {
-                    if (level <= PA_LOG_ERROR) {
+                    if (level <= PA_LOG_ERROR)
                         prefix = "\x1B[1;31m";
-                        suffix = "\x1B[0m";
-                    } else if (level <= PA_LOG_WARN) {
+                    else if (level <= PA_LOG_WARN)
                         prefix = "\x1B[1m";
+
+                    if (bt)
+                        grey = "\x1B[2m";
+
+                    if (grey[0] || prefix[0])
                         suffix = "\x1B[0m";
-                    }
                 }
 #endif
 
@@ -202,9 +305,9 @@ void pa_log_levelv_meta(
                  * minimize the hit in RT threads */
                 local_t = pa_utf8_to_locale(t);
                 if (!local_t)
-                    fprintf(stderr, "%s%c: %s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, suffix);
+                    fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix);
                 else {
-                    fprintf(stderr, "%s%c: %s%s%s%s\n", timestamp, level_to_char[level], location, prefix, local_t, suffix);
+                    fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, local_t, grey, pa_strempty(bt), suffix);
                     pa_xfree(local_t);
                 }
 
@@ -219,9 +322,9 @@ void pa_log_levelv_meta(
 
                 local_t = pa_utf8_to_locale(t);
                 if (!local_t)
-                    syslog(level_to_syslog[level], "%s%s%s", timestamp, location, t);
+                    syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
                 else {
-                    syslog(level_to_syslog[level], "%s%s%s", timestamp, location, local_t);
+                    syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, local_t, pa_strempty(bt));
                     pa_xfree(local_t);
                 }
 
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index 633227f..3d66e90 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -25,6 +25,8 @@
 
 #include <stdarg.h>
 #include <stdlib.h>
+
+#include <pulsecore/macro.h>
 #include <pulse/gccmacro.h>
 
 /* A simple logging subsystem */
@@ -54,8 +56,11 @@ typedef void (*pa_log_func_t)(pa_log_level_t t, const char*s);
 /* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */
 void pa_log_set_target(pa_log_target_t t, pa_log_func_t func);
 
-/* Minimal log level */
+/* Maximal log level */
 void pa_log_set_maximal_level(pa_log_level_t l);
+void pa_log_set_show_meta(pa_bool_t b);
+void pa_log_set_show_time(pa_bool_t b);
+void pa_log_set_show_backtrace(unsigned nlevels);
 
 void pa_log_level_meta(
         pa_log_level_t level,

commit 651a451c54011d6730f6cc834ed84d9aaf209ba6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 19:14:07 2008 +0200

    support changing logging parameters during runtime using the CLI

diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 1624165..b5ff98d 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -117,6 +117,10 @@ static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa
 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
+static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
+static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
+static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
+static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
 
 /* A method table for all available commands */
 
@@ -167,6 +171,10 @@ static const struct command commands[] = {
     { "suspend-sink",            pa_cli_command_suspend_sink,       "Suspend sink (args: index|name, bool)", 3},
     { "suspend-source",          pa_cli_command_suspend_source,     "Suspend source (args: index|name, bool)", 3},
     { "suspend",                 pa_cli_command_suspend,            "Suspend all sinks and all sources (args: bool)", 2},
+    { "set-log-level",           pa_cli_command_log_level,          "Change the log level (args: numeric level)", 2},
+    { "set-log-meta",            pa_cli_command_log_meta,           "Show source code location in log messages (args: bool)", 2},
+    { "set-log-time",            pa_cli_command_log_time,           "Show timestamps in log messages (args: bool)", 2},
+    { "set-log-backtrace",       pa_cli_command_log_backtrace,      "Show bakctrace in log messages (args: frames)", 2},
     { NULL, NULL, NULL, 0 }
 };
 
@@ -1203,6 +1211,102 @@ static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, p
     return 0;
 }
 
+static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
+    const char *m;
+    uint32_t level;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    if (!(m = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n");
+        return -1;
+    }
+
+    if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) {
+        pa_strbuf_puts(buf, "Failed to parse log level.\n");
+        return -1;
+    }
+
+    pa_log_set_maximal_level(level);
+
+    return 0;
+}
+
+static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
+    const char *m;
+    pa_bool_t b;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    if (!(m = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a boolean.\n");
+        return -1;
+    }
+
+    if ((b = pa_parse_boolean(m)) < 0) {
+        pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
+        return -1;
+    }
+
+    pa_log_set_show_meta(b);
+
+    return 0;
+}
+
+static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
+    const char *m;
+    pa_bool_t b;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    if (!(m = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a boolean.\n");
+        return -1;
+    }
+
+    if ((b = pa_parse_boolean(m)) < 0) {
+        pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
+        return -1;
+    }
+
+    pa_log_set_show_time(b);
+
+    return 0;
+}
+
+static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
+    const char *m;
+    uint32_t nframes;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    if (!(m = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a backtrace level.\n");
+        return -1;
+    }
+
+    if (pa_atou(m, &nframes) < 0 || nframes >= 1000) {
+        pa_strbuf_puts(buf, "Failed to parse backtrace level.\n");
+        return -1;
+    }
+
+    pa_log_set_show_backtrace(nframes);
+
+    return 0;
+}
+
 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
     pa_module *m;
     pa_sink *sink;

commit 496499c0df237dea16344cc7bc4d30efa0868317
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 19:15:41 2008 +0200

    Make log meta, time, backtrace configurable using config file

diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index 939b25d..d7ffc10 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -74,6 +74,9 @@ static const pa_daemon_conf default_conf = {
     .default_script_file = NULL,
     .log_target = PA_LOG_SYSLOG,
     .log_level = PA_LOG_NOTICE,
+    .log_backtrace = 0,
+    .log_meta = FALSE,
+    .log_time = FALSE,
     .resample_method = PA_RESAMPLER_AUTO,
     .disable_remixing = FALSE,
     .disable_lfe_remixing = TRUE,
@@ -399,6 +402,7 @@ static int parse_rtprio(const char *filename, unsigned line, const char *lvalue,
 int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
     int r = -1;
     FILE *f = NULL;
+    unsigned i = 0;
 
     pa_config_item table[] = {
         { "daemonize",                  pa_config_parse_bool,     NULL },
@@ -431,6 +435,9 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
         { "disable-lfe-remixing",       pa_config_parse_bool,     NULL },
         { "load-default-script-file",   pa_config_parse_bool,     NULL },
         { "shm-size-bytes",             pa_config_parse_size,     NULL },
+        { "log-meta",                   pa_config_parse_bool,     NULL },
+        { "log-time",                   pa_config_parse_bool,     NULL },
+        { "log-backtrace",              pa_config_parse_unsigned, NULL },
 #ifdef HAVE_SYS_RESOURCE_H
         { "rlimit-fsize",               parse_rlimit,             NULL },
         { "rlimit-data",                parse_rlimit,             NULL },
@@ -467,98 +474,75 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
         { NULL,                         NULL,                     NULL },
     };
 
-    table[0].data = &c->daemonize;
-    table[1].data = &c->fail;
-    table[2].data = &c->high_priority;
-    table[3].data = &c->realtime_scheduling;
-    table[4].data = &c->disallow_module_loading;
-    table[5].data = &c->disallow_exit;
-    table[6].data = &c->use_pid_file;
-    table[7].data = &c->system_instance;
-    table[8].data = &c->no_cpu_limit;
-    table[9].data = &c->disable_shm;
-    table[10].data = &c->exit_idle_time;
-    table[11].data = &c->module_idle_time;
-    table[12].data = &c->scache_idle_time;
-    table[13].data = c;
-    table[14].data = &c->dl_search_path;
-    table[15].data = &c->default_script_file;
-    table[16].data = c;
-    table[17].data = c;
-    table[18].data = c;
-    table[19].data = c;
-    table[20].data = c;
-    table[21].data = c;
-    table[22].data = c;
-    table[23].data = c;
-    table[24].data = c;
-    table[25].data = c;
-    table[26].data = &c->disable_remixing;
-    table[27].data = &c->disable_lfe_remixing;
-    table[28].data = &c->load_default_script_file;
-    table[29].data = &c->shm_size;
+    table[i++].data = &c->daemonize;
+    table[i++].data = &c->fail;
+    table[i++].data = &c->high_priority;
+    table[i++].data = &c->realtime_scheduling;
+    table[i++].data = &c->disallow_module_loading;
+    table[i++].data = &c->disallow_exit;
+    table[i++].data = &c->use_pid_file;
+    table[i++].data = &c->system_instance;
+    table[i++].data = &c->no_cpu_limit;
+    table[i++].data = &c->disable_shm;
+    table[i++].data = &c->exit_idle_time;
+    table[i++].data = &c->module_idle_time;
+    table[i++].data = &c->scache_idle_time;
+    table[i++].data = c;
+    table[i++].data = &c->dl_search_path;
+    table[i++].data = &c->default_script_file;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = c;
+    table[i++].data = &c->disable_remixing;
+    table[i++].data = &c->disable_lfe_remixing;
+    table[i++].data = &c->load_default_script_file;
+    table[i++].data = &c->shm_size;
+    table[i++].data = &c->log_meta;
+    table[i++].data = &c->log_time;
+    table[i++].data = &c->log_backtrace;
 #ifdef HAVE_SYS_RESOURCE_H
-    table[30].data = &c->rlimit_fsize;
-    table[31].data = &c->rlimit_data;
-    table[32].data = &c->rlimit_stack;
-    table[33].data = &c->rlimit_as;
-    table[34].data = &c->rlimit_core;
-    table[35].data = &c->rlimit_nofile;
-    table[36].data = &c->rlimit_as;
+    table[i++].data = &c->rlimit_fsize;
+    table[i++].data = &c->rlimit_data;
+    table[i++].data = &c->rlimit_stack;
+    table[i++].data = &c->rlimit_as;
+    table[i++].data = &c->rlimit_core;
+    table[i++].data = &c->rlimit_nofile;
+    table[i++].data = &c->rlimit_as;
 #ifdef RLIMIT_NPROC
-    table[37].data = &c->rlimit_nproc;
+    table[i++].data = &c->rlimit_nproc;
 #endif
-
 #ifdef RLIMIT_MEMLOCK
-#ifndef RLIMIT_NPROC
-#error "Houston, we have a numbering problem!"
-#endif
-    table[38].data = &c->rlimit_memlock;
+    table[i++].data = &c->rlimit_memlock;
 #endif
-
 #ifdef RLIMIT_LOCKS
-#ifndef RLIMIT_MEMLOCK
-#error "Houston, we have a numbering problem!"
-#endif
-    table[39].data = &c->rlimit_locks;
+    table[i++].data = &c->rlimit_locks;
 #endif
-
 #ifdef RLIMIT_SIGPENDING
-#ifndef RLIMIT_LOCKS
-#error "Houston, we have a numbering problem!"
-#endif
-    table[40].data = &c->rlimit_sigpending;
+    table[i++].data = &c->rlimit_sigpending;
 #endif
-
 #ifdef RLIMIT_MSGQUEUE
-#ifndef RLIMIT_SIGPENDING
-#error "Houston, we have a numbering problem!"
-#endif
-    table[41].data = &c->rlimit_msgqueue;
+    table[i++].data = &c->rlimit_msgqueue;
 #endif
-
 #ifdef RLIMIT_NICE
-#ifndef RLIMIT_MSGQUEUE
-#error "Houston, we have a numbering problem!"
-#endif
-    table[42].data = &c->rlimit_nice;
+    table[i++].data = &c->rlimit_nice;
 #endif
-
 #ifdef RLIMIT_RTPRIO
-#ifndef RLIMIT_NICE
-#error "Houston, we have a numbering problem!"
-#endif
-    table[43].data = &c->rlimit_rtprio;
+    table[i++].data = &c->rlimit_rtprio;
 #endif
-
 #ifdef RLIMIT_RTTIME
-#ifndef RLIMIT_RTTIME
-#error "Houston, we have a numbering problem!"
-#endif
-    table[44].data = &c->rlimit_rttime;
+    table[i++].data = &c->rlimit_rttime;
 #endif
 #endif
 
+    pa_assert(i == PA_ELEMENTSOF(table)-1);
+
     pa_xfree(c->config_file);
     c->config_file = NULL;
 
@@ -674,6 +658,9 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
     pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments);
     pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec);
     pa_strbuf_printf(s, "shm-size-bytes = %lu\n", (unsigned long) c->shm_size);
+    pa_strbuf_printf(s, "log-meta = %s\n", pa_yes_no(c->log_meta));
+    pa_strbuf_printf(s, "log-time = %s\n", pa_yes_no(c->log_time));
+    pa_strbuf_printf(s, "log-backtrace = %u\n", c->log_backtrace);
 #ifdef HAVE_SYS_RESOURCE_H
     pa_strbuf_printf(s, "rlimit-fsize = %li\n", c->rlimit_fsize.is_set ? (long int) c->rlimit_fsize.value : -1);
     pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index 9032926..04a4ebe 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -68,7 +68,9 @@ typedef struct pa_daemon_conf {
         disable_remixing,
         disable_lfe_remixing,
         load_default_script_file,
-        disallow_exit;
+        disallow_exit,
+        log_meta,
+        log_time;
     int exit_idle_time,
         module_idle_time,
         scache_idle_time,
@@ -79,6 +81,7 @@ typedef struct pa_daemon_conf {
     char *script_commands, *dl_search_path, *default_script_file;
     pa_log_target_t log_target;
     pa_log_level_t log_level;
+    unsigned log_backtrace;
     char *config_file;
 
 #ifdef HAVE_SYS_RESOURCE_H
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index c672d42..00a9593 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -45,6 +45,9 @@
 
 ; log-target = auto
 ; log-level = notice
+; log-meta = no
+; log-time = no
+; log-backtrace = 0
 
 ; resample-method = speex-float-3
 ; disable-remixing = no
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 2306483..f6d2512 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -428,6 +428,9 @@ int main(int argc, char *argv[]) {
 
     pa_log_set_maximal_level(conf->log_level);
     pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
+    pa_log_set_show_meta(conf->log_meta);
+    pa_log_set_show_backtrace(conf->log_backtrace);
+    pa_log_set_show_time(conf->log_time);
 
     pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root));
 

commit 16471915af1d95f4e4953df7c0f0c5e491d57d30
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 19:16:49 2008 +0200

    make log meta, time, backtrace configurable using command line

diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c
index fbd6dc3..0bfc8a9 100644
--- a/src/daemon/cmdline.c
+++ b/src/daemon/cmdline.c
@@ -55,6 +55,9 @@ enum {
     ARG_MODULE_IDLE_TIME,
     ARG_SCACHE_IDLE_TIME,
     ARG_LOG_TARGET,
+    ARG_LOG_META,
+    ARG_LOG_TIME,
+    ARG_LOG_BACKTRACE,
     ARG_LOAD,
     ARG_FILE,
     ARG_DL_SEARCH_PATH,
@@ -88,6 +91,9 @@ static const struct option long_options[] = {
     {"module-idle-time",            2, 0, ARG_MODULE_IDLE_TIME},
     {"scache-idle-time",            2, 0, ARG_SCACHE_IDLE_TIME},
     {"log-target",                  1, 0, ARG_LOG_TARGET},
+    {"log-meta",                    2, 0, ARG_LOG_META},
+    {"log-time",                    2, 0, ARG_LOG_TIME},
+    {"log-backtrace",               1, 0, ARG_LOG_BACKTRACE},
     {"load",                        1, 0, ARG_LOAD},
     {"file",                        1, 0, ARG_FILE},
     {"dl-search-path",              1, 0, ARG_DL_SEARCH_PATH},
@@ -148,6 +154,9 @@ void pa_cmdline_help(const char *argv0) {
            "      --log-level[=LEVEL]               Increase or set verbosity level\n"
            "  -v                                    Increase the verbosity level\n"
            "      --log-target={auto,syslog,stderr} Specify the log target\n"
+           "      --log-meta[=BOOL]                 Include code location in log messages\n"
+           "      --log-time[=BOOL]                 Include timestamps in log messages\n"
+           "      --log-backtrace=FRAMES            Include a backtrace in log messages\n"
            "  -p, --dl-search-path=PATH             Set the search path for dynamic shared\n"
            "                                        objects (plugins)\n"
            "      --resample-method=METHOD          Use the specified resampling method\n"
@@ -321,6 +330,24 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
                 }
                 break;
 
+            case ARG_LOG_TIME:
+                if ((conf->log_time = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
+                    pa_log(_("--log-time boolean argument"));
+                    goto fail;
+                }
+                break;
+
+            case ARG_LOG_META:
+                if ((conf->log_meta = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
+                    pa_log(_("--log-meta boolean argument"));
+                    goto fail;
+                }
+                break;
+
+            case ARG_LOG_BACKTRACE:
+                conf->log_backtrace = (unsigned) atoi(optarg);
+                break;
+
             case ARG_EXIT_IDLE_TIME:
                 conf->exit_idle_time = atoi(optarg);
                 break;

commit ef9f3f6ec4d73b9a1cdac648bcf3c4ad1a051393
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Oct 21 20:00:36 2008 +0200

    Try to catch certain driver errors
    
    ... by verifying return values of snd_pcm_avail_update() and
    snd_pcm_begin_mmap() for their sanenness.

diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index ffe7795..39cea49 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -30,6 +30,7 @@
 
 #include <pulse/sample.h>
 #include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
 
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
@@ -1109,3 +1110,62 @@ pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
 
     return item;
 }
+
+snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
+    snd_pcm_sframes_t n;
+    size_t k;
+
+    pa_assert(pcm);
+    pa_assert(hwbuf_size > 0);
+    pa_assert(ss);
+
+    /* Some ALSA driver expose weird bugs, let's inform the user about
+     * what is going on */
+
+    n = snd_pcm_avail_update(pcm);
+
+    if (n <= 0)
+        return n;
+
+    k = (size_t) n * pa_frame_size(ss);
+
+    if (k >= hwbuf_size * 3 ||
+        k >= pa_bytes_per_second(ss)*10)
+        pa_log("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms) "
+               "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.",
+               (unsigned long) k, (unsigned long) pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC);
+
+    return n;
+}
+
+int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss) {
+    int r;
+    snd_pcm_uframes_t before;
+    size_t k;
+
+    pa_assert(pcm);
+    pa_assert(areas);
+    pa_assert(offset);
+    pa_assert(frames);
+    pa_assert(hwbuf_size > 0);
+    pa_assert(ss);
+
+    before = *frames;
+
+    r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
+
+    if (r < 0)
+        return r;
+
+    k = (size_t) *frames * pa_frame_size(ss);
+
+    if (*frames > before ||
+        k >= hwbuf_size * 3 ||
+        k >= pa_bytes_per_second(ss)*10)
+
+        pa_log("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms) "
+               "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.",
+               (unsigned long) k, (unsigned long) pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC);
+
+    return r;
+}
diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h
index b66adc1..aaa01c7 100644
--- a/src/modules/alsa-util.h
+++ b/src/modules/alsa-util.h
@@ -92,4 +92,7 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
 
 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll);
 
+snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss);
+int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss);
+
 #endif
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index 4044de1..af83103 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -261,7 +261,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
         /* First we determine how many samples are missing to fill the
          * buffer up to 100% */
 
-        if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
+        if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
 
             if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
                 continue;
@@ -299,7 +299,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
 
 /*             pa_log_debug("%lu frames to write", (unsigned long) frames); */
 
-            if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) {
+            if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
 
                 if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0)
                     continue;
@@ -374,7 +374,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec) {
 
         snd_pcm_hwsync(u->pcm_handle);
 
-        if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
+        if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
 
             if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
                 continue;
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
index a743776..dd6ca97 100644
--- a/src/modules/module-alsa-source.c
+++ b/src/modules/module-alsa-source.c
@@ -255,7 +255,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
 
         snd_pcm_hwsync(u->pcm_handle);
 
-        if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
+        if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) {
 
             if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
                 continue;
@@ -282,7 +282,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
 
 /*             pa_log_debug("%lu frames to read", (unsigned long) frames); */
 
-            if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) {
+            if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->source->sample_spec)) < 0)) {
 
                 if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0)
                     continue;
@@ -353,7 +353,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) {
 
         snd_pcm_hwsync(u->pcm_handle);
 
-        if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
+        if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) {
 
             if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
                 continue;

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list