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

Colin Guthrie gitmailer-noreply at 0pointer.de
Fri Apr 1 06:14:47 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  13d1928f3e0557d8809f67e1de77f07726267d23 (commit)

- Log -----------------------------------------------------------------
c083259 tests: add a connection stress test
35c93f7 bluetooth: Fix HSP volume handling.
ccbf7a3 bluetooth: restore original sco_{sink, src}->set_volume when unloading
2386471 bluetooth: fix set_volume_cb on sco over pcm
209b7b7 bluetooth: use sco_sink/source to start with right state
13849f1 bluetooth: Drop all "#ifdef NOKIA" directives.
-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am                                 |   11 +-
 src/modules/bluetooth/module-bluetooth-device.c |  192 ++++++++++++++---------
 src/tests/{sync-playback.c => connect-stress.c} |  164 ++++++++++----------
 3 files changed, 213 insertions(+), 154 deletions(-)
 copy src/tests/{sync-playback.c => connect-stress.c} (59%)

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

commit 13849f153cf44ff9b1e2157b3b6bc8b8c990a70f
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Mon Mar 28 15:35:14 2011 +0300

    bluetooth: Drop all "#ifdef NOKIA" directives.
    
    The #ifdefs only added clutter. I don't see any reason to not compile the
    SCO over PCM support in all the time.

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index b132d42..6f92764 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -76,14 +76,9 @@ PA_MODULE_USAGE(
         "rate=<sample rate> "
         "channels=<number of channels> "
         "path=<device object path> "
-        "auto_connect=<automatically connect?>");
-
-/*
-#ifdef NOKIA
+        "auto_connect=<automatically connect?> "
         "sco_sink=<SCO over PCM sink name> "
-        "sco_source=<SCO over PCM source name>"
-#endif
-*/
+        "sco_source=<SCO over PCM source name>");
 
 /* TODO: not close fd when entering suspend mode in a2dp */
 
@@ -101,10 +96,8 @@ static const char* const valid_modargs[] = {
     "channels",
     "path",
     "auto_connect",
-#ifdef NOKIA
     "sco_sink",
     "sco_source",
-#endif
     NULL
 };
 
@@ -124,10 +117,8 @@ struct a2dp_info {
 
 struct hsp_info {
     pcm_capabilities_t pcm_capabilities;
-#ifdef NOKIA
     pa_sink *sco_sink;
     pa_source *sco_source;
-#endif
     pa_hook_slot *sink_state_changed_slot;
     pa_hook_slot *source_state_changed_slot;
 };
@@ -189,9 +180,7 @@ struct userdata {
 
 #define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
 
-#ifdef NOKIA
 #define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && u->hsp.sco_source))
-#endif
 
 static int init_bt(struct userdata *u);
 static int init_profile(struct userdata *u);
@@ -1882,8 +1871,6 @@ static char *get_name(const char *type, pa_modargs *ma, const char *device_id, p
     return pa_sprintf_malloc("bluez_%s.%s", type, n);
 }
 
-#ifdef NOKIA
-
 static void sco_over_pcm_state_update(struct userdata *u) {
     pa_assert(u);
     pa_assert(USE_SCO_OVER_PCM(u));
@@ -1946,12 +1933,8 @@ static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct
     return PA_HOOK_OK;
 }
 
-#endif
-
 /* Run from main thread */
 static int add_sink(struct userdata *u) {
-
-#ifdef NOKIA
     if (USE_SCO_OVER_PCM(u)) {
         pa_proplist *p;
 
@@ -1964,10 +1947,7 @@ static int add_sink(struct userdata *u) {
         if (!u->hsp.sink_state_changed_slot)
             u->hsp.sink_state_changed_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_state_changed_cb, u);
 
-    } else
-#endif
-
-    {
+    } else {
         pa_sink_new_data data;
         pa_bool_t b;
 
@@ -2015,8 +1995,6 @@ static int add_sink(struct userdata *u) {
 
 /* Run from main thread */
 static int add_source(struct userdata *u) {
-
-#ifdef NOKIA
     if (USE_SCO_OVER_PCM(u)) {
         u->source = u->hsp.sco_source;
         pa_proplist_sets(u->source->proplist, "bluetooth.protocol", "hsp");
@@ -2024,10 +2002,7 @@ static int add_source(struct userdata *u) {
         if (!u->hsp.source_state_changed_slot)
             u->hsp.source_state_changed_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) source_state_changed_cb, u);
 
-    } else
-#endif
-
-    {
+    } else {
         pa_source_new_data data;
         pa_bool_t b;
 
@@ -2288,12 +2263,10 @@ static int setup_bt(struct userdata *u) {
 
     pa_log_debug("Connection to the device configured");
 
-#ifdef NOKIA
     if (USE_SCO_OVER_PCM(u)) {
         pa_log_debug("Configured to use SCO over PCM");
         return 0;
     }
-#endif
 
     pa_log_debug("Got the stream socket");
 
@@ -2382,7 +2355,6 @@ static int start_thread(struct userdata *u) {
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll);
 
-#ifdef NOKIA
     if (USE_SCO_OVER_PCM(u)) {
         if (u->transport) {
             if (bt_transport_acquire(u, TRUE) < 0)
@@ -2395,7 +2367,6 @@ static int start_thread(struct userdata *u) {
         /* FIXME: monitor stream_fd error */
         return 0;
     }
-#endif
 
     if (!(u->thread = pa_thread_new("bluetooth", thread_func, u))) {
         pa_log_error("Failed to create IO thread");
@@ -2462,17 +2433,15 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
 
     if (u->sink) {
         inputs = pa_sink_move_all_start(u->sink, NULL);
-#ifdef NOKIA
+
         if (!USE_SCO_OVER_PCM(u))
-#endif
             pa_sink_unlink(u->sink);
     }
 
     if (u->source) {
         outputs = pa_source_move_all_start(u->source, NULL);
-#ifdef NOKIA
+
         if (!USE_SCO_OVER_PCM(u))
-#endif
             pa_source_unlink(u->source);
     }
 
@@ -2729,7 +2698,6 @@ int pa__init(pa_module* m) {
     u->sample_spec = m->core->default_sample_spec;
     u->modargs = ma;
 
-#ifdef NOKIA
     if (pa_modargs_get_value(ma, "sco_sink", NULL) &&
         !(u->hsp.sco_sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sco_sink", NULL), PA_NAMEREG_SINK))) {
         pa_log("SCO sink not found");
@@ -2741,7 +2709,6 @@ int pa__init(pa_module* m) {
         pa_log("SCO source not found");
         goto fail;
     }
-#endif
 
     if (pa_modargs_get_value_u32(ma, "rate", &u->sample_spec.rate) < 0 ||
         u->sample_spec.rate <= 0 || u->sample_spec.rate > PA_RATE_MAX) {
@@ -2849,18 +2816,10 @@ void pa__done(pa_module *m) {
     if (!(u = m->userdata))
         return;
 
-    if (u->sink
-#ifdef NOKIA
-        && !USE_SCO_OVER_PCM(u)
-#endif
-    )
+    if (u->sink && !USE_SCO_OVER_PCM(u))
         pa_sink_unlink(u->sink);
 
-    if (u->source
-#ifdef NOKIA
-        && !USE_SCO_OVER_PCM(u)
-#endif
-    )
+    if (u->source && !USE_SCO_OVER_PCM(u))
         pa_source_unlink(u->source);
 
     stop_thread(u);

commit 209b7b781d8d1a5ac5f1442bd647098c2a3c4e18
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Mon Mar 28 15:35:15 2011 +0300

    bluetooth: use sco_sink/source to start with right state
    
    Note from Tanu Kaskinen: I resolved some conflicts with newer upstream code, so
    if this patch is broken, blame me..

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 6f92764..2cf5273 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1871,39 +1871,46 @@ static char *get_name(const char *type, pa_modargs *ma, const char *device_id, p
     return pa_sprintf_malloc("bluez_%s.%s", type, n);
 }
 
-static void sco_over_pcm_state_update(struct userdata *u) {
+static int sco_over_pcm_state_update(struct userdata *u) {
     pa_assert(u);
     pa_assert(USE_SCO_OVER_PCM(u));
 
     if (PA_SINK_IS_OPENED(pa_sink_get_state(u->hsp.sco_sink)) ||
         PA_SOURCE_IS_OPENED(pa_source_get_state(u->hsp.sco_source))) {
 
-        if (u->service_fd >= 0)
-            return;
+        if (u->service_fd >= 0 && u->stream_fd >= 0)
+            return 0;
 
         init_bt(u);
 
         pa_log_debug("Resuming SCO over PCM");
-        if (init_profile(u) < 0)
+        if (init_profile(u) < 0) {
             pa_log("Can't resume SCO over PCM");
+            return -1;
+        }
 
         if (u->transport)
-            bt_transport_acquire(u, TRUE);
+            return bt_transport_acquire(u, TRUE);
         else
-            start_stream_fd(u);
+            return start_stream_fd(u);
+
     } else {
+        if (u->service_fd < 0 && u->stream_fd < 0)
+            return 0;
 
-        if (u->service_fd < 0)
-            return;
+        pa_log_debug("Closing SCO over PCM");
 
         if (u->transport)
             bt_transport_release(u);
-        else
+        else if (u->stream_fd >= 0)
             stop_stream_fd(u);
 
-        pa_log_debug("Closing SCO over PCM");
-        pa_close(u->service_fd);
-        u->service_fd = -1;
+        if (u->service_fd >= 0) {
+            pa_close(u->service_fd);
+            u->service_fd = -1;
+        }
+
+        return 0;
     }
 }
 
@@ -2356,11 +2363,11 @@ static int start_thread(struct userdata *u) {
     pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll);
 
     if (USE_SCO_OVER_PCM(u)) {
-        if (u->transport) {
-            if (bt_transport_acquire(u, TRUE) < 0)
-                return -1;
-        } else if (start_stream_fd(u) < 0)
+        if (sco_over_pcm_state_update(u) < 0) {
+            u->sink = NULL;
+            u->source = NULL;
             return -1;
+        }
 
         pa_sink_ref(u->sink);
         pa_source_ref(u->source);

commit 2386471e10c25c01e7b4b7885c41ce72de6e84ca
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Mon Mar 28 15:35:16 2011 +0300

    bluetooth: fix set_volume_cb on sco over pcm
    
    The current implementation is totally bogus, it cast the over_sink
    userdata to the bluetooth-device userdata... It was failing nicely
    because the previous code had a gentle safe-guard in u->profile ==
    PROFILE_HSP, and u->profile was just random.
    
    There is no easy way to associate additional data to a sink or
    source. Two solutions seems possible: looking up loaded modules and
    check which one was handling the sink/source, or using pa_shared. I
    went for the second solution.

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 2cf5273..2f98c16 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -39,6 +39,7 @@
 #include <pulsecore/core-rtclock.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/shared.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
@@ -1796,14 +1797,21 @@ fail:
 
 /* Run from main thread */
 static void sink_set_volume_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
     DBusMessage *m;
     dbus_uint16_t gain;
+    struct userdata *u;
+    char *k;
 
-    pa_assert(u);
+    pa_assert(s);
+    pa_assert(s->core);
 
-    if (u->profile != PROFILE_HSP)
-        return;
+    k = pa_sprintf_malloc("bluetooth-device@%p", (void*) s);
+    u = pa_shared_get(s->core, k);
+    pa_xfree(k);
+
+    pa_assert(u);
+    pa_assert(u->sink == s);
+    pa_assert(u->profile == PROFILE_HSP);
 
     gain = (pa_cvolume_max(&s->real_volume) * 15) / PA_VOLUME_NORM;
 
@@ -1820,14 +1828,21 @@ static void sink_set_volume_cb(pa_sink *s) {
 
 /* Run from main thread */
 static void source_set_volume_cb(pa_source *s) {
-    struct userdata *u = s->userdata;
     DBusMessage *m;
     dbus_uint16_t gain;
+    struct userdata *u;
+    char *k;
 
-    pa_assert(u);
+    pa_assert(s);
+    pa_assert(s->core);
 
-    if (u->profile != PROFILE_HSP)
-        return;
+    k = pa_sprintf_malloc("bluetooth-device@%p", (void*) s);
+    u = pa_shared_get(s->core, k);
+    pa_xfree(k);
+
+    pa_assert(u);
+    pa_assert(u->source == s);
+    pa_assert(u->profile == PROFILE_HSP);
 
     gain = (pa_cvolume_max(&s->volume) * 15) / PA_VOLUME_NORM;
 
@@ -2685,7 +2700,7 @@ int pa__init(pa_module* m) {
     struct userdata *u;
     const char *address, *path;
     DBusError err;
-    char *mike, *speaker, *transport;
+    char *mike, *speaker, *transport, *k;
     const pa_bluetooth_device *device;
 
     pa_assert(m);
@@ -2786,6 +2801,18 @@ int pa__init(pa_module* m) {
     /* Connect to the BT service */
     init_bt(u);
 
+    if (u->hsp.sco_sink) {
+        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
+        pa_shared_set(u->core, k, u);
+        pa_xfree(k);
+    }
+
+    if (u->hsp.sco_source) {
+        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
+        pa_shared_set(u->core, k, u);
+        pa_xfree(k);
+    }
+
     if (u->profile != PROFILE_OFF)
         if (init_profile(u) < 0)
             goto fail;
@@ -2818,6 +2845,8 @@ int pa__get_n_used(pa_module *m) {
 
 void pa__done(pa_module *m) {
     struct userdata *u;
+    char *k;
+
     pa_assert(m);
 
     if (!(u = m->userdata))
@@ -2858,6 +2887,18 @@ void pa__done(pa_module *m) {
 
     shutdown_bt(u);
 
+    if (u->hsp.sco_sink) {
+        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
+        pa_shared_remove(u->core, k);
+        pa_xfree(k);
+    }
+
+    if (u->hsp.sco_source) {
+        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
+        pa_shared_remove(u->core, k);
+        pa_xfree(k);
+    }
+
     if (u->a2dp.buffer)
         pa_xfree(u->a2dp.buffer);
 

commit ccbf7a3006abfda81cb891a68625a9304689b352
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Mon Mar 28 15:35:17 2011 +0300

    bluetooth: restore original sco_{sink, src}->set_volume when unloading

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 2f98c16..b0e0a7b 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -119,7 +119,9 @@ struct a2dp_info {
 struct hsp_info {
     pcm_capabilities_t pcm_capabilities;
     pa_sink *sco_sink;
+    void (*sco_sink_set_volume)(pa_sink *s);
     pa_source *sco_source;
+    void (*sco_source_set_volume)(pa_source *s);
     pa_hook_slot *sink_state_changed_slot;
     pa_hook_slot *source_state_changed_slot;
 };
@@ -2802,12 +2804,14 @@ int pa__init(pa_module* m) {
     init_bt(u);
 
     if (u->hsp.sco_sink) {
+        u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume;
         k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
         pa_shared_set(u->core, k, u);
         pa_xfree(k);
     }
 
     if (u->hsp.sco_source) {
+        u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume;
         k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
         pa_shared_set(u->core, k, u);
         pa_xfree(k);
@@ -2888,12 +2892,14 @@ void pa__done(pa_module *m) {
     shutdown_bt(u);
 
     if (u->hsp.sco_sink) {
+        u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume;
         k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
         pa_shared_remove(u->core, k);
         pa_xfree(k);
     }
 
     if (u->hsp.sco_source) {
+        u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume;
         k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
         pa_shared_remove(u->core, k);
         pa_xfree(k);

commit 35c93f711df803cee81a4753700f1fe2ec73bf21
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Mar 31 15:00:52 2011 +0300

    bluetooth: Fix HSP volume handling.
    
    Previously the userdata for the volume callbacks was saved to
    pa_core.shared only once when loading module-bluetooth-device, and only when
    the SCO over PCM feature was used. That breaks volume handling in cases where
    the HSP profile is used without the SCO over PCM setup. Now the userdata is
    set always when a sink or source is created, and removed when a sink or source
    is removed.

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index b0e0a7b..e4a2cef 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1959,6 +1959,8 @@ static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct
 
 /* Run from main thread */
 static int add_sink(struct userdata *u) {
+    char *k;
+
     if (USE_SCO_OVER_PCM(u)) {
         pa_proplist *p;
 
@@ -2012,6 +2014,10 @@ static int add_sink(struct userdata *u) {
     if (u->profile == PROFILE_HSP) {
         u->sink->set_volume = sink_set_volume_cb;
         u->sink->n_volume_steps = 16;
+
+        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
+        pa_shared_set(u->core, k, u);
+        pa_xfree(k);
     }
 
     return 0;
@@ -2019,6 +2025,8 @@ static int add_sink(struct userdata *u) {
 
 /* Run from main thread */
 static int add_source(struct userdata *u) {
+    char *k;
+
     if (USE_SCO_OVER_PCM(u)) {
         u->source = u->hsp.sco_source;
         pa_proplist_sets(u->source->proplist, "bluetooth.protocol", "hsp");
@@ -2077,6 +2085,10 @@ static int add_source(struct userdata *u) {
     if (u->profile == PROFILE_HSP) {
         u->source->set_volume = source_set_volume_cb;
         u->source->n_volume_steps = 16;
+
+        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
+        pa_shared_set(u->core, k, u);
+        pa_xfree(k);
     }
 
     return 0;
@@ -2323,6 +2335,8 @@ static int init_profile(struct userdata *u) {
 
 /* Run from main thread */
 static void stop_thread(struct userdata *u) {
+    char *k;
+
     pa_assert(u);
 
     if (u->thread) {
@@ -2347,11 +2361,23 @@ static void stop_thread(struct userdata *u) {
     }
 
     if (u->sink) {
+        if (u->profile == PROFILE_HSP) {
+            k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
+            pa_shared_remove(u->core, k);
+            pa_xfree(k);
+        }
+
         pa_sink_unref(u->sink);
         u->sink = NULL;
     }
 
     if (u->source) {
+        if (u->profile == PROFILE_HSP) {
+            k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
+            pa_shared_remove(u->core, k);
+            pa_xfree(k);
+        }
+
         pa_source_unref(u->source);
         u->source = NULL;
     }
@@ -2381,8 +2407,20 @@ static int start_thread(struct userdata *u) {
 
     if (USE_SCO_OVER_PCM(u)) {
         if (sco_over_pcm_state_update(u) < 0) {
-            u->sink = NULL;
-            u->source = NULL;
+            char *k;
+
+            if (u->sink) {
+                k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
+                pa_shared_remove(u->core, k);
+                pa_xfree(k);
+                u->sink = NULL;
+            }
+            if (u->source) {
+                k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
+                pa_shared_remove(u->core, k);
+                pa_xfree(k);
+                u->source = NULL;
+            }
             return -1;
         }
 
@@ -2419,6 +2457,22 @@ static int start_thread(struct userdata *u) {
     return 0;
 }
 
+static void save_sco_volume_callbacks(struct userdata *u) {
+    pa_assert(u);
+    pa_assert(USE_SCO_OVER_PCM(u));
+
+    u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume;
+    u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume;
+}
+
+static void restore_sco_volume_callbacks(struct userdata *u) {
+    pa_assert(u);
+    pa_assert(USE_SCO_OVER_PCM(u));
+
+    u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume;
+    u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume;
+}
+
 /* Run from main thread */
 static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
     struct userdata *u;
@@ -2472,9 +2526,15 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
     stop_thread(u);
     shutdown_bt(u);
 
+    if (USE_SCO_OVER_PCM(u))
+        restore_sco_volume_callbacks(u);
+
     u->profile = *d;
     u->sample_spec = u->requested_sample_spec;
 
+    if (USE_SCO_OVER_PCM(u))
+        save_sco_volume_callbacks(u);
+
     init_bt(u);
 
     if (u->profile != PROFILE_OFF)
@@ -2639,6 +2699,9 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
     d = PA_CARD_PROFILE_DATA(u->card->active_profile);
     u->profile = *d;
 
+    if (USE_SCO_OVER_PCM(u))
+        save_sco_volume_callbacks(u);
+
     return 0;
 }
 
@@ -2702,7 +2765,7 @@ int pa__init(pa_module* m) {
     struct userdata *u;
     const char *address, *path;
     DBusError err;
-    char *mike, *speaker, *transport, *k;
+    char *mike, *speaker, *transport;
     const pa_bluetooth_device *device;
 
     pa_assert(m);
@@ -2803,20 +2866,6 @@ int pa__init(pa_module* m) {
     /* Connect to the BT service */
     init_bt(u);
 
-    if (u->hsp.sco_sink) {
-        u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume;
-        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
-        pa_shared_set(u->core, k, u);
-        pa_xfree(k);
-    }
-
-    if (u->hsp.sco_source) {
-        u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume;
-        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
-        pa_shared_set(u->core, k, u);
-        pa_xfree(k);
-    }
-
     if (u->profile != PROFILE_OFF)
         if (init_profile(u) < 0)
             goto fail;
@@ -2849,7 +2898,6 @@ int pa__get_n_used(pa_module *m) {
 
 void pa__done(pa_module *m) {
     struct userdata *u;
-    char *k;
 
     pa_assert(m);
 
@@ -2864,6 +2912,9 @@ void pa__done(pa_module *m) {
 
     stop_thread(u);
 
+    if (USE_SCO_OVER_PCM(u))
+        restore_sco_volume_callbacks(u);
+
     if (u->connection) {
 
         if (u->path) {
@@ -2891,20 +2942,6 @@ void pa__done(pa_module *m) {
 
     shutdown_bt(u);
 
-    if (u->hsp.sco_sink) {
-        u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume;
-        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
-        pa_shared_remove(u->core, k);
-        pa_xfree(k);
-    }
-
-    if (u->hsp.sco_source) {
-        u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume;
-        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
-        pa_shared_remove(u->core, k);
-        pa_xfree(k);
-    }
-
     if (u->a2dp.buffer)
         pa_xfree(u->a2dp.buffer);
 

commit c083259464e1e140165795a8bf6e3c0cfcbc64fe
Author: Daniel Mack <zonque at gmail.com>
Date:   Thu Mar 31 14:37:40 2011 +0200

    tests: add a connection stress test
    
    This test is based on a threaded main loop and was written to hunt an
    evil race condition.

diff --git a/src/Makefile.am b/src/Makefile.am
index 3bec5e8..bdedded 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -240,7 +240,7 @@ pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 #         Test programs           #
 ###################################
 
-# missing: mcalign-test flist-test pacat-simple parec-simple sync-playback rtstutter stripnul interpol-test thread-test
+# missing: mcalign-test flist-test pacat-simple parec-simple sync-playback rtstutter stripnul interpol-test thread-test connect-stress
 
 TESTS = \
 		mainloop-test \
@@ -303,7 +303,8 @@ TESTS_BINARIES = \
 		rtstutter \
 		stripnul \
 		lock-autospawn-test \
-		prioq-test
+		prioq-test \
+		connect-stress
 
 if !OS_IS_WIN32
 TESTS += \
@@ -563,6 +564,12 @@ usergroup_test_LDADD = $(AM_LDADD) libpulsecore- at PA_MAJORMINOR@.la libpulse.la l
 usergroup_test_CFLAGS = $(AM_CFLAGS)
 usergroup_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
+connect_stress_SOURCES = tests/connect-stress.c
+connect_stress_LDADD = $(AM_LDADD) libpulse.la libpulsecommon- at PA_MAJORMINOR@.la
+connect_stress_CFLAGS = $(AM_CFLAGS)
+connect_stress_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+
 ###################################
 #         Common library          #
 ###################################
diff --git a/src/tests/connect-stress.c b/src/tests/connect-stress.c
new file mode 100644
index 0000000..f427195
--- /dev/null
+++ b/src/tests/connect-stress.c
@@ -0,0 +1,198 @@
+/***
+  This file is part of PulseAudio.
+
+  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.1 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 <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/mainloop.h>
+
+#define NSTREAMS 16
+#define NTESTS 1000
+#define SAMPLE_HZ 44100
+
+static pa_context *context = NULL;
+static pa_stream *streams[NSTREAMS];
+static pa_threaded_mainloop *mainloop = NULL;
+
+static const pa_sample_spec sample_spec = {
+    .format = PA_SAMPLE_FLOAT32,
+    .rate = SAMPLE_HZ,
+    .channels = 1
+};
+
+static void context_state_callback(pa_context *c, void *userdata);
+
+static void connect(const char *name, int *try) {
+    int ret;
+    pa_mainloop_api *api;
+
+    /* Set up a new main loop */
+    mainloop = pa_threaded_mainloop_new();
+    assert(mainloop);
+
+    api = pa_threaded_mainloop_get_api(mainloop);
+    context = pa_context_new(api, name);
+    assert(context);
+
+    pa_context_set_state_callback(context, context_state_callback, try);
+
+    /* Connect the context */
+    if (pa_context_connect(context, NULL, 0, NULL) < 0) {
+        fprintf(stderr, "pa_context_connect() failed.\n");
+        abort();
+    }
+
+    ret = pa_threaded_mainloop_start(mainloop);
+    assert(ret == 0);
+}
+
+static void disconnect(void) {
+    int i;
+
+    assert(mainloop);
+    assert(context);
+
+    pa_threaded_mainloop_lock(mainloop);
+
+    for (i = 0; i < NSTREAMS; i++)
+        if (streams[i]) {
+            pa_stream_disconnect(streams[i]);
+            pa_stream_unref(streams[i]);
+            streams[i] = NULL;
+        }
+
+    pa_context_disconnect(context);
+    context = NULL;
+
+    pa_threaded_mainloop_unlock(mainloop);
+    pa_threaded_mainloop_stop(mainloop);
+    pa_threaded_mainloop_free(mainloop);
+    mainloop = NULL;
+}
+
+static const pa_buffer_attr buffer_attr = {
+    .maxlength = SAMPLE_HZ * sizeof(float) * NSTREAMS,
+    .tlength = (uint32_t) -1,
+    .prebuf = 0, /* Setting prebuf to 0 guarantees us the the streams will run synchronously, no matter what */
+    .minreq = (uint32_t) -1,
+    .fragsize = 0
+};
+
+static void stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
+    char silence[8192];
+
+    memset(silence, 0, sizeof(silence));
+
+    while (nbytes) {
+        int n = MIN(sizeof(silence), nbytes);
+        pa_stream_write(stream, silence, n, NULL, 0, 0);
+        nbytes -= n;
+    }
+}
+
+static void stream_state_callback(pa_stream *s, void *userdata) {
+    assert(s);
+
+    switch (pa_stream_get_state(s)) {
+        case PA_STREAM_UNCONNECTED:
+        case PA_STREAM_CREATING:
+        case PA_STREAM_TERMINATED:
+        case PA_STREAM_READY:
+            break;
+
+        default:
+        case PA_STREAM_FAILED:
+            fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
+            abort();
+    }
+}
+
+static void context_state_callback(pa_context *c, void *userdata) {
+    int *try;
+
+    assert(c);
+    assert(userdata);
+
+    try = (int*)userdata;
+
+    switch (pa_context_get_state(c)) {
+        case PA_CONTEXT_CONNECTING:
+        case PA_CONTEXT_AUTHORIZING:
+        case PA_CONTEXT_SETTING_NAME:
+            break;
+
+        case PA_CONTEXT_READY: {
+
+            int i;
+            fprintf(stderr, "Connection (%d of %d) established.\n", (*try)+1, NTESTS);
+
+            for (i = 0; i < NSTREAMS; i++) {
+                char name[64];
+
+                snprintf(name, sizeof(name), "stream #%i", i);
+                streams[i] = pa_stream_new(c, name, &sample_spec, NULL);
+                assert(streams[i]);
+                pa_stream_set_state_callback(streams[i], stream_state_callback, NULL);
+                pa_stream_set_write_callback(streams[i], stream_write_callback, NULL);
+                pa_stream_connect_playback(streams[i], NULL, &buffer_attr, 0, NULL, NULL);
+            }
+
+            break;
+        }
+
+        case PA_CONTEXT_TERMINATED:
+            fprintf(stderr, "Connection terminated.\n");
+            pa_context_unref(context);
+            context = NULL;
+            break;
+
+        case PA_CONTEXT_FAILED:
+        default:
+            fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c)));
+            abort();
+    }
+}
+
+int main(int argc, char *argv[]) {
+    int i;
+
+    for (i = 0; i < NSTREAMS; i++)
+        streams[i] = NULL;
+
+    for (i = 0; i < NTESTS; i++) {
+        connect(argv[0], &i);
+        usleep(random() % 500000);
+        disconnect();
+        usleep(random() % 500000);
+    }
+
+    fprintf(stderr, "Done.\n");
+
+    return 0;
+}

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list