[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.15-test7-68-gee6657a

Lennart Poettering gitmailer-noreply at 0pointer.de
Thu Apr 9 16:31:51 PDT 2009


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  6c04a1c9039606182314f5f263445c89f3f28a9f (commit)

- Log -----------------------------------------------------------------
ee6657a bluetooth: when starting up HSP stream, send 2 packets first, only afterwards enter one-read-one-write logic
d77b28c bluetooth: rework timing logic, properly implement latency callbacks
e9a4dec bluetooth: be a bit more verbose if we exit due to bad poll() revents flag
48cff5b bluetooth: rename sco to hsp also for the user
f7c229d core: add a seperate fixed_latency field for sinks/sources with fixed latency
9ae8ca2 core: memory leak, fix ref counting when moving streams
dcd4a73 dbus: memory leak, actually free dbus wrapper
d827ecd dbus: drop pa_ prefix from static symbol
f8ebe85 protocol-native: downgrade message if we receive pcm block for dead stream
5b87196 protocol-native: print underrun message only once for each underrun
3507d1e socket-server: memory leak, free machine id after use
669703d dbus: memory leak, free pending calls
9ba9883 dbus: memory leak, free server id after use
9ee6a41 bluetooth: memory leak, actually free discovery struct itself
f65b276 interpol-test: make it easier to test corking only optionally
-----------------------------------------------------------------------

Summary of changes:
 src/modules/bluetooth/bluetooth-util.c          |    2 +
 src/modules/bluetooth/module-bluetooth-device.c |  193 +++++++++++++++++------
 src/pulsecore/cli-text.c                        |   12 ++-
 src/pulsecore/dbus-shared.c                     |   12 +-
 src/pulsecore/dbus-util.c                       |   11 +-
 src/pulsecore/protocol-native.c                 |    5 +-
 src/pulsecore/sink-input.c                      |   33 +++-
 src/pulsecore/sink.c                            |   31 +++-
 src/pulsecore/sink.h                            |    2 +
 src/pulsecore/socket-server.c                   |    1 +
 src/pulsecore/source-output.c                   |   29 +++-
 src/pulsecore/source.c                          |   34 +++--
 src/pulsecore/source.h                          |    2 +
 src/tests/interpol-test.c                       |   15 ++-
 14 files changed, 284 insertions(+), 98 deletions(-)

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

commit f65b276db3881dce35a32b4478b1c44ade098830
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:10:59 2009 +0200

    interpol-test: make it easier to test corking only optionally

diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c
index c103a49..0c906d3 100644
--- a/src/tests/interpol-test.c
+++ b/src/tests/interpol-test.c
@@ -37,6 +37,7 @@
 #include <pulsecore/thread.h>
 
 #define INTERPOLATE
+//#define CORK
 
 static pa_context *context = NULL;
 static pa_stream *stream = NULL;
@@ -125,7 +126,9 @@ int main(int argc, char *argv[]) {
     int k, r;
     struct timeval start, last_info = { 0, 0 };
     pa_usec_t old_t = 0, old_rtc = 0;
+#ifdef CORK
     pa_bool_t corked = FALSE;
+#endif
 
     pa_log_set_level(PA_LOG_DEBUG);
 
@@ -150,7 +153,12 @@ int main(int argc, char *argv[]) {
     r = pa_threaded_mainloop_start(m);
     assert(r >= 0);
 
-    for (k = 0; k < 20000; k++) {
+/* #ifdef CORK */
+    for (k = 0; k < 20000; k++)
+/* #else */
+/*     for (k = 0; k < 2000; k++) */
+/* #endif */
+    {
         pa_bool_t success = FALSE, changed = FALSE;
         pa_usec_t t, rtc;
         struct timeval now, tv;
@@ -179,8 +187,9 @@ int main(int argc, char *argv[]) {
         pa_gettimeofday(&now);
 
         if (success) {
+#ifdef CORK
             pa_bool_t cork_now;
-
+#endif
             rtc = pa_timeval_diff(&now, &start);
             printf("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\n", k,
                    (unsigned long long) rtc,
@@ -195,6 +204,7 @@ int main(int argc, char *argv[]) {
             old_t = t;
             old_rtc = rtc;
 
+#ifdef CORK
             cork_now = (rtc / (2*PA_USEC_PER_SEC)) % 2 == 1;
 
             if (corked != cork_now) {
@@ -206,6 +216,7 @@ int main(int argc, char *argv[]) {
 
                 corked = cork_now;
             }
+#endif
         }
 
         /* Spin loop, ugly but normal usleep() is just too badly grained */

commit 9ee6a41491f2cfeccd9d60409598c903c657269c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:12:12 2009 +0200

    bluetooth: memory leak, actually free discovery struct itself

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 6e4344f..5c7681d 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -773,6 +773,8 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
 
     if (y->core)
         pa_shared_remove(y->core, "bluetooth-discovery");
+
+    pa_xfree(y);
 }
 
 void pa_bluetooth_discovery_sync(pa_bluetooth_discovery *y) {

commit 9ba9883693ebe817532468c0974c8d5dccb4e006
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:12:46 2009 +0200

    dbus: memory leak, free server id after use

diff --git a/src/pulsecore/dbus-util.c b/src/pulsecore/dbus-util.c
index b35e747..4e97046 100644
--- a/src/pulsecore/dbus-util.c
+++ b/src/pulsecore/dbus-util.c
@@ -247,6 +247,7 @@ static void wakeup_main(void *userdata) {
 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBusType type, DBusError *error) {
     DBusConnection *conn;
     pa_dbus_wrap_connection *pconn;
+    char *id;
 
     pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
 
@@ -267,9 +268,11 @@ pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBus
 
     pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
                  type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
-                 pa_strnull(dbus_connection_get_server_id(conn)),
+                 pa_strnull((id = dbus_connection_get_server_id(conn))),
                  pa_strnull(dbus_bus_get_unique_name(conn)));
 
+    dbus_free(id);
+
     return pconn;
 }
 

commit 669703daec2b9231ab80eefe3bccfca29cc3decb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:14:46 2009 +0200

    dbus: memory leak, free pending calls

diff --git a/src/pulsecore/dbus-util.c b/src/pulsecore/dbus-util.c
index 4e97046..ece36de 100644
--- a/src/pulsecore/dbus-util.c
+++ b/src/pulsecore/dbus-util.c
@@ -380,8 +380,10 @@ pa_dbus_pending *pa_dbus_pending_new(
 void pa_dbus_pending_free(pa_dbus_pending *p) {
     pa_assert(p);
 
-    if (p->pending)
-        dbus_pending_call_cancel(p->pending); /* p->pending is freed by cancel() */
+    if (p->pending) {
+        dbus_pending_call_cancel(p->pending);
+        dbus_pending_call_unref(p->pending);
+    }
 
     if (p->message)
         dbus_message_unref(p->message);

commit 3507d1eb37173cb7f5e6a10d306f5fca57fe0b39
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:15:26 2009 +0200

    socket-server: memory leak, free machine id after use

diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c
index 8147b27..e660700 100644
--- a/src/pulsecore/socket-server.c
+++ b/src/pulsecore/socket-server.c
@@ -536,6 +536,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
                 return NULL;
 
             pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
+            pa_xfree(id);
             return c;
         }
 

commit 5b871966ab556134b0bb3ff93e8cd81e16e19f5d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:16:24 2009 +0200

    protocol-native: print underrun message only once for each underrun

diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index edcd598..9526de0 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1468,7 +1468,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
     if (pa_memblockq_is_readable(s->memblockq))
         s->is_underrun = FALSE;
     else {
-        pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq));
+        if (!s->is_underrun)
+            pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq));
 
         if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
             s->drain_request = FALSE;

commit f8ebe8571cbf52e9155b029ae085ea69e16178e1
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:16:59 2009 +0200

    protocol-native: downgrade message if we receive pcm block for dead stream

diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 9526de0..7c2183d 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -4245,7 +4245,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
     pa_native_connection_assert_ref(c);
 
     if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
-        pa_log("client sent block for invalid stream.");
+        pa_log_debug("Client sent block for invalid stream.");
         /* Ignoring */
         return;
     }

commit d827ecd28d87eedaa9eb50020504fe789c7800c8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:17:49 2009 +0200

    dbus: drop pa_ prefix from static symbol

diff --git a/src/pulsecore/dbus-shared.c b/src/pulsecore/dbus-shared.c
index b52c14c..f01ec2c 100644
--- a/src/pulsecore/dbus-shared.c
+++ b/src/pulsecore/dbus-shared.c
@@ -41,7 +41,7 @@ struct pa_dbus_connection {
     const char *property_name;
 };
 
-static pa_dbus_connection* pa_dbus_connection_new(pa_core *c, pa_dbus_wrap_connection *conn, const char *name) {
+static pa_dbus_connection* dbus_connection_new(pa_core *c, pa_dbus_wrap_connection *conn, const char *name) {
     pa_dbus_connection *pconn;
 
     pconn = pa_xnew(pa_dbus_connection, 1);
@@ -73,9 +73,7 @@ pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, DBusError *err
     if (!(conn = pa_dbus_wrap_connection_new(c->mainloop, type, error)))
         return NULL;
 
-    pconn = pa_dbus_connection_new(c, conn, prop_name[type]);
-
-    return pconn;
+    return dbus_connection_new(c, conn, prop_name[type]);
 }
 
 DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c){
@@ -106,6 +104,3 @@ pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c) {
 
     return c;
 }
-
-
-

commit dcd4a73df94b0e9083f72d79f81083961bd15746
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:18:04 2009 +0200

    dbus: memory leak, actually free dbus wrapper

diff --git a/src/pulsecore/dbus-shared.c b/src/pulsecore/dbus-shared.c
index f01ec2c..9d9445b 100644
--- a/src/pulsecore/dbus-shared.c
+++ b/src/pulsecore/dbus-shared.c
@@ -91,7 +91,8 @@ void pa_dbus_connection_unref(pa_dbus_connection *c) {
     if (PA_REFCNT_DEC(c) > 0)
         return;
 
-    /* already disconnected, just free */
+    pa_dbus_wrap_connection_free(c->connection);
+
     pa_shared_remove(c->core, c->property_name);
     pa_xfree(c);
 }

commit 9ae8ca2c3754abb9b6f6ce94c414c12d87419ac0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:21:16 2009 +0200

    core: memory leak, fix ref counting when moving streams

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 5855977..9ae98ed 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -335,8 +335,8 @@ int pa_sink_input_new(
             0,
             &i->sink->silence);
 
-    pa_assert_se(pa_idxset_put(core->sink_inputs, pa_sink_input_ref(i), &i->index) == 0);
-    pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0);
+    pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
+    pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
 
     if (i->client)
         pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0);
@@ -1155,6 +1155,8 @@ int pa_sink_input_start_move(pa_sink_input *i) {
     pa_sink_update_status(i->sink);
     i->sink = NULL;
 
+    pa_sink_input_unref(i);
+
     return 0;
 }
 
@@ -1202,7 +1204,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 
     i->sink = dest;
     i->save_sink = save;
-    pa_idxset_put(dest->inputs, i, NULL);
+    pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL);
 
     if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
         i->sink->n_corked++;
@@ -1267,11 +1269,19 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     if (!pa_sink_input_may_move_to(i, dest))
         return -PA_ERR_NOTSUPPORTED;
 
-    if ((r = pa_sink_input_start_move(i)) < 0)
+    pa_sink_input_ref(i);
+
+    if ((r = pa_sink_input_start_move(i)) < 0) {
+        pa_sink_input_unref(i);
         return r;
+    }
 
-    if ((r = pa_sink_input_finish_move(i, dest, save)) < 0)
+    if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) {
+        pa_sink_input_unref(i);
         return r;
+    }
+
+    pa_sink_input_unref(i);
 
     return 0;
 }
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 4cf7b6c..2771fec 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -515,8 +515,12 @@ pa_queue *pa_sink_move_all_start(pa_sink *s) {
     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
         n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
 
+        pa_sink_input_ref(i);
+
         if (pa_sink_input_start_move(i) >= 0)
-            pa_queue_push(q, pa_sink_input_ref(i));
+            pa_queue_push(q, i);
+        else
+            pa_sink_input_unref(i);
     }
 
     return q;
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 8918b43..489393a 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -705,6 +705,8 @@ int pa_source_output_start_move(pa_source_output *o) {
     pa_source_update_status(o->source);
     o->source = NULL;
 
+    pa_source_output_unref(o);
+
     return 0;
 }
 
@@ -752,7 +754,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
 
     o->source = dest;
     o->save_source = save;
-    pa_idxset_put(o->source->outputs, o, NULL);
+    pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL);
 
     if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
         o->source->n_corked++;
@@ -804,11 +806,19 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav
     if (!pa_source_output_may_move_to(o, dest))
         return -PA_ERR_NOTSUPPORTED;
 
-    if ((r = pa_source_output_start_move(o)) < 0)
+    pa_source_output_ref(o);
+
+    if ((r = pa_source_output_start_move(o)) < 0) {
+        pa_source_output_unref(o);
         return r;
+    }
 
-    if ((r = pa_source_output_finish_move(o, dest, save)) < 0)
+    if ((r = pa_source_output_finish_move(o, dest, save)) < 0) {
+        pa_source_output_unref(o);
         return r;
+    }
+
+    pa_source_output_unref(o);
 
     return 0;
 }
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index b85d6e1..693fab3 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -466,8 +466,12 @@ pa_queue *pa_source_move_all_start(pa_source *s) {
     for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
         n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
 
+        pa_source_output_ref(o);
+
         if (pa_source_output_start_move(o) >= 0)
-            pa_queue_push(q, pa_source_output_ref(o));
+            pa_queue_push(q, o);
+        else
+            pa_source_output_unref(o);
     }
 
     return q;

commit f7c229d8f9a4c67ff7ef0f3d351069a45ba19aff
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:26:04 2009 +0200

    core: add a seperate fixed_latency field for sinks/sources with fixed latency

diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 324f83c..b0911ef 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -288,7 +288,11 @@ char *pa_sink_list_to_string(pa_core *c) {
                     (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC,
                     (double) min_latency / PA_USEC_PER_MSEC,
                     (double) max_latency / PA_USEC_PER_MSEC);
-        }
+        } else
+            pa_strbuf_printf(
+                    s,
+                    "\tfixed latency: %0.2f ms\n",
+                    (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC);
 
         if (sink->card)
             pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name);
@@ -382,7 +386,11 @@ char *pa_source_list_to_string(pa_core *c) {
                     (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC,
                     (double) min_latency / PA_USEC_PER_MSEC,
                     (double) max_latency / PA_USEC_PER_MSEC);
-        }
+        } else
+            pa_strbuf_printf(
+                    s,
+                    "\tfixed latency: %0.2f ms\n",
+                    (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC);
 
         if (source->monitor_of)
             pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index);
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 9ae98ed..b1b9fb5 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -824,6 +824,9 @@ void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes  /* in the
 pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
     pa_sink_input_assert_ref(i);
 
+    if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
+        usec = i->sink->fixed_latency;
+
     if (usec != (pa_usec_t) -1)
         usec =  PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
 
@@ -835,8 +838,6 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa
 
 /* Called from main context */
 pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
-    pa_usec_t min_latency, max_latency;
-
     pa_sink_input_assert_ref(i);
 
     if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
@@ -848,10 +849,14 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
      * we have to touch the thread info data directly */
 
     if (i->sink) {
-        pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
+        if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
+            usec = i->sink->fixed_latency;
 
-        if (usec != (pa_usec_t) -1)
+        if (usec != (pa_usec_t) -1) {
+            pa_usec_t min_latency, max_latency;
+            pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
             usec =  PA_CLAMP(usec, min_latency, max_latency);
+        }
     }
 
     i->thread_info.requested_sink_latency = usec;
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 2771fec..93800d1 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -50,6 +50,7 @@
 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
 #define ABSOLUTE_MIN_LATENCY (500)
 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
+#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
 
 static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
 
@@ -208,6 +209,8 @@ pa_sink* pa_sink_new(
     s->muted = data->muted;
     s->refresh_volume = s->refresh_muted = FALSE;
 
+    s->fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
+
     reset_callbacks(s);
     s->userdata = NULL;
 
@@ -363,8 +366,13 @@ void pa_sink_put(pa_sink* s) {
     if (s->flags & PA_SINK_LATENCY)
         s->monitor_source->flags |= PA_SOURCE_LATENCY;
 
-    if (s->flags & PA_SINK_DYNAMIC_LATENCY)
+    if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
         s->monitor_source->flags |= PA_SOURCE_DYNAMIC_LATENCY;
+        s->fixed_latency = 0;
+    } else if (s->fixed_latency <= 0)
+        s->fixed_latency = DEFAULT_FIXED_LATENCY;
+
+    s->monitor_source->fixed_latency = s->fixed_latency;
 
     pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
 
@@ -1824,6 +1832,9 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
 
     pa_sink_assert_ref(s);
 
+    if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
+        return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
+
     if (s->thread_info.requested_latency_valid)
         return s->thread_info.requested_latency;
 
@@ -1839,13 +1850,8 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
         (result == (pa_usec_t) -1 || result > monitor_latency))
         result = monitor_latency;
 
-    if (result != (pa_usec_t) -1) {
-        if (result > s->thread_info.max_latency)
-            result = s->thread_info.max_latency;
-
-        if (result < s->thread_info.min_latency)
-            result = s->thread_info.min_latency;
-    }
+    if (result != (pa_usec_t) -1)
+        result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
 
     s->thread_info.requested_latency = result;
     s->thread_info.requested_latency_valid = TRUE;
@@ -1934,6 +1940,9 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) {
 
     pa_sink_assert_ref(s);
 
+    if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
+        return;
+
     s->thread_info.requested_latency_valid = FALSE;
 
     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 289054d..cb4697f 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -86,6 +86,8 @@ struct pa_sink {
 
     pa_memchunk silence;
 
+    pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */
+
     /* Called when the main loop requests a state change. Called from
      * main loop context. If returns -1 the state change will be
      * inhibited */
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 489393a..3ee2673 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -520,6 +520,9 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes  /* i
 pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) {
     pa_source_output_assert_ref(o);
 
+    if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
+        usec = o->source->fixed_latency;
+
     if (usec != (pa_usec_t) -1)
         usec = PA_CLAMP(usec, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
 
@@ -531,8 +534,6 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output
 
 /* Called from main context */
 pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
-    pa_usec_t min_latency, max_latency;
-
     pa_source_output_assert_ref(o);
 
     if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
@@ -544,10 +545,14 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
      * have to touch the thread info data directly */
 
     if (o->source) {
-        pa_source_get_latency_range(o->source, &min_latency, &max_latency);
+        if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
+            usec = o->source->fixed_latency;
 
-        if (usec != (pa_usec_t) -1)
+        if (usec != (pa_usec_t) -1) {
+            pa_usec_t min_latency, max_latency;
+            pa_source_get_latency_range(o->source, &min_latency, &max_latency);
             usec = PA_CLAMP(usec, min_latency, max_latency);
+        }
     }
 
     o->thread_info.requested_source_latency = usec;
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 693fab3..2190250 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -43,6 +43,7 @@
 
 #define ABSOLUTE_MIN_LATENCY (500)
 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
+#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
 
 static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
 
@@ -199,6 +200,8 @@ pa_source* pa_source_new(
     s->muted = data->muted;
     s->refresh_volume = s->refresh_muted = FALSE;
 
+    s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
+
     reset_callbacks(s);
     s->userdata = NULL;
 
@@ -303,8 +306,7 @@ void pa_source_put(pa_source *s) {
     /* The following fields must be initialized properly when calling _put() */
     pa_assert(s->asyncmsgq);
     pa_assert(s->rtpoll);
-    pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
-              s->thread_info.min_latency <= s->thread_info.max_latency);
+    pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
 
     if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
         s->flags |= PA_SOURCE_DECIBEL_VOLUME;
@@ -316,6 +318,11 @@ void pa_source_put(pa_source *s) {
     if (s->flags & PA_SOURCE_DECIBEL_VOLUME)
         s->n_volume_steps = PA_VOLUME_NORM+1;
 
+    if (s->flags & PA_SOURCE_DYNAMIC_LATENCY)
+        s->fixed_latency = 0;
+    else if (s->fixed_latency <= 0)
+        s->fixed_latency = DEFAULT_FIXED_LATENCY;
+
     pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
 
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
@@ -1096,6 +1103,9 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
 
     pa_source_assert_ref(s);
 
+    if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
+        return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
+
     if (s->thread_info.requested_latency_valid)
         return s->thread_info.requested_latency;
 
@@ -1105,13 +1115,8 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
             (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
             result = o->thread_info.requested_source_latency;
 
-    if (result != (pa_usec_t) -1) {
-        if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
-            result = s->thread_info.max_latency;
-
-        if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
-            result = s->thread_info.min_latency;
-    }
+    if (result != (pa_usec_t) -1)
+        result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
 
     s->thread_info.requested_latency = result;
     s->thread_info.requested_latency_valid = TRUE;
@@ -1121,7 +1126,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
 
 /* Called from main thread */
 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
-    pa_usec_t usec;
+    pa_usec_t usec = 0;
 
     pa_source_assert_ref(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
@@ -1169,6 +1174,9 @@ void pa_source_invalidate_requested_latency(pa_source *s) {
 
     pa_source_assert_ref(s);
 
+    if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
+        return;
+
     s->thread_info.requested_latency_valid = FALSE;
 
     if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 652783e..b502c22 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -87,6 +87,8 @@ struct pa_source {
 
     pa_memchunk silence;
 
+    pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */
+
     /* Called when the main loop requests a state change. Called from
      * main loop context. If returns -1 the state change will be
      * inhibited */

commit 48cff5b55d66857b3017d847a571acc409f058ca
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:28:21 2009 +0200

    bluetooth: rename sco to hsp also for the user

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 0e2b380..420f228 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1525,7 +1525,7 @@ 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", "sco");
+        pa_proplist_sets(u->source->proplist, "bluetooth.protocol", "hsp");
 
         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);
@@ -1541,7 +1541,7 @@ static int add_source(struct userdata *u) {
         data.driver = __FILE__;
         data.module = u->module;
         pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
-        pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "sco");
+        pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "hsp");
         data.card = u->card;
         data.name = get_name("source", u->modargs, u->address, &b);
         data.namereg_fail = b;
@@ -1871,7 +1871,7 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl
     }
 
     if (pa_bluetooth_uuid_has(device->uuids, HSP_HS_UUID) ||
-	pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID)) {
+        pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID)) {
         p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile));
         p->priority = 20;
         p->n_sinks = 1;

commit e9a4dec81ebc98f571d29d4f684855ceddd38d36
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:29:46 2009 +0200

    bluetooth: be a bit more verbose if we exit due to bad poll() revents flag

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 420f228..bf2e0e8 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1265,7 +1265,11 @@ static void thread_func(void *userdata) {
         pollfd = u->rtpoll_item ? pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL) : NULL;
 
         if (pollfd && (pollfd->revents & ~(POLLOUT|POLLIN))) {
-            pa_log_error("FD error.");
+            pa_log_info("FD error: %s%s%s%s",
+                        pollfd->revents & POLLERR ? "POLLERR " :"",
+                        pollfd->revents & POLLHUP ? "POLLHUP " :"",
+                        pollfd->revents & POLLPRI ? "POLLPRI " :"",
+                        pollfd->revents & POLLNVAL ? "POLLNVAL " :"");
             goto fail;
         }
     }

commit d77b28cb4bd088ab0f723cbdd65e3947b35b3b25
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:30:50 2009 +0200

    bluetooth: rework timing logic, properly implement latency callbacks

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index bf2e0e8..2812bc2 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -166,10 +166,14 @@ struct userdata {
 
     pa_modargs *modargs;
 
-    int stream_write_type, stream_read_type;
+    int stream_write_type;
     int service_write_type, service_read_type;
 };
 
+#define FIXED_LATENCY_PLAYBACK_A2DP (25*PA_USEC_PER_MSEC)
+#define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC)
+#define FIXED_LATENCY_RECORD_HSP (25*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
@@ -711,6 +715,7 @@ static int start_stream_fd(struct userdata *u) {
         uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
     } msg;
     struct pollfd *pollfd;
+    int one;
 
     pa_assert(u);
     pa_assert(u->rtpoll);
@@ -739,13 +744,29 @@ static int start_stream_fd(struct userdata *u) {
     pa_make_fd_nonblock(u->stream_fd);
     pa_make_socket_low_delay(u->stream_fd);
 
+    one = 1;
+    if (setsockopt(u->stream_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) < 0)
+        pa_log_warn("Failed to enable SO_TIMESTAMP: %s", pa_cstrerror(errno));
+
+    pa_log_debug("Stream properly set up, we're ready to roll!");
+
     u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
     pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
     pollfd->fd = u->stream_fd;
     pollfd->events = pollfd->revents = 0;
 
-    u->read_index = 0;
-    u->write_index = 0;
+    u->read_index = u->write_index = 0;
+    u->started_at = 0;
+
+    if (u->source)
+        u->read_smoother = pa_smoother_new(
+                PA_USEC_PER_SEC,
+                PA_USEC_PER_SEC*2,
+                TRUE,
+                TRUE,
+                10,
+                pa_rtclock_usec(),
+                TRUE);
 
     return 0;
 }
@@ -781,6 +802,11 @@ static int stop_stream_fd(struct userdata *u) {
     pa_close(u->stream_fd);
     u->stream_fd = -1;
 
+    if (u->read_smoother) {
+        pa_smoother_free(u->read_smoother);
+        u->read_smoother = NULL;
+    }
+
     return r;
 }
 
@@ -819,8 +845,6 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
                     if (!u->source || u->source->state == PA_SOURCE_SUSPENDED)
                         if (start_stream_fd(u) < 0)
                             failed = TRUE;
-
-                    u->started_at = pa_rtclock_usec();
                     break;
 
                 case PA_SINK_UNLINKED:
@@ -831,7 +855,24 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
             break;
 
         case PA_SINK_MESSAGE_GET_LATENCY: {
-            *((pa_usec_t*) data) = 0;
+
+            if (u->read_smoother) {
+                pa_usec_t wi, ri;
+
+                ri = pa_smoother_get(u->read_smoother, pa_rtclock_usec());
+                wi = pa_bytes_to_usec(u->write_index + u->block_size, &u->sample_spec);
+
+                *((pa_usec_t*) data) = wi > ri ? wi - ri : 0;
+            } else {
+                pa_usec_t ri, wi;
+
+                ri = pa_rtclock_usec() - u->started_at;
+                wi = pa_bytes_to_usec(u->write_index, &u->sample_spec);
+
+                *((pa_usec_t*) data) = wi > ri ? wi - ri : 0;
+            }
+
+            *((pa_usec_t*) data) += u->sink->fixed_latency;
             return 0;
         }
     }
@@ -862,7 +903,8 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
                     if (!u->sink || u->sink->state == PA_SINK_SUSPENDED)
                         stop_stream_fd(u);
 
-                    pa_smoother_pause(u->read_smoother, pa_rtclock_usec());
+                    if (u->read_smoother)
+                        pa_smoother_pause(u->read_smoother, pa_rtclock_usec());
                     break;
 
                 case PA_SOURCE_IDLE:
@@ -875,7 +917,8 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
                         if (start_stream_fd(u) < 0)
                             failed = TRUE;
 
-                    pa_smoother_resume(u->read_smoother, pa_rtclock_usec(), TRUE);
+                    /* We don't resume the smoother here. Instead we
+                     * wait until the first packet arrives */
                     break;
 
                 case PA_SOURCE_UNLINKED:
@@ -886,7 +929,12 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
             break;
 
         case PA_SOURCE_MESSAGE_GET_LATENCY: {
-            *((pa_usec_t*) data) = 0;
+            pa_usec_t wi, ri;
+
+            wi = pa_smoother_get(u->read_smoother, pa_rtclock_usec());
+            ri = pa_bytes_to_usec(u->read_index, &u->sample_spec);
+
+            *((pa_usec_t*) data) = (wi > ri ? wi - ri : 0) + u->source->fixed_latency;
             return 0;
         }
 
@@ -954,6 +1002,7 @@ static int hsp_process_render(struct userdata *u) {
         pa_memblock_unref(u->write_memchunk.memblock);
         pa_memchunk_reset(&u->write_memchunk);
 
+        ret = 1;
         break;
     }
 
@@ -968,6 +1017,7 @@ static int hsp_process_push(struct userdata *u) {
     pa_assert(u);
     pa_assert(u->profile == PROFILE_HSP);
     pa_assert(u->source);
+    pa_assert(u->read_smoother);
 
     memchunk.memblock = pa_memblock_new(u->core->mempool, u->block_size);
     memchunk.index = memchunk.length = 0;
@@ -975,9 +1025,26 @@ static int hsp_process_push(struct userdata *u) {
     for (;;) {
         ssize_t l;
         void *p;
+        struct msghdr m;
+        struct cmsghdr *cm;
+        uint8_t aux[1024];
+        struct iovec iov;
+        pa_bool_t found_tstamp = FALSE;
+        pa_usec_t tstamp;
+
+        memset(&m, 0, sizeof(m));
+        memset(&aux, 0, sizeof(aux));
+        memset(&iov, 0, sizeof(iov));
+
+        m.msg_iov = &iov;
+        m.msg_iovlen = 1;
+        m.msg_control = aux;
+        m.msg_controllen = sizeof(aux);
 
         p = pa_memblock_acquire(memchunk.memblock);
-        l = pa_read(u->stream_fd, p, pa_memblock_get_length(memchunk.memblock), &u->stream_read_type);
+        iov.iov_base = p;
+        iov.iov_len = pa_memblock_get_length(memchunk.memblock);
+        l = recvmsg(u->stream_fd, &m, 0);
         pa_memblock_release(memchunk.memblock);
 
         if (l <= 0) {
@@ -1000,7 +1067,26 @@ static int hsp_process_push(struct userdata *u) {
         memchunk.length = (size_t) l;
         u->read_index += (uint64_t) l;
 
+        for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
+            if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) {
+                struct timeval *tv = (struct timeval*) CMSG_DATA(cm);
+                pa_rtclock_from_wallclock(tv);
+                tstamp = pa_timeval_load(tv);
+                found_tstamp = TRUE;
+                break;
+            }
+
+        if (!found_tstamp) {
+            pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!");
+            tstamp = pa_rtclock_usec();
+        }
+
+        pa_smoother_put(u->read_smoother, tstamp, pa_bytes_to_usec(u->read_index, &u->sample_spec));
+        pa_smoother_resume(u->read_smoother, tstamp, TRUE);
+
         pa_source_post(u->source, &memchunk);
+
+        ret = 1;
         break;
     }
 
@@ -1105,7 +1191,7 @@ static int a2dp_process_render(struct userdata *u) {
     header->v = 2;
     header->pt = 1;
     header->sequence_number = htons(a2dp->seq_num++);
-    header->timestamp = htonl(u->write_index / pa_frame_size(&u->sink->sample_spec));
+    header->timestamp = htonl(u->write_index / pa_frame_size(&u->sample_spec));
     header->ssrc = htonl(1);
     payload->frame_count = frame_count;
 
@@ -1147,6 +1233,8 @@ static int a2dp_process_render(struct userdata *u) {
         pa_memblock_unref(u->write_memchunk.memblock);
         pa_memchunk_reset(&u->write_memchunk);
 
+        ret = 1;
+
         break;
     }
 
@@ -1155,7 +1243,8 @@ static int a2dp_process_render(struct userdata *u) {
 
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
-    pa_bool_t do_write = FALSE, writable = FALSE;
+    unsigned do_write = 0;
+    pa_bool_t writable = FALSE;
 
     pa_assert(u);
 
@@ -1170,8 +1259,6 @@ static void thread_func(void *userdata) {
     pa_thread_mq_install(&u->thread_mq);
     pa_rtpoll_install(u->rtpoll);
 
-    pa_smoother_set_time_offset(u->read_smoother, pa_rtclock_usec());
-
     for (;;) {
         struct pollfd *pollfd;
         int ret;
@@ -1182,12 +1269,13 @@ static void thread_func(void *userdata) {
         if (u->source && PA_SOURCE_IS_LINKED(u->source->thread_info.state)) {
 
             if (pollfd && (pollfd->revents & POLLIN)) {
+                int n_read;
 
-                if (hsp_process_push(u) < 0)
+                if ((n_read = hsp_process_push(u)) < 0)
                     goto fail;
 
                 /* We just read something, so we are supposed to write something, too */
-                do_write = TRUE;
+                do_write += n_read;
             }
         }
 
@@ -1200,7 +1288,7 @@ static void thread_func(void *userdata) {
                 if (pollfd->revents & POLLOUT)
                     writable = TRUE;
 
-                if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && !do_write && writable) {
+                if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0 && writable) {
                     pa_usec_t time_passed;
                     uint64_t should_have_written;
 
@@ -1208,36 +1296,37 @@ static void thread_func(void *userdata) {
                      * to. So let's do things by time */
 
                     time_passed = pa_rtclock_usec() - u->started_at;
-                    should_have_written = pa_usec_to_bytes(time_passed, &u->sink->sample_spec);
+                    should_have_written = pa_usec_to_bytes(time_passed, &u->sample_spec);
 
-                    do_write = u->write_index <= should_have_written ;
-/*                 pa_log_debug("Time has come: %s", pa_yes_no(do_write)); */
+                    do_write = u->write_index <= should_have_written;
                 }
 
-                if (writable && do_write) {
-                    if (u->write_index == 0)
+                if (writable && do_write > 0) {
+                    int n_written;
+
+                    if (u->write_index <= 0)
                         u->started_at = pa_rtclock_usec();
 
                     if (u->profile == PROFILE_A2DP) {
-                        if (a2dp_process_render(u) < 0)
+                        if ((n_written = a2dp_process_render(u)) < 0)
                             goto fail;
                     } else {
-                        if (hsp_process_render(u) < 0)
+                        if ((n_written = hsp_process_render(u)) < 0)
                             goto fail;
                     }
 
-                    do_write = FALSE;
+                    do_write -= n_written;
                     writable = FALSE;
                 }
 
-                if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && !do_write) {
+                if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0) {
                     pa_usec_t time_passed, next_write_at, sleep_for;
 
                     /* Hmm, there is no input stream we could synchronize
                      * to. So let's estimate when we need to wake up the latest */
 
                     time_passed = pa_rtclock_usec() - u->started_at;
-                    next_write_at = pa_bytes_to_usec(u->write_index, &u->sink->sample_spec);
+                    next_write_at = pa_bytes_to_usec(u->write_index, &u->sample_spec);
                     sleep_for = time_passed < next_write_at ? next_write_at - time_passed : 0;
 
 /*                 pa_log("Sleeping for %lu; time passed %lu, next write at %lu", (unsigned long) sleep_for, (unsigned long) time_passed, (unsigned long)next_write_at); */
@@ -1317,12 +1406,12 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
         if (u->profile == PROFILE_HSP) {
             if (u->sink && dbus_message_is_signal(m, "org.bluez.Headset", "SpeakerGainChanged")) {
 
-                pa_cvolume_set(&v, u->sink->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
+                pa_cvolume_set(&v, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
                 pa_sink_volume_changed(u->sink, &v);
 
             } else if (u->source && dbus_message_is_signal(m, "org.bluez.Headset", "MicrophoneGainChanged")) {
 
-                pa_cvolume_set(&v, u->sink->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
+                pa_cvolume_set(&v, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
                 pa_source_volume_changed(u->source, &v);
             }
         }
@@ -1350,7 +1439,7 @@ static void sink_set_volume_cb(pa_sink *s) {
     if (gain > 15)
         gain = 15;
 
-    pa_cvolume_set(&s->virtual_volume, u->sink->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
+    pa_cvolume_set(&s->virtual_volume, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
 
     pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->path, "org.bluez.Headset", "SetSpeakerGain"));
     pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID));
@@ -1374,7 +1463,7 @@ static void source_set_volume_cb(pa_source *s) {
     if (gain > 15)
         gain = 15;
 
-    pa_cvolume_set(&s->virtual_volume, u->source->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
+    pa_cvolume_set(&s->virtual_volume, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
 
     pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->path, "org.bluez.Headset", "SetMicrophoneGain"));
     pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID));
@@ -1513,6 +1602,9 @@ static int add_sink(struct userdata *u) {
         u->sink->parent.process_msg = sink_process_msg;
 
         pa_sink_set_max_request(u->sink, u->block_size);
+        u->sink->fixed_latency =
+            (u->profile == PROFILE_A2DP ? FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
+            pa_bytes_to_usec(u->block_size, &u->sample_spec);
     }
 
     if (u->profile == PROFILE_HSP) {
@@ -1560,6 +1652,10 @@ static int add_source(struct userdata *u) {
 
         u->source->userdata = u;
         u->source->parent.process_msg = source_process_msg;
+
+        u->source->fixed_latency =
+            (/* u->profile == PROFILE_A2DP ? FIXED_LATENCY_RECORD_A2DP : */ FIXED_LATENCY_RECORD_HSP) +
+            pa_bytes_to_usec(u->block_size, &u->sample_spec);
     }
 
     if (u->profile == PROFILE_HSP) {
@@ -1580,12 +1676,12 @@ static void shutdown_bt(struct userdata *u) {
         u->stream_fd = -1;
 
         u->stream_write_type = 0;
-        u->stream_read_type = 0;
     }
 
     if (u->service_fd >= 0) {
         pa_close(u->service_fd);
         u->service_fd = -1;
+        u->service_write_type = u->service_write_type = 0;
     }
 
     if (u->write_memchunk.memblock) {
@@ -1600,7 +1696,7 @@ static int init_bt(struct userdata *u) {
 
     shutdown_bt(u);
 
-    u->stream_write_type = u->stream_read_type = 0;
+    u->stream_write_type = 0;
     u->service_write_type = u->service_write_type = 0;
 
     if ((u->service_fd = bt_audio_service_open()) < 0) {
@@ -1701,6 +1797,11 @@ static void stop_thread(struct userdata *u) {
         pa_rtpoll_free(u->rtpoll);
         u->rtpoll = NULL;
     }
+
+    if (u->read_smoother) {
+        pa_smoother_free(u->read_smoother);
+        u->read_smoother = NULL;
+    }
 }
 
 /* Run from main thread */
@@ -1997,14 +2098,6 @@ int pa__init(pa_module* m) {
     u->core = m->core;
     u->service_fd = -1;
     u->stream_fd = -1;
-    u->read_smoother = pa_smoother_new(
-            PA_USEC_PER_SEC,
-            PA_USEC_PER_SEC*2,
-            TRUE,
-            TRUE,
-            10,
-            0,
-            FALSE);
     u->sample_spec = m->core->default_sample_spec;
     u->modargs = ma;
 

commit ee6657aa9a654d334a5a900ea359c726550383e0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Apr 10 01:31:25 2009 +0200

    bluetooth: when starting up HSP stream, send 2 packets first, only afterwards enter one-read-one-write logic

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 2812bc2..90f6486 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1268,6 +1268,12 @@ static void thread_func(void *userdata) {
 
         if (u->source && PA_SOURCE_IS_LINKED(u->source->thread_info.state)) {
 
+            /* We should send two blocks to the device before we expect
+             * a response. */
+
+            if (u->write_index == 0 && u->read_index <= 0)
+                do_write = 2;
+
             if (pollfd && (pollfd->revents & POLLIN)) {
                 int n_read;
 

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list