[pulseaudio-commits] 66 commits - bootstrap.sh configure.ac .gitignore m4/.gitignore Makefile.am man/pulseaudio.1.xml.in man/pulse-daemon.conf.5.xml.in meson.build meson_options.txt po/be.po po/de.po po/el.po po/fr.po po/.gitignore po/hr.po po/hu.po po/id.po po/it.po po/lt.po po/Makevars po/nn.po po/oc.po po/pl.po po/POTFILES.in po/pt_BR.po po/ru.po po/sk.po po/sv.po po/tr.po po/uk.po po/zh_CN.po po/zh_TW.po PROTOCOL src/daemon src/Makefile.am src/map-file src/meson.build src/modules src/pulse src/pulsecore src/tests src/utils .travis.yml

Arun Raghavan arun at kemper.freedesktop.org
Thu Jun 21 01:04:03 UTC 2018


 .gitignore                                                              |    3 
 .travis.yml                                                             |    1 
 Makefile.am                                                             |    3 
 PROTOCOL                                                                |    7 
 bootstrap.sh                                                            |    8 
 configure.ac                                                            |   29 
 m4/.gitignore                                                           |    2 
 man/pulse-daemon.conf.5.xml.in                                          |   15 
 man/pulseaudio.1.xml.in                                                 |   17 
 meson.build                                                             |  220 
 meson_options.txt                                                       |   13 
 po/.gitignore                                                           |    3 
 po/Makevars                                                             |   78 
 po/POTFILES.in                                                          |    1 
 po/be.po                                                                |   28 
 po/de.po                                                                |   28 
 po/el.po                                                                |   28 
 po/fr.po                                                                |   28 
 po/hr.po                                                                |   28 
 po/hu.po                                                                |   28 
 po/id.po                                                                |   28 
 po/it.po                                                                |   28 
 po/lt.po                                                                |   28 
 po/nn.po                                                                |   28 
 po/oc.po                                                                |   28 
 po/pl.po                                                                |   72 
 po/pt_BR.po                                                             |   28 
 po/ru.po                                                                |   28 
 po/sk.po                                                                |   28 
 po/sv.po                                                                |   28 
 po/tr.po                                                                |   28 
 po/uk.po                                                                |   28 
 po/zh_CN.po                                                             |   28 
 po/zh_TW.po                                                             |   28 
 src/Makefile.am                                                         |   41 
 src/daemon/daemon-conf.c                                                |    4 
 src/daemon/main.c                                                       |    9 
 src/daemon/meson.build                                                  |   34 
 src/daemon/pulseaudio.desktop.in                                        |    4 
 src/map-file                                                            |    1 
 src/meson.build                                                         |  194 
 src/modules/alsa/alsa-mixer.c                                           |    3 
 src/modules/alsa/alsa-sink.c                                            |   28 
 src/modules/alsa/alsa-source.c                                          |   27 
 src/modules/alsa/meson.build                                            |   31 
 src/modules/alsa/mixer/paths/steelseries-arctis-5-output-chat.conf      |   27 
 src/modules/alsa/mixer/paths/steelseries-arctis-5-output-game.conf      |   27 
 src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules                 |    4 
 src/modules/alsa/mixer/profile-sets/cmedia-high-speed-true-hdaudio.conf |   66 
 src/modules/alsa/mixer/profile-sets/default.conf                        |   18 
 src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf           |   90 
 src/modules/alsa/mixer/profile-sets/steelseries-arctis-5-usb-audio.conf |   22 
 src/modules/alsa/mixer/profile-sets/steelseries-arctis-7-usb-audio.conf |    6 
 src/modules/alsa/module-alsa-card.c                                     |   51 
 src/modules/bluetooth/backend-ofono.c                                   |  112 
 src/modules/bluetooth/bluez4-util.c                                     | 1851 ------
 src/modules/bluetooth/bluez4-util.h                                     |  160 
 src/modules/bluetooth/module-bluetooth-discover.c                       |   13 
 src/modules/bluetooth/module-bluetooth-policy.c                         |   17 
 src/modules/bluetooth/module-bluez4-device.c                            | 2664 ----------
 src/modules/bluetooth/module-bluez4-discover.c                          |  187 
 src/modules/bluetooth/module-bluez5-device.c                            |   11 
 src/modules/echo-cancel/module-echo-cancel.c                            |    2 
 src/modules/jack/module-jack-sink.c                                     |    5 
 src/modules/jack/module-jack-source.c                                   |    5 
 src/modules/macosx/module-coreaudio-device.c                            |    2 
 src/modules/meson.build                                                 |  125 
 src/modules/module-combine-sink.c                                       |    3 
 src/modules/module-console-kit.c                                        |   13 
 src/modules/module-equalizer-sink.c                                     |    2 
 src/modules/module-esound-sink.c                                        |    4 
 src/modules/module-ladspa-sink.c                                        |    2 
 src/modules/module-loopback.c                                           |  174 
 src/modules/module-null-sink.c                                          |    6 
 src/modules/module-null-source.c                                        |    4 
 src/modules/module-pipe-sink.c                                          |    4 
 src/modules/module-remap-sink.c                                         |    2 
 src/modules/module-role-cork.c                                          |    2 
 src/modules/module-role-ducking.c                                       |    2 
 src/modules/module-solaris.c                                            |   18 
 src/modules/module-systemd-login.c                                      |   14 
 src/modules/module-udev-detect.c                                        |   17 
 src/modules/module-virtual-sink.c                                       |    2 
 src/modules/module-virtual-surround-sink.c                              |    2 
 src/modules/module-waveout.c                                            |    2 
 src/modules/oss/module-oss.c                                            |   14 
 src/modules/raop/raop-sink.c                                            |    4 
 src/modules/rtp/module-rtp-send.c                                       |    5 
 src/modules/x11/module-x11-xsmp.c                                       |   13 
 src/pulse/context.c                                                     |   23 
 src/pulse/context.h                                                     |   14 
 src/pulse/format.c                                                      |    2 
 src/pulse/format.h                                                      |    8 
 src/pulse/internal.h                                                    |    6 
 src/pulse/mainloop.c                                                    |    2 
 src/pulse/mainloop.h                                                    |    2 
 src/pulse/meson.build                                                   |   73 
 src/pulse/operation.c                                                   |    2 
 src/pulse/operation.h                                                   |    2 
 src/pulse/proplist.c                                                    |   49 
 src/pulse/proplist.h                                                    |   18 
 src/pulse/scache.c                                                      |    8 
 src/pulse/scache.h                                                      |    2 
 src/pulse/stream.c                                                      |   28 
 src/pulse/stream.h                                                      |   24 
 src/pulse/thread-mainloop.c                                             |    2 
 src/pulse/thread-mainloop.h                                             |    2 
 src/pulse/util.c                                                        |  176 
 src/pulse/util.h                                                        |    6 
 src/pulse/volume.c                                                      |    2 
 src/pulse/volume.h                                                      |    2 
 src/pulsecore/cli-command.c                                             |    7 
 src/pulsecore/core-format.c                                             |   20 
 src/pulsecore/core-util.c                                               |  173 
 src/pulsecore/core-util.h                                               |    1 
 src/pulsecore/core.c                                                    |   10 
 src/pulsecore/core.h                                                    |    2 
 src/pulsecore/hashmap.c                                                 |   16 
 src/pulsecore/hashmap.h                                                 |   14 
 src/pulsecore/meson.build                                               |  170 
 src/pulsecore/module.c                                                  |    4 
 src/pulsecore/sink.c                                                    |    6 
 src/pulsecore/sink.h                                                    |    2 
 src/pulsecore/source.c                                                  |    6 
 src/pulsecore/source.h                                                  |    2 
 src/pulsecore/tagstruct.c                                               |    4 
 src/pulsecore/tagstruct.h                                               |    4 
 src/tests/lo-test-util.c                                                |    2 
 src/tests/rtstutter.c                                                   |    2 
 src/utils/meson.build                                                   |   67 
 130 files changed, 2077 insertions(+), 6042 deletions(-)

New commits:
commit d251665f223ccb9f51b81db0140fbd807413bef2
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Thu Jun 7 04:02:16 2018 +0100

    context: pa_context_rttime_restart: constify context pointer

diff --git a/src/pulse/context.c b/src/pulse/context.c
index c5850979..dc59ed2d 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1606,7 +1606,7 @@ pa_time_event* pa_context_rttime_new(const pa_context *c, pa_usec_t usec, pa_tim
     return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
 }
 
-void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
+void pa_context_rttime_restart(const pa_context *c, pa_time_event *e, pa_usec_t usec) {
     struct timeval tv;
 
     pa_assert(c);
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 665e9f83..cc96f419 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -264,7 +264,7 @@ pa_time_event* pa_context_rttime_new(const pa_context *c, pa_usec_t usec, pa_tim
 
 /** Restart a running or expired timer event source (wrapper for
  * mainloop->time_restart). \since 0.9.16 */
-void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec);
+void pa_context_rttime_restart(const pa_context *c, pa_time_event *e, pa_usec_t usec);
 
 /** Return the optimal block size for passing around audio buffers. It
  * is recommended to allocate buffers of the size returned here when

commit 31da2a7d3f4244eb888701cab89138234d7c2cb3
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Thu Jun 7 04:00:42 2018 +0100

    context: pa_context_rttime_new: constify context pointer

diff --git a/src/pulse/context.c b/src/pulse/context.c
index 1f32421b..c5850979 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1591,7 +1591,7 @@ finish:
         pa_proplist_free(pl);
 }
 
-pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
+pa_time_event* pa_context_rttime_new(const pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
     struct timeval tv;
 
     pa_assert(c);
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 37333fca..665e9f83 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -260,7 +260,7 @@ uint32_t pa_context_get_index(pa_context *s);
 
 /** Create a new timer event source for the specified time (wrapper
  * for mainloop->time_new). \since 0.9.16 */
-pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata);
+pa_time_event* pa_context_rttime_new(const pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata);
 
 /** Restart a running or expired timer event source (wrapper for
  * mainloop->time_restart). \since 0.9.16 */

commit ccf3d2926490f77a17e02e1ab59ebf478c364990
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Thu Jun 7 03:51:09 2018 +0100

    context: pa_context_errno: constify

diff --git a/src/pulse/context.c b/src/pulse/context.c
index d298ae3e..1f32421b 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1068,7 +1068,7 @@ pa_context_state_t pa_context_get_state(const pa_context *c) {
     return c->state;
 }
 
-int pa_context_errno(pa_context *c) {
+int pa_context_errno(const pa_context *c) {
 
     if (!c)
         return PA_ERR_INVALID;
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 7a38ff23..37333fca 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -190,7 +190,7 @@ void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, voi
 void pa_context_set_event_callback(pa_context *p, pa_context_event_cb_t cb, void *userdata);
 
 /** Return the error number of the last failed operation */
-int pa_context_errno(pa_context *c);
+int pa_context_errno(const pa_context *c);
 
 /** Return non-zero if some data is pending to be written to the connection */
 int pa_context_is_pending(pa_context *c);

commit f727cd9ac07dab6d88df8e0ddcf60c54f4805d81
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Thu Jun 7 02:43:56 2018 +0100

    context: hide error attr behind pointer
    
    Paves the way towards more of the API using const pointers.
    
    Some pa_context_* functions return their errors by setting the context
    error, even when there's no other change in the context state. This
    prevented constifying the pa_context arguments of such functions. This
    patch puts the error in its own struct behind a pointer, so that setting
    the error doesn't any more count as modifying the pa_context object.

diff --git a/src/pulse/context.c b/src/pulse/context.c
index adbeb153..d298ae3e 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -139,6 +139,9 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
     c = pa_xnew0(pa_context, 1);
     PA_REFCNT_INIT(c);
 
+    c->error = pa_xnew0(pa_context_error, 1);
+    assert(c->error);
+
     c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
 
     if (name)
@@ -156,7 +159,7 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
     PA_LLIST_HEAD_INIT(pa_stream, c->streams);
     PA_LLIST_HEAD_INIT(pa_operation, c->operations);
 
-    c->error = PA_OK;
+    c->error->error = PA_OK;
     c->state = PA_CONTEXT_UNCONNECTED;
 
     reset_callbacks(c);
@@ -315,7 +318,7 @@ int pa_context_set_error(pa_context *c, int error) {
     pa_assert(error < PA_ERR_MAX);
 
     if (c)
-        c->error = error;
+        c->error->error = error;
 
     return error;
 }
@@ -1072,7 +1075,7 @@ int pa_context_errno(pa_context *c) {
 
     pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
-    return c->error;
+    return c->error->error;
 }
 
 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index 01d2b6e4..04f35e9a 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -55,6 +55,10 @@
 #define PA_PROTOCOL_FLAG_SHM 0x80000000U
 #define PA_PROTOCOL_FLAG_MEMFD 0x40000000U
 
+typedef struct pa_context_error {
+    int error;
+} pa_context_error;
+
 struct pa_context {
     PA_REFCNT_DECLARE;
 
@@ -80,7 +84,7 @@ struct pa_context {
     uint32_t version;
     uint32_t ctag;
     uint32_t csyncid;
-    int error;
+    pa_context_error *error;
     pa_context_state_t state;
 
     pa_context_notify_cb_t state_callback;

commit 9472bebcb00ee9bd337c2efbd7e651a6bc3227bf
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Thu Jun 7 03:15:41 2018 +0100

    stream: constify internal functions

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 73743cbb..f0c8034a 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1731,7 +1731,7 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us
     return o;
 }
 
-static pa_usec_t calc_time(pa_stream *s, bool ignore_transport) {
+static pa_usec_t calc_time(const pa_stream *s, bool ignore_transport) {
     pa_usec_t usec;
 
     pa_assert(s);
@@ -2485,7 +2485,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) {
     return 0;
 }
 
-static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) {
+static pa_usec_t time_counter_diff(const pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 

commit 1e734e9946c6d5d321a3e13c3bc9bc57f0cbe14b
Author: Nazar Mokrynskyi <nazar at mokrynskyi.com>
Date:   Fri Jun 1 13:38:14 2018 +0300

    alsa-mixer: Don't move LFE in 2.1 and 4.1 modes on SB Omni Surround 5.1
    
    A bit hacky approach, but it allows to preserve LFE output position
    even in reduced output modes 2.1 and 4.1.
    
    Signed-off-by: Nazar Mokrynskyi <nazar at mokrynskyi.com>

diff --git a/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf b/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf
index 11985bb3..d5d1d653 100644
--- a/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf
+++ b/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf
@@ -42,7 +42,7 @@ direction = output
 
 [Mapping analog-surround-21]
 device-strings = surround51:%f
-channel-map = front-left,front-right,lfe
+channel-map = front-left,front-right,aux1,aux2,aux3,lfe
 paths-output = analog-output
 direction = output
 
@@ -54,7 +54,7 @@ direction = output
 
 [Mapping analog-surround-41]
 device-strings = surround51:%f
-channel-map = front-left,front-right,rear-left,rear-right,lfe
+channel-map = front-left,front-right,rear-left,rear-right,aux1,lfe
 paths-output = analog-output
 direction = output
 

commit 3f2a0c17baa976b7d2d4bafad7a8e703ffd0191a
Author: Tomaz Solc <tomaz.solc at tablix.org>
Date:   Tue May 29 09:22:59 2018 +0200

    cli-command: Report error in pa_play_file.
    
    Current code does not check whether pa_play_file call failed. Hence no error is
    reported in the cli interface if playback failed because e.g. file isn't
    readable by the daemon.

diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 44795b0d..defdac1e 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1282,7 +1282,12 @@ static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf,
         return -1;
     }
 
-    return pa_play_file(sink, fname, NULL);
+    if (pa_play_file(sink, fname, NULL) < 0) {
+        pa_strbuf_puts(buf, "Failed to play sound file.\n");
+        return -1;
+    }
+
+    return 0;
 }
 
 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {

commit e6226b07c0ef71ea0ae5301def0ffa8354eaa145
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 06:08:16 2018 +0100

    stream: pa_stream_get_monitor_stream: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index b23323d2..73743cbb 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -2915,7 +2915,7 @@ int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) {
     return 0;
 }
 
-uint32_t pa_stream_get_monitor_stream(pa_stream *s) {
+uint32_t pa_stream_get_monitor_stream(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 667af853..7913f7fe 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -801,7 +801,7 @@ int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx);
 /** Return the sink input index previously set with
  * pa_stream_set_monitor_stream(). Returns PA_INVALID_INDEX
  * on failure. \since 0.9.11 */
-uint32_t pa_stream_get_monitor_stream(pa_stream *s);
+uint32_t pa_stream_get_monitor_stream(const pa_stream *s);
 
 PA_C_DECL_END
 

commit 6f2a70191dbbe523c6174e0106513bc16a532d2b
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Mon May 28 00:03:14 2018 +0100

    stream: pa_stream_get_format_info: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index d57c27ad..b23323d2 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -2570,7 +2570,7 @@ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) {
     return &s->channel_map;
 }
 
-const pa_format_info* pa_stream_get_format_info(pa_stream *s) {
+const pa_format_info* pa_stream_get_format_info(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 1c228354..667af853 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -751,7 +751,7 @@ const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s);
 const pa_channel_map* pa_stream_get_channel_map(pa_stream *s);
 
 /** Return a pointer to the stream's format. \since 1.0 */
-const pa_format_info* pa_stream_get_format_info(pa_stream *s);
+const pa_format_info* pa_stream_get_format_info(const pa_stream *s);
 
 /** Return the per-stream server-side buffer metrics of the
  * stream. Only valid after the stream has been connected successfully

commit c16b842ac07c238b362e081b8acf50fcfd1adf2c
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 06:00:02 2018 +0100

    stream: pa_stream_get_underflow_index: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 4786d751..d57c27ad 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -850,7 +850,7 @@ finish:
     pa_context_unref(c);
 }
 
-int64_t pa_stream_get_underflow_index(pa_stream *p) {
+int64_t pa_stream_get_underflow_index(const pa_stream *p) {
     pa_assert(p);
     return p->latest_underrun_at_index;
 }
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 4a2efada..1c228354 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -602,7 +602,7 @@ void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, voi
  * known (e.g.\ if no underflow has occurred, or server is older than 1.0).
  * Can be used inside the underflow callback to get information about the current underflow.
  * (Only for playback streams) \since 1.0 */
-int64_t pa_stream_get_underflow_index(pa_stream *p);
+int64_t pa_stream_get_underflow_index(const pa_stream *p);
 
 /** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) */
 void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);

commit 883421df03d88ef634fd06d6e5dc2faf70e52198
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:57:52 2018 +0100

    stream: pa_stream_[writable|readable]_size: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index e32dd008..4786d751 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1678,7 +1678,7 @@ int pa_stream_drop(pa_stream *s) {
     return 0;
 }
 
-size_t pa_stream_writable_size(pa_stream *s) {
+size_t pa_stream_writable_size(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
@@ -1689,7 +1689,7 @@ size_t pa_stream_writable_size(pa_stream *s) {
     return s->requested_bytes > 0 ? (size_t) s->requested_bytes : 0;
 }
 
-size_t pa_stream_readable_size(pa_stream *s) {
+size_t pa_stream_readable_size(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 89a8924c..4a2efada 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -566,12 +566,12 @@ int pa_stream_drop(pa_stream *p);
  *
  * (size_t) -1 is returned on error.
  */
-size_t pa_stream_writable_size(pa_stream *p);
+size_t pa_stream_writable_size(const pa_stream *p);
 
 /** Return the number of bytes that may be read using pa_stream_peek().
  *
  * (size_t) -1 is returned on error. */
-size_t pa_stream_readable_size(pa_stream *p);
+size_t pa_stream_readable_size(const pa_stream *p);
 
 /** Drain a playback stream.  Use this for notification when the
  * playback buffer is empty after playing all the audio in the buffer.

commit d1f708ecfcc2c7c6b8c7cee986fc1091c3a18eb2
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:54:02 2018 +0100

    stream: pa_stream_is_[suspended|corked]: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 52b10cd4..e32dd008 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -2740,7 +2740,7 @@ const char *pa_stream_get_device_name(const pa_stream *s) {
     return s->device_name;
 }
 
-int pa_stream_is_suspended(pa_stream *s) {
+int pa_stream_is_suspended(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
@@ -2752,7 +2752,7 @@ int pa_stream_is_suspended(pa_stream *s) {
     return s->suspended;
 }
 
-int pa_stream_is_corked(pa_stream *s) {
+int pa_stream_is_corked(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 08adc993..89a8924c 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -380,11 +380,11 @@ const char *pa_stream_get_device_name(const pa_stream *s);
  * been suspended. This will return 0 if not, and a negative value on
  * error. This function will return with -PA_ERR_NOTSUPPORTED when the
  * server is older than 0.9.8. \since 0.9.8 */
-int pa_stream_is_suspended(pa_stream *s);
+int pa_stream_is_suspended(const pa_stream *s);
 
 /** Return 1 if the this stream has been corked. This will return 0 if
  * not, and a negative value on error. \since 0.9.11 */
-int pa_stream_is_corked(pa_stream *s);
+int pa_stream_is_corked(const pa_stream *s);
 
 /** Connect the stream to a sink. It is strongly recommended to pass
  * NULL in both \a dev and \a volume and to set neither

commit 22f2a445a26b5b74ddb02c3b4a2b02a74ef53dde
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:51:30 2018 +0100

    stream: pa_stream_get_device_[index|name]: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index bb2115ac..52b10cd4 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -2714,7 +2714,7 @@ pa_operation* pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr
     return o;
 }
 
-uint32_t pa_stream_get_device_index(pa_stream *s) {
+uint32_t pa_stream_get_device_index(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
@@ -2727,7 +2727,7 @@ uint32_t pa_stream_get_device_index(pa_stream *s) {
     return s->device_index;
 }
 
-const char *pa_stream_get_device_name(pa_stream *s) {
+const char *pa_stream_get_device_name(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 63289141..08adc993 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -363,7 +363,7 @@ uint32_t pa_stream_get_index(const pa_stream *s);
  * it is recommended to use pa_stream_set_moved_callback() to be notified
  * about this. This function will return with PA_INVALID_INDEX on failure,
  * including the being server older than 0.9.8. \since 0.9.8 */
-uint32_t pa_stream_get_device_index(pa_stream *s);
+uint32_t pa_stream_get_device_index(const pa_stream *s);
 
 /** Return the name of the sink or source this stream is connected to
  * in the server. This is useful with the introspection
@@ -374,7 +374,7 @@ uint32_t pa_stream_get_device_index(pa_stream *s);
  * it is recommended to use pa_stream_set_moved_callback() to be notified
  * about this. This function will fail when the server is older than
  * 0.9.8. \since 0.9.8 */
-const char *pa_stream_get_device_name(pa_stream *s);
+const char *pa_stream_get_device_name(const pa_stream *s);
 
 /** Return 1 if the sink or source this stream is connected to has
  * been suspended. This will return 0 if not, and a negative value on

commit 274cb7b6d0032d6c9a3cbe5974be958b9090ac01
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:49:23 2018 +0100

    stream: pa_stream_get_index: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index d1ccfbca..bb2115ac 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -345,7 +345,7 @@ pa_context* pa_stream_get_context(const pa_stream *s) {
     return s->context;
 }
 
-uint32_t pa_stream_get_index(pa_stream *s) {
+uint32_t pa_stream_get_index(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 4c52c310..63289141 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -352,7 +352,7 @@ pa_context* pa_stream_get_context(const pa_stream *p);
  * introspection functions such as pa_context_get_sink_input_info()
  * or pa_context_get_source_output_info(). This returns PA_INVALID_INDEX
  * on failure. */
-uint32_t pa_stream_get_index(pa_stream *s);
+uint32_t pa_stream_get_index(const pa_stream *s);
 
 /** Return the index of the sink or source this stream is connected to
  * in the server. This is useful with the introspection

commit 31eb433d7b0c53e0bcdeeb3ccad82cf66cfd9c3e
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:45:36 2018 +0100

    stream: pa_stream_get_context: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 3df52592..d1ccfbca 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -338,7 +338,7 @@ pa_stream_state_t pa_stream_get_state(const pa_stream *s) {
     return s->state;
 }
 
-pa_context* pa_stream_get_context(pa_stream *s) {
+pa_context* pa_stream_get_context(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 2a904b94..4c52c310 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -345,7 +345,7 @@ pa_stream *pa_stream_ref(pa_stream *s);
 pa_stream_state_t pa_stream_get_state(const pa_stream *p);
 
 /** Return the context this stream is attached to. */
-pa_context* pa_stream_get_context(pa_stream *p);
+pa_context* pa_stream_get_context(const pa_stream *p);
 
 /** Return the sink input resp.\ source output index this stream is
  * identified in the server with. This is useful with the

commit 6ab533c7aaea9e12d48acb0835c8f261b357f68b
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:43:01 2018 +0100

    stream: pa_stream_get_state: constify

diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index ee95757f..3df52592 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -331,7 +331,7 @@ pa_stream* pa_stream_ref(pa_stream *s) {
     return s;
 }
 
-pa_stream_state_t pa_stream_get_state(pa_stream *s) {
+pa_stream_state_t pa_stream_get_state(const pa_stream *s) {
     pa_assert(s);
     pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 4efba934..2a904b94 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -342,7 +342,7 @@ void pa_stream_unref(pa_stream *s);
 pa_stream *pa_stream_ref(pa_stream *s);
 
 /** Return the current state of the stream. */
-pa_stream_state_t pa_stream_get_state(pa_stream *p);
+pa_stream_state_t pa_stream_get_state(const pa_stream *p);
 
 /** Return the context this stream is attached to. */
 pa_context* pa_stream_get_context(pa_stream *p);

commit a24be6cc139dc4db731c29af2301d61bce5df7fa
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 06:14:29 2018 +0100

    operation: pa_operation_get_state: constify

diff --git a/src/pulse/operation.c b/src/pulse/operation.c
index 3ed3143f..61adf69b 100644
--- a/src/pulse/operation.c
+++ b/src/pulse/operation.c
@@ -129,7 +129,7 @@ void pa_operation_done(pa_operation *o) {
     operation_set_state(o, PA_OPERATION_DONE);
 }
 
-pa_operation_state_t pa_operation_get_state(pa_operation *o) {
+pa_operation_state_t pa_operation_get_state(const pa_operation *o) {
     pa_assert(o);
     pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
diff --git a/src/pulse/operation.h b/src/pulse/operation.h
index edd7d76e..302b85ba 100644
--- a/src/pulse/operation.h
+++ b/src/pulse/operation.h
@@ -49,7 +49,7 @@ void pa_operation_unref(pa_operation *o);
 void pa_operation_cancel(pa_operation *o);
 
 /** Return the current status of the operation */
-pa_operation_state_t pa_operation_get_state(pa_operation *o);
+pa_operation_state_t pa_operation_get_state(const pa_operation *o);
 
 /** Set the callback function that is called when the operation state
  * changes. Usually this is not necessary, since the functions that

commit 9b5077c468ba33872a124119a5a0a16fea8471ce
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 06:39:11 2018 +0100

    mainloop: constify get_retval functions

diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c
index aeb55d94..7d6a99c9 100644
--- a/src/pulse/mainloop.c
+++ b/src/pulse/mainloop.c
@@ -910,7 +910,7 @@ quit:
     return -2;
 }
 
-int pa_mainloop_get_retval(pa_mainloop *m) {
+int pa_mainloop_get_retval(const pa_mainloop *m) {
     pa_assert(m);
 
     return m->retval;
diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h
index a7df8a19..5f8c6267 100644
--- a/src/pulse/mainloop.h
+++ b/src/pulse/mainloop.h
@@ -96,7 +96,7 @@ a negative value on error. On success returns the number of source dispatched. *
 int pa_mainloop_dispatch(pa_mainloop *m);
 
 /** Return the return value as specified with the main loop's quit() routine. */
-int pa_mainloop_get_retval(pa_mainloop *m);
+int pa_mainloop_get_retval(const pa_mainloop *m);
 
 /** Run a single iteration of the main loop. This is a convenience function
 for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch().
diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c
index 993b7ba0..0205a4a7 100644
--- a/src/pulse/thread-mainloop.c
+++ b/src/pulse/thread-mainloop.c
@@ -231,7 +231,7 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) {
     pa_cond_signal(m->accept_cond, 0);
 }
 
-int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
+int pa_threaded_mainloop_get_retval(const pa_threaded_mainloop *m) {
     pa_assert(m);
 
     return pa_mainloop_get_retval(m->real_mainloop);
diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h
index 79c91eff..4dbc2d20 100644
--- a/src/pulse/thread-mainloop.h
+++ b/src/pulse/thread-mainloop.h
@@ -299,7 +299,7 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m);
 
 /** Return the return value as specified with the main loop's
  * pa_mainloop_quit() routine. */
-int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m);
+int pa_threaded_mainloop_get_retval(const pa_threaded_mainloop *m);
 
 /** Return the main loop abstraction layer vtable for this main loop.
  * There is no need to free this object as it is owned by the loop

commit 277c3735df5d67d01673083368f8918e0ec964cc
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 06:24:17 2018 +0100

    context: pa_context_get_state: constify

diff --git a/src/pulse/context.c b/src/pulse/context.c
index a63265df..adbeb153 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1058,7 +1058,7 @@ void pa_context_disconnect(pa_context *c) {
         pa_context_set_state(c, PA_CONTEXT_TERMINATED);
 }
 
-pa_context_state_t pa_context_get_state(pa_context *c) {
+pa_context_state_t pa_context_get_state(const pa_context *c) {
     pa_assert(c);
     pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
diff --git a/src/pulse/context.h b/src/pulse/context.h
index d79661f5..7a38ff23 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -196,7 +196,7 @@ int pa_context_errno(pa_context *c);
 int pa_context_is_pending(pa_context *c);
 
 /** Return the current context status */
-pa_context_state_t pa_context_get_state(pa_context *c);
+pa_context_state_t pa_context_get_state(const pa_context *c);
 
 /** Connect the context to the specified server. If server is NULL,
  * connect to the default server. This routine may but will not always

commit 326b749a78d043728c8ffefea158b68f5ebc353e
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Mon May 28 01:12:39 2018 +0100

    context: pa_context_get_protocol_version: constify

diff --git a/src/pulse/context.c b/src/pulse/context.c
index 8722f350..a63265df 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1331,7 +1331,7 @@ const char* pa_context_get_server(pa_context *c) {
     return c->server;
 }
 
-uint32_t pa_context_get_protocol_version(pa_context *c) {
+uint32_t pa_context_get_protocol_version(const pa_context *c) {
     return PA_PROTOCOL_VERSION;
 }
 
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 9d4c926e..d79661f5 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -236,7 +236,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su
 const char* pa_context_get_server(pa_context *c);
 
 /** Return the protocol version of the library. */
-uint32_t pa_context_get_protocol_version(pa_context *c);
+uint32_t pa_context_get_protocol_version(const pa_context *c);
 
 /** Return the protocol version of the connected server.
  * Returns PA_INVALID_INDEX on error. */

commit c0a70e8db81840c22eb361a0cb3d266547da2e8a
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sat May 26 23:50:55 2018 +0100

    context: pa_context_new_with_proplist: constify proplist param

diff --git a/src/pulse/context.c b/src/pulse/context.c
index e7695009..8722f350 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -125,7 +125,7 @@ static void reset_callbacks(pa_context *c) {
     c->ext_stream_restore.userdata = NULL;
 }
 
-pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
+pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, const pa_proplist *p) {
     pa_context *c;
     pa_mem_type_t type;
 
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 2cb0776e..9d4c926e 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -174,7 +174,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name);
 /** Instantiate a new connection context with an abstract mainloop API
  * and an application name, and specify the initial client property
  * list. \since 0.9.11 */
-pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist);
+pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, const pa_proplist *proplist);
 
 /** Decrease the reference counter of the context by one */
 void pa_context_unref(pa_context *c);

commit d851021cf59256a7e56d905ca55974153edd4a75
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 07:56:11 2018 +0100

    volume: pa_cvolume_get_position: constify

diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index ead54152..fc6ac8d2 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -911,7 +911,7 @@ pa_cvolume* pa_cvolume_set_position(
 }
 
 pa_volume_t pa_cvolume_get_position(
-        pa_cvolume *cv,
+        const pa_cvolume *cv,
         const pa_channel_map *map,
         pa_channel_position_t t) {
 
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index 2503c3f6..fe44b0bb 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -416,7 +416,7 @@ pa_cvolume* pa_cvolume_set_position(pa_cvolume *cv, const pa_channel_map *map, p
  * position. Will return 0 if there is no channel at the position
  * specified. You can check if a channel map includes a specific
  * position by calling pa_channel_map_has_position(). \since 0.9.16 */
-pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE;
+pa_volume_t pa_cvolume_get_position(const pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE;
 
 /** This goes through all channels in a and b and sets the
  * corresponding channel in dest to the greater volume of both. a, b

commit 3455d62e4906174e83bf0ea9af8b584808d3e779
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Fri Jun 1 11:24:01 2018 +0300

    alsa-mixer: make the mono mapping a fallback only
    
    If a sound card doesn't have the "front" device defined for it, we have
    to use the "hw" device for stereo. Not so long ago, the analog-stereo
    mapping had "hw:%f" in its device-strings and everything worked great,
    except that it caused trouble with the Intel HDMI LPE driver that uses
    the first "hw" device for HDMI, and we were incorrectly detecting it as
    an analog device. That problem was fixed in commit ea3ebd09, which
    removed "hw:%f" from analog-stereo and added a new stereo fallback
    mapping for "hw".
    
    Now the problem is that if a sound card doesn't have the "front" device
    defined for it, and it supports both mono and stereo, only the mono
    mapping is used, because the stereo mapping is only a fallback. This
    patch makes the mono mapping a fallback too, so the mono mapping is used
    only if there's absolutely nothing else that works.
    
    This can cause trouble at least in theory. Maybe someone actually wants
    to use mono output on a card that supports both mono and stereo. But
    that seems quite unlikely.

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index a07c4351..7d50fc7b 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -4060,6 +4060,7 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) {
     static const struct description_map well_known_descriptions[] = {
         { "analog-mono",            N_("Analog Mono") },
         { "analog-stereo",          N_("Analog Stereo") },
+        { "mono-fallback",          N_("Mono") },
         { "stereo-fallback",        N_("Stereo") },
         /* Note: Not translated to "Analog Stereo Input", because the source
          * name gets "Input" appended to it automatically, so adding "Input"
diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf
index f5093830..34c51bc5 100644
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -101,13 +101,6 @@
 [General]
 auto-profiles = yes
 
-[Mapping analog-mono]
-device-strings = hw:%f
-channel-map = mono
-paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono
-paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic
-priority = 7
-
 [Mapping analog-stereo]
 device-strings = front:%f
 channel-map = left,right
@@ -115,7 +108,7 @@ paths-output = analog-output analog-output-lineout analog-output-speaker analog-
 paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
 priority = 15
 
-# If everything else fails, try to use hw:0 as a stereo device.
+# If everything else fails, try to use hw:0 as a stereo device...
 [Mapping stereo-fallback]
 device-strings = hw:%f
 fallback = yes
@@ -124,6 +117,15 @@ paths-output = analog-output analog-output-lineout analog-output-speaker analog-
 paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
 priority = 1
 
+# ...and if even that fails, try to use hw:0 as a mono device.
+[Mapping mono-fallback]
+device-strings = hw:%f
+fallback = yes
+channel-map = mono
+paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic
+priority = 1
+
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe

commit 5c2d28f6dff160c51fd6627323377795bbcd35b2
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:15:14 2018 +0100

    scache: pa_context_play_sample_with_proplist: constify proplist param
    
    If the given proplist is NULL, the function creates a new (empty)
    proplist. That caused a compiler warning after the constification, which
    is why the new proplist is now created using a separate variable.

diff --git a/src/pulse/scache.c b/src/pulse/scache.c
index de7b4112..d393229b 100644
--- a/src/pulse/scache.c
+++ b/src/pulse/scache.c
@@ -205,7 +205,7 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char
     return o;
 }
 
-pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_proplist *p, pa_context_play_sample_cb_t cb, void *userdata) {
+pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *name, const char *dev, pa_volume_t volume, const pa_proplist *p, pa_context_play_sample_cb_t cb, void *userdata) {
     pa_operation *o;
     pa_tagstruct *t;
     uint32_t tag;
@@ -237,9 +237,9 @@ pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *na
     if (p)
         pa_tagstruct_put_proplist(t, p);
     else {
-        p = pa_proplist_new();
-        pa_tagstruct_put_proplist(t, p);
-        pa_proplist_free(p);
+        pa_proplist *empty_proplist = pa_proplist_new();
+        pa_tagstruct_put_proplist(t, empty_proplist);
+        pa_proplist_free(empty_proplist);
     }
 
     pa_pstream_send_tagstruct(c->pstream, t);
diff --git a/src/pulse/scache.h b/src/pulse/scache.h
index e4b82bc7..1be71983 100644
--- a/src/pulse/scache.h
+++ b/src/pulse/scache.h
@@ -116,7 +116,7 @@ pa_operation* pa_context_play_sample_with_proplist(
         const char *name                /**< Name of the sample to play */,
         const char *dev                 /**< Sink to play this sample on */,
         pa_volume_t volume              /**< Volume to play this sample with. Starting with 0.9.15 you may pass here PA_VOLUME_INVALID which will leave the decision about the volume to the server side, which is a good idea.  */ ,
-        pa_proplist *proplist           /**< Property list for this sound. The property list of the cached entry will have this merged into it. */,
+        const pa_proplist *proplist     /**< Property list for this sound. The property list of the cached entry will have this merged into it. */,
         pa_context_play_sample_cb_t cb  /**< Call this function after successfully starting playback, or NULL */,
         void *userdata                  /**< Userdata to pass to the callback */);
 

commit f17bcb0ad5f97d43530dd2f06922729270e331a1
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 05:14:04 2018 +0100

    scache: pa_context_play_sample_with_proplist: clarify proplist param
    
    Existing documentation was unclear about which property list would be the
    one changed (merged into), making it seem (along with the non-const
    proplist pointer param, which needs changing seperately), that the proplist
    object for which a pointer is given will be the one merged into, instead of
    the internal cached entry's proplist.

diff --git a/src/pulse/scache.h b/src/pulse/scache.h
index 2b85854e..e4b82bc7 100644
--- a/src/pulse/scache.h
+++ b/src/pulse/scache.h
@@ -116,7 +116,7 @@ pa_operation* pa_context_play_sample_with_proplist(
         const char *name                /**< Name of the sample to play */,
         const char *dev                 /**< Sink to play this sample on */,
         pa_volume_t volume              /**< Volume to play this sample with. Starting with 0.9.15 you may pass here PA_VOLUME_INVALID which will leave the decision about the volume to the server side, which is a good idea.  */ ,
-        pa_proplist *proplist           /**< Property list for this sound. The property list of the cached entry will be merged into this property list */,
+        pa_proplist *proplist           /**< Property list for this sound. The property list of the cached entry will have this merged into it. */,
         pa_context_play_sample_cb_t cb  /**< Call this function after successfully starting playback, or NULL */,
         void *userdata                  /**< Userdata to pass to the callback */);
 

commit 4af27c25d2a028ef31bfacf24fca2d054982683d
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 04:42:36 2018 +0100

    proplist: pa_proplist_equal: constify proplist pointers

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index a0913b10..91351159 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -674,7 +674,7 @@ int pa_proplist_isempty(const pa_proplist *p) {
     return pa_hashmap_isempty(MAKE_HASHMAP_CONST(p));
 }
 
-int pa_proplist_equal(pa_proplist *a, pa_proplist *b) {
+int pa_proplist_equal(const pa_proplist *a, const pa_proplist *b) {
     const void *key = NULL;
     struct property *a_prop = NULL;
     struct property *b_prop = NULL;
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 2c99976f..e50518b3 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -404,7 +404,7 @@ int pa_proplist_isempty(const pa_proplist *p);
 
 /** Return non-zero when a and b have the same keys and values.
  * \since 0.9.16 */
-int pa_proplist_equal(pa_proplist *a, pa_proplist *b);
+int pa_proplist_equal(const pa_proplist *a, const pa_proplist *b);
 
 PA_C_DECL_END
 

commit 2562446c4a01818dffcd675679d8409475301b4c
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 04:40:07 2018 +0100

    proplist: pa_proplist_[size|isempty]: constify proplist pointer

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index 4ad092d6..a0913b10 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -662,13 +662,13 @@ pa_proplist* pa_proplist_copy(const pa_proplist *p) {
     return copy;
 }
 
-unsigned pa_proplist_size(pa_proplist *p) {
+unsigned pa_proplist_size(const pa_proplist *p) {
     pa_assert(p);
 
     return pa_hashmap_size(MAKE_HASHMAP_CONST(p));
 }
 
-int pa_proplist_isempty(pa_proplist *p) {
+int pa_proplist_isempty(const pa_proplist *p) {
     pa_assert(p);
 
     return pa_hashmap_isempty(MAKE_HASHMAP_CONST(p));
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index c148c793..2c99976f 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -397,10 +397,10 @@ void pa_proplist_clear(pa_proplist *p);
 pa_proplist* pa_proplist_copy(const pa_proplist *p);
 
 /** Return the number of entries in the property list. \since 0.9.15 */
-unsigned pa_proplist_size(pa_proplist *p);
+unsigned pa_proplist_size(const pa_proplist *p);
 
 /** Returns 0 when the proplist is empty, positive otherwise \since 0.9.15 */
-int pa_proplist_isempty(pa_proplist *p);
+int pa_proplist_isempty(const pa_proplist *p);
 
 /** Return non-zero when a and b have the same keys and values.
  * \since 0.9.16 */

commit 5a146049df065d22006b0b72393666976603410c
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 04:35:33 2018 +0100

    proplist: pa_proplist_contains: constify proplist pointer

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index 75500246..4ad092d6 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -632,7 +632,7 @@ fail:
     return NULL;
 }
 
-int pa_proplist_contains(pa_proplist *p, const char *key) {
+int pa_proplist_contains(const pa_proplist *p, const char *key) {
     pa_assert(p);
     pa_assert(key);
 
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index f7a42826..c148c793 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -387,7 +387,7 @@ pa_proplist *pa_proplist_from_string(const char *str);
 
 /** Returns 1 if an entry for the specified key exists in the
  * property list. Returns negative on error. \since 0.9.11 */
-int pa_proplist_contains(pa_proplist *p, const char *key);
+int pa_proplist_contains(const pa_proplist *p, const char *key);
 
 /** Remove all entries from the property list object. \since 0.9.11 */
 void pa_proplist_clear(pa_proplist *p);

commit 25b55284dba9a5c956b86cb94b6e5b83240d1fc1
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 04:31:49 2018 +0100

    proplist: pa_proplist_to_string[_sep]: constify proplist pointer

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index f9aaea5b..75500246 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -379,7 +379,7 @@ const char *pa_proplist_iterate(const pa_proplist *p, void **state) {
     return prop->key;
 }
 
-char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep) {
+char *pa_proplist_to_string_sep(const pa_proplist *p, const char *sep) {
     const char *key;
     void *state = NULL;
     pa_strbuf *buf;
@@ -437,7 +437,7 @@ char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep) {
     return pa_strbuf_to_string_free(buf);
 }
 
-char *pa_proplist_to_string(pa_proplist *p) {
+char *pa_proplist_to_string(const pa_proplist *p) {
     char *s, *t;
 
     s = pa_proplist_to_string_sep(p, "\n");
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 9e0f706e..f7a42826 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -374,12 +374,12 @@ const char *pa_proplist_iterate(const pa_proplist *p, void **state);
  * works very much like pa_proplist_to_string_sep() and uses a newline
  * as separator and appends one final one. Call pa_xfree() on the
  * result. \since 0.9.11 */
-char *pa_proplist_to_string(pa_proplist *p);
+char *pa_proplist_to_string(const pa_proplist *p);
 
 /** Format the property list nicely as a human readable string and
  * choose the separator. Call pa_xfree() on the result. \since
  * 0.9.15 */
-char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep);
+char *pa_proplist_to_string_sep(const pa_proplist *p, const char *sep);
 
 /** Allocate a new property list and assign key/value from a human
  * readable string. \since 0.9.15 */

commit 6161e106c01412838feaeefa1e6d29257d18bc02
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 03:04:43 2018 +0100

    context: pa_context_proplist_update: constify proplist pointer

diff --git a/src/pulse/context.c b/src/pulse/context.c
index 6adfc5a9..e7695009 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1369,7 +1369,7 @@ uint32_t pa_context_get_index(pa_context *c) {
     return c->client_index;
 }
 
-pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
+pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, const pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
     pa_operation *o;
     pa_tagstruct *t;
     uint32_t tag;
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 9b96f8ce..2cb0776e 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -247,7 +247,7 @@ uint32_t pa_context_get_server_protocol_version(pa_context *c);
  * initially via pa_context_new_with_proplist() as possible instead a
  * posteriori with this function, since that information may then be
  * used to route streams of the client to the right device. \since 0.9.11 */
-pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata);
+pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, const pa_proplist *p, pa_context_success_cb_t cb, void *userdata);
 
 /** Update the property list of the client, remove entries. \since 0.9.11 */
 pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata);

commit 887150530acbe6f8f106c7456cb6251d655661e7
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 03:02:30 2018 +0100

    tagstruct: pa_tagstruct_put_format_info: constify format pointer

diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
index 50168717..6e9c7d15 100644
--- a/src/pulsecore/tagstruct.c
+++ b/src/pulsecore/tagstruct.c
@@ -334,7 +334,7 @@ void pa_tagstruct_put_proplist(pa_tagstruct *t, const pa_proplist *p) {
     pa_tagstruct_puts(t, NULL);
 }
 
-void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f) {
+void pa_tagstruct_put_format_info(pa_tagstruct *t, const pa_format_info *f) {
     pa_assert(t);
     pa_assert(f);
 
diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
index 9236490a..dcb51cbf 100644
--- a/src/pulsecore/tagstruct.h
+++ b/src/pulsecore/tagstruct.h
@@ -83,7 +83,7 @@ void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map);
 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume);
 void pa_tagstruct_put_proplist(pa_tagstruct *t, const pa_proplist *p);
 void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t volume);
-void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f);
+void pa_tagstruct_put_format_info(pa_tagstruct *t, const pa_format_info *f);
 
 int pa_tagstruct_get(pa_tagstruct *t, ...);
 

commit e8c32998f76e3ef7ec3fdea448d0f46eb819da55
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 03:01:14 2018 +0100

    tagstruct: pa_tagstruct_put_proplist: constify proplist pointer

diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
index 8a29957b..50168717 100644
--- a/src/pulsecore/tagstruct.c
+++ b/src/pulsecore/tagstruct.c
@@ -310,7 +310,7 @@ void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t vol) {
     write_u32(t, vol);
 }
 
-void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p) {
+void pa_tagstruct_put_proplist(pa_tagstruct *t, const pa_proplist *p) {
     void *state = NULL;
     pa_assert(t);
     pa_assert(p);
diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
index 348c65d2..9236490a 100644
--- a/src/pulsecore/tagstruct.h
+++ b/src/pulsecore/tagstruct.h
@@ -81,7 +81,7 @@ void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv);
 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u);
 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map);
 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume);
-void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p);
+void pa_tagstruct_put_proplist(pa_tagstruct *t, const pa_proplist *p);
 void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t volume);
 void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f);
 

commit 58c3f9b67189e8268aa5e8426f461fef0595c494
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 04:10:53 2018 +0100

    proplist: pa_proplist_gets: constify proplist pointer

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index 0da127ef..f9aaea5b 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -272,7 +272,7 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb
     return 0;
 }
 
-const char *pa_proplist_gets(pa_proplist *p, const char *key) {
+const char *pa_proplist_gets(const pa_proplist *p, const char *key) {
     struct property *prop;
 
     pa_assert(p);
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 68900183..9e0f706e 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -311,7 +311,7 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb
  * the data is not valid UTF-8. Will return a NUL-terminated string in
  * an internally allocated buffer. The caller should make a copy of
  * the data before accessing the property list again. \since 0.9.11 */
-const char *pa_proplist_gets(pa_proplist *p, const char *key);
+const char *pa_proplist_gets(const pa_proplist *p, const char *key);
 
 /** Store the value for the specified key in \a data. Will store a
  * NUL-terminated string for string entries. The \a data pointer returned will

commit cc063264e69e20ed2fe44d69987d0404cc945e8c
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 02:59:12 2018 +0100

    proplist: pa_proplist_get: constify proplist pointer

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index 37877b4e..0da127ef 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -299,7 +299,7 @@ const char *pa_proplist_gets(pa_proplist *p, const char *key) {
     return (char*) prop->value;
 }
 
-int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes) {
+int pa_proplist_get(const pa_proplist *p, const char *key, const void **data, size_t *nbytes) {
     struct property *prop;
 
     pa_assert(p);
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 14139a7e..68900183 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -318,7 +318,7 @@ const char *pa_proplist_gets(pa_proplist *p, const char *key);
  * point to an internally allocated buffer. The caller should make a
  * copy of the data before the property list is accessed again.
  * Returns zero on success, negative on error. \since 0.9.11 */
-int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes);
+int pa_proplist_get(const pa_proplist *p, const char *key, const void **data, size_t *nbytes);
 
 /** Update mode enum for pa_proplist_update(). \since 0.9.11 */
 typedef enum pa_update_mode {

commit 5d101fd2e2cdeb064b1788f9d3a3c316138404f2
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 02:45:47 2018 +0100

    proplist: pa_proplist_iterate: constify proplist pointer

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index 328d3ad2..37877b4e 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -370,7 +370,7 @@ int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
     return n;
 }
 
-const char *pa_proplist_iterate(pa_proplist *p, void **state) {
+const char *pa_proplist_iterate(const pa_proplist *p, void **state) {
     struct property *prop;
 
     if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP_CONST(p), state, NULL)))
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index cec3b357..14139a7e 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -368,7 +368,7 @@ int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]);
  * current entry. On each invocation this function will return the
  * key string for the next entry. The keys in the property list do not
  * have any particular order. \since 0.9.11 */
-const char *pa_proplist_iterate(pa_proplist *p, void **state);
+const char *pa_proplist_iterate(const pa_proplist *p, void **state);
 
 /** Format the property list nicely as a human readable string. This
  * works very much like pa_proplist_to_string_sep() and uses a newline

commit e82506f08d52481e690d17255bb27bd126c619c4
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 02:41:54 2018 +0100

    proplist: add and use const version of MAKE_HASHMAP macro

diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index d8c64044..328d3ad2 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -40,6 +40,7 @@ struct property {
 };
 
 #define MAKE_HASHMAP(p) ((pa_hashmap*) (p))
+#define MAKE_HASHMAP_CONST(p) ((const pa_hashmap*) (p))
 #define MAKE_PROPLIST(p) ((pa_proplist*) (p))
 
 int pa_proplist_key_valid(const char *key) {
@@ -83,7 +84,7 @@ int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) {
     if (!pa_proplist_key_valid(key) || !pa_utf8_valid(value))
         return -1;
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), key))) {
         prop = pa_xnew(struct property, 1);
         prop->key = pa_xstrdup(key);
         add = true;
@@ -118,7 +119,7 @@ static int proplist_setn(pa_proplist *p, const char *key, size_t key_length, con
         return -1;
     }
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), k))) {
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), k))) {
         prop = pa_xnew(struct property, 1);
         prop->key = k;
         add = true;
@@ -181,7 +182,7 @@ static int proplist_sethex(pa_proplist *p, const char *key, size_t key_length, c
 
     pa_xfree(v);
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), k))) {
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), k))) {
         prop = pa_xnew(struct property, 1);
         prop->key = k;
         add = true;
@@ -221,7 +222,7 @@ int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) {
     if (!pa_utf8_valid(v))
         goto fail;
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), key))) {
         prop = pa_xnew(struct property, 1);
         prop->key = pa_xstrdup(key);
         add = true;
@@ -252,7 +253,7 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb
     if (!pa_proplist_key_valid(key))
         return -1;
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), key))) {
         prop = pa_xnew(struct property, 1);
         prop->key = pa_xstrdup(key);
         add = true;
@@ -280,7 +281,7 @@ const char *pa_proplist_gets(pa_proplist *p, const char *key) {
     if (!pa_proplist_key_valid(key))
         return NULL;
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), key)))
         return NULL;
 
     if (prop->nbytes <= 0)
@@ -309,7 +310,7 @@ int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *
     if (!pa_proplist_key_valid(key))
         return -1;
 
-    if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
+    if (!(prop = pa_hashmap_get(MAKE_HASHMAP_CONST(p), key)))
         return -1;
 
     *data = prop->value;
@@ -329,9 +330,7 @@ void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, const pa_proplist
     if (mode == PA_UPDATE_SET)
         pa_proplist_clear(p);
 
-    /* MAKE_HASHMAP turns the const pointer into a non-const pointer, but
-     * that's ok, because we don't modify the hashmap contents. */
-    while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL))) {
+    while ((prop = pa_hashmap_iterate(MAKE_HASHMAP_CONST(other), &state, NULL))) {
 
         if (mode == PA_UPDATE_MERGE && pa_proplist_contains(p, prop->key))
             continue;
@@ -374,7 +373,7 @@ int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
 const char *pa_proplist_iterate(pa_proplist *p, void **state) {
     struct property *prop;
 
-    if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP(p), state, NULL)))
+    if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP_CONST(p), state, NULL)))
         return NULL;
 
     return prop->key;
@@ -640,7 +639,7 @@ int pa_proplist_contains(pa_proplist *p, const char *key) {
     if (!pa_proplist_key_valid(key))
         return -1;
 
-    if (!(pa_hashmap_get(MAKE_HASHMAP(p), key)))
+    if (!(pa_hashmap_get(MAKE_HASHMAP_CONST(p), key)))
         return 0;
 
     return 1;
@@ -666,13 +665,13 @@ pa_proplist* pa_proplist_copy(const pa_proplist *p) {
 unsigned pa_proplist_size(pa_proplist *p) {
     pa_assert(p);
 
-    return pa_hashmap_size(MAKE_HASHMAP(p));
+    return pa_hashmap_size(MAKE_HASHMAP_CONST(p));
 }
 
 int pa_proplist_isempty(pa_proplist *p) {
     pa_assert(p);
 
-    return pa_hashmap_isempty(MAKE_HASHMAP(p));
+    return pa_hashmap_isempty(MAKE_HASHMAP_CONST(p));
 }
 
 int pa_proplist_equal(pa_proplist *a, pa_proplist *b) {
@@ -690,8 +689,8 @@ int pa_proplist_equal(pa_proplist *a, pa_proplist *b) {
     if (pa_proplist_size(a) != pa_proplist_size(b))
         return 0;
 
-    while ((a_prop = pa_hashmap_iterate(MAKE_HASHMAP(a), &state, &key))) {
-        if (!(b_prop = pa_hashmap_get(MAKE_HASHMAP(b), key)))
+    while ((a_prop = pa_hashmap_iterate(MAKE_HASHMAP_CONST(a), &state, &key))) {
+        if (!(b_prop = pa_hashmap_get(MAKE_HASHMAP_CONST(b), key)))
             return 0;
 
         if (a_prop->nbytes != b_prop->nbytes)

commit b757a2de5ba6468a7a79f7f67cd9eb65ea748148
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 02:57:12 2018 +0100

    hashmap: constify pointer of pa_hashmap_get
    
    relies upon the same having just been done for the private hash_scan
    function

diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
index c03af3bc..c2fc3f5e 100644
--- a/src/pulsecore/hashmap.c
+++ b/src/pulsecore/hashmap.c
@@ -173,7 +173,7 @@ int pa_hashmap_put(pa_hashmap *h, void *key, void *value) {
     return 0;
 }
 
-void* pa_hashmap_get(pa_hashmap *h, const void *key) {
+void* pa_hashmap_get(const pa_hashmap *h, const void *key) {
     unsigned hash;
     struct hashmap_entry *e;
 
diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h
index ea883765..c18a564f 100644
--- a/src/pulsecore/hashmap.h
+++ b/src/pulsecore/hashmap.h
@@ -45,7 +45,7 @@ void pa_hashmap_free(pa_hashmap*);
 int pa_hashmap_put(pa_hashmap *h, void *key, void *value);
 
 /* Return an entry from the hashmap */
-void* pa_hashmap_get(pa_hashmap *h, const void *key);
+void* pa_hashmap_get(const pa_hashmap *h, const void *key);
 
 /* Returns the data of the entry while removing */
 void* pa_hashmap_remove(pa_hashmap *h, const void *key);

commit d9f72d9f42e2dfb3cc3b55591763ece58236cdb1
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 02:56:11 2018 +0100

    hashmap: constify pointer of private hash_scan function
    
    paves the way for doing the same for pa_hashmap_get and users of it

diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
index 6477783e..c03af3bc 100644
--- a/src/pulsecore/hashmap.c
+++ b/src/pulsecore/hashmap.c
@@ -119,7 +119,7 @@ void pa_hashmap_free(pa_hashmap *h) {
     pa_xfree(h);
 }
 
-static struct hashmap_entry *hash_scan(pa_hashmap *h, unsigned hash, const void *key) {
+static struct hashmap_entry *hash_scan(const pa_hashmap *h, unsigned hash, const void *key) {
     struct hashmap_entry *e;
     pa_assert(h);
     pa_assert(hash < NBUCKETS);

commit 65450eea2c98c4bff37296da928026bf02160c77
Author: Lyndon Brown <jnqnfe at gmail.com>
Date:   Sun May 27 02:27:43 2018 +0100

    hashmap: constify hashmap ptr for various functions

diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
index 2385c55c..6477783e 100644
--- a/src/pulsecore/hashmap.c
+++ b/src/pulsecore/hashmap.c
@@ -231,7 +231,7 @@ void pa_hashmap_remove_all(pa_hashmap *h) {
     }
 }
 
-void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
+void *pa_hashmap_iterate(const pa_hashmap *h, void **state, const void **key) {
     struct hashmap_entry *e;
 
     pa_assert(h);
@@ -264,7 +264,7 @@ at_end:
     return NULL;
 }
 
-void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void **key) {
+void *pa_hashmap_iterate_backwards(const pa_hashmap *h, void **state, const void **key) {
     struct hashmap_entry *e;
 
     pa_assert(h);
@@ -297,7 +297,7 @@ at_beginning:
     return NULL;
 }
 
-void* pa_hashmap_first(pa_hashmap *h) {
+void* pa_hashmap_first(const pa_hashmap *h) {
     pa_assert(h);
 
     if (!h->iterate_list_head)
@@ -306,7 +306,7 @@ void* pa_hashmap_first(pa_hashmap *h) {
     return h->iterate_list_head->value;
 }
 
-void* pa_hashmap_last(pa_hashmap *h) {
+void* pa_hashmap_last(const pa_hashmap *h) {
     pa_assert(h);
 
     if (!h->iterate_list_tail)
@@ -329,13 +329,13 @@ void* pa_hashmap_steal_first(pa_hashmap *h) {
     return data;
 }
 
-unsigned pa_hashmap_size(pa_hashmap *h) {
+unsigned pa_hashmap_size(const pa_hashmap *h) {
     pa_assert(h);
 
     return h->n_entries;
 }
 
-bool pa_hashmap_isempty(pa_hashmap *h) {
+bool pa_hashmap_isempty(const pa_hashmap *h) {
     pa_assert(h);
 
     return h->n_entries == 0;
diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h
index b1027e75..ea883765 100644
--- a/src/pulsecore/hashmap.h
+++ b/src/pulsecore/hashmap.h
@@ -61,10 +61,10 @@ int pa_hashmap_remove_and_free(pa_hashmap *h, const void *key);
 void pa_hashmap_remove_all(pa_hashmap *h);
 
 /* Return the current number of entries of the hashmap */
-unsigned pa_hashmap_size(pa_hashmap *h);
+unsigned pa_hashmap_size(const pa_hashmap *h);
 
 /* Return true if the hashmap is empty */
-bool pa_hashmap_isempty(pa_hashmap *h);
+bool pa_hashmap_isempty(const pa_hashmap *h);
 
 /* May be used to iterate through the hashmap. Initially the opaque
    pointer *state has to be set to NULL. The hashmap may not be
@@ -72,19 +72,19 @@ bool pa_hashmap_isempty(pa_hashmap *h);
    via pa_hashmap_remove(). The key of the entry is returned in *key,
    if key is non-NULL. After the last entry in the hashmap NULL is
    returned. */
-void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key);
+void *pa_hashmap_iterate(const pa_hashmap *h, void **state, const void**key);
 
 /* Same as pa_hashmap_iterate() but goes backwards */
-void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void**key);
+void *pa_hashmap_iterate_backwards(const pa_hashmap *h, void **state, const void**key);
 
 /* Remove the oldest entry in the hashmap and return it */
 void *pa_hashmap_steal_first(pa_hashmap *h);
 
 /* Return the oldest entry in the hashmap */
-void* pa_hashmap_first(pa_hashmap *h);
+void* pa_hashmap_first(const pa_hashmap *h);
 
 /* Return the newest entry in the hashmap */
-void* pa_hashmap_last(pa_hashmap *h);
+void* pa_hashmap_last(const pa_hashmap *h);
 
 /* A macro to ease iteration through all entries */
 #define PA_HASHMAP_FOREACH(e, h, state) \

commit d0a9eabbac2714e8c981c2beed31172e8a356872
Author: Arun Raghavan <arun at arunraghavan.net>
Date:   Sun May 20 08:08:42 2018 +0530

    build-sys: Update meson.build based on recent changes
    
    Bump the protocol version, and drop (commented out) references to BlueZ
    4.

diff --git a/meson.build b/meson.build
index f215ce36..9308aa9f 100644
--- a/meson.build
+++ b/meson.build
@@ -12,7 +12,7 @@ pa_version_micro = version_split[2]
 pa_version_major_minor = pa_version_major + '.' + pa_version_minor
 
 pa_api_version = 12
-pa_protocol_version = 31
+pa_protocol_version = 33
 
 apiversion = '1.0'
 soversion = 0
diff --git a/src/modules/meson.build b/src/modules/meson.build
index 3d6b53fe..339f6d01 100644
--- a/src/modules/meson.build
+++ b/src/modules/meson.build
@@ -6,8 +6,6 @@ all_modules = [
   [ 'module-augment-properties', 'module-augment-properties.c' ],
   [ 'module-bluetooth-discover', 'bluetooth/module-bluetooth-discover.c' ],
   [ 'module-bluetooth-policy', 'bluetooth/module-bluetooth-policy.c' ],
-#  [ 'module-bluez4-device', 'bluetooth/module-bluez4-device.c' ],
-#  [ 'module-bluez4-discover', 'bluetooth/module-bluez4-discover.c' ],
 #  [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c' ],
 #  [ 'module-bluez5-discover', 'bluetooth/module-bluez5-discover.c' ],
 #  [ 'module-bonjour-publish', 'macosx/module-bonjour-publish.c' ],

commit ef094638f552a9cd8006a3f31da7d2c649104d5f
Author: Sangchul Lee <sangchul1011 at gmail.com>
Date:   Fri May 25 01:29:53 2018 +0900

    udev-detect, alsa-card: Adopt avoid resampling option from daemon.conf
    
    Previously, the "avoid-resampling" option of daemon.conf is to make the
    daemon try to use the stream sample rate if possible for all sinks or
    sources.
    
    This patch applies this option to module-udev-detect and module-alsa-card
    as a module argument in order to override the default value of daemon.conf.
    
    As a result, user can use this argument for more fine-grained control.
    e.g.) set it false in daemon.conf and set it true for module-udev-detect
    or a particular module-alsa-card in default.pa.(or vice versa)
    
    To set it, use "avoid_resampling=true or false" as the module argument.
    
    Signed-off-by: Sangchul Lee <sc11.lee at samsung.com>

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 8e1fa7b2..871c8292 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -2101,7 +2101,16 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark, rewind_safeguard;
     snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
     size_t frame_size;
-    bool use_mmap = true, b, use_tsched = true, d, ignore_dB = false, namereg_fail = false, deferred_volume = false, set_formats = false, fixed_latency_range = false;
+    bool use_mmap = true;
+    bool use_tsched = true;
+    bool ignore_dB = false;
+    bool namereg_fail = false;
+    bool deferred_volume = false;
+    bool set_formats = false;
+    bool fixed_latency_range = false;
+    bool b;
+    bool d;
+    bool avoid_resampling;
     pa_sink_new_data data;
     bool volume_is_set;
     bool mute_is_set;
@@ -2113,6 +2122,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 
     ss = m->core->default_sample_spec;
     map = m->core->default_channel_map;
+    avoid_resampling = m->core->avoid_resampling;
 
     /* Pick sample spec overrides from the mapping, if any */
     if (mapping) {
@@ -2369,6 +2379,13 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     }
     data.namereg_fail = namereg_fail;
 
+    if (pa_modargs_get_value_boolean(ma, "avoid_resampling", &avoid_resampling) < 0) {
+        pa_log("Failed to parse avoid_resampling argument.");
+        pa_sink_new_data_done(&data);
+        goto fail;
+    }
+    data.avoid_resampling = avoid_resampling;
+
     pa_sink_new_data_set_sample_spec(&data, &ss);
     pa_sink_new_data_set_channel_map(&data, &map);
     pa_sink_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 78b20abe..c32e7e98 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1795,7 +1795,15 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark;
     snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
     size_t frame_size;
-    bool use_mmap = true, b, use_tsched = true, d, ignore_dB = false, namereg_fail = false, deferred_volume = false, fixed_latency_range = false;
+    bool use_mmap = true;
+    bool use_tsched = true;
+    bool ignore_dB = false;
+    bool namereg_fail = false;
+    bool deferred_volume = false;
+    bool fixed_latency_range = false;
+    bool b;
+    bool d;
+    bool avoid_resampling;
     pa_source_new_data data;
     bool volume_is_set;
     bool mute_is_set;
@@ -1807,6 +1815,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 
     ss = m->core->default_sample_spec;
     map = m->core->default_channel_map;
+    avoid_resampling = m->core->avoid_resampling;
 
     /* Pick sample spec overrides from the mapping, if any */
     if (mapping) {
@@ -2046,6 +2055,13 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     }
     data.namereg_fail = namereg_fail;
 
+    if (pa_modargs_get_value_boolean(ma, "avoid_resampling", &avoid_resampling) < 0) {
+        pa_log("Failed to parse avoid_resampling argument.");
+        pa_source_new_data_done(&data);
+        goto fail;
+    }
+    data.avoid_resampling = avoid_resampling;
+
     pa_source_new_data_set_sample_spec(&data, &ss);
     pa_source_new_data_set_channel_map(&data, &map);
     pa_source_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index ab81ef9c..041d5312 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -68,6 +68,7 @@ PA_MODULE_USAGE(
         "profile_set=<profile set configuration file> "
         "paths_dir=<directory containing the path configuration files> "
         "use_ucm=<load use case manager> "
+        "avoid_resampling=<use stream original sample rate if possible?> "
 );
 
 static const char* const valid_modargs[] = {
@@ -95,6 +96,7 @@ static const char* const valid_modargs[] = {
     "profile_set",
     "paths_dir",
     "use_ucm",
+    "avoid_resampling",
     NULL
 };
 
diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c
index beac9d42..d119f96a 100644
--- a/src/modules/module-udev-detect.c
+++ b/src/modules/module-udev-detect.c
@@ -46,7 +46,8 @@ PA_MODULE_USAGE(
         "fixed_latency_range=<disable latency range changes on underrun?> "
         "ignore_dB=<ignore dB information from the device?> "
         "deferred_volume=<syncronize sw and hw volume changes in IO-thread?> "
-        "use_ucm=<use ALSA UCM for card configuration?>");
+        "use_ucm=<use ALSA UCM for card configuration?> "
+        "avoid_resampling=<use stream original sample rate if possible?>");
 
 struct device {
     char *path;
@@ -67,6 +68,7 @@ struct userdata {
     bool ignore_dB:1;
     bool deferred_volume:1;
     bool use_ucm:1;
+    bool avoid_resampling:1;
 
     uint32_t tsched_buffer_size;
 
@@ -85,6 +87,7 @@ static const char* const valid_modargs[] = {
     "ignore_dB",
     "deferred_volume",
     "use_ucm",
+    "avoid_resampling",
     NULL
 };
 
@@ -401,6 +404,7 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
                      "ignore_dB=%s "
                      "deferred_volume=%s "
                      "use_ucm=%s "
+                     "avoid_resampling=%s "
                      "card_properties=\"module-udev-detect.discovered=1\"",
                      path_get_card_id(path),
                      n,
@@ -409,7 +413,8 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
                      pa_yes_no(u->fixed_latency_range),
                      pa_yes_no(u->ignore_dB),
                      pa_yes_no(u->deferred_volume),
-                     pa_yes_no(u->use_ucm));
+                     pa_yes_no(u->use_ucm),
+                     pa_yes_no(u->avoid_resampling));
     pa_xfree(n);
 
     if (u->tsched_buffer_size_valid)
@@ -682,6 +687,7 @@ int pa__init(pa_module *m) {
     int fd;
     bool use_tsched = true, fixed_latency_range = false, ignore_dB = false, deferred_volume = m->core->deferred_volume;
     bool use_ucm = true;
+    bool avoid_resampling;
 
     pa_assert(m);
 
@@ -734,6 +740,13 @@ int pa__init(pa_module *m) {
     }
     u->use_ucm = use_ucm;
 
+    avoid_resampling = m->core->avoid_resampling;
+    if (pa_modargs_get_value_boolean(ma, "avoid_resampling", &avoid_resampling) < 0) {
+        pa_log("Failed to parse avoid_resampling= argument.");
+        goto fail;
+    }
+    u->avoid_resampling = avoid_resampling;
+
     if (!(u->udev = udev_new())) {
         pa_log("Failed to initialize udev library.");
         goto fail;
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 38e8e50d..d617d27f 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -271,6 +271,8 @@ pa_sink* pa_sink_new(
     else
         s->alternate_sample_rate = s->core->alternate_sample_rate;
 
+    s->avoid_resampling = data->avoid_resampling;
+
     s->inputs = pa_idxset_new(NULL, NULL);
     s->n_corked = 0;
     s->input_to_master = NULL;
@@ -1444,7 +1446,7 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     pa_sink_input *i;
     bool default_rate_is_usable = false;
     bool alternate_rate_is_usable = false;
-    bool avoid_resampling = s->core->avoid_resampling;
+    bool avoid_resampling = s->avoid_resampling;
 
     /* We currently only try to reconfigure the sample rate */
 
@@ -1512,7 +1514,7 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, bool passthrough) {
     if (!passthrough && pa_sink_used_by(s) > 0)
         return -1;
 
-    pa_log_debug("Suspending sink %s due to changing format.", s->name);
+    pa_log_debug("Suspending sink %s due to changing format, desired rate = %u", s->name, desired_spec.rate);
     pa_sink_suspend(s, true, PA_SUSPEND_INTERNAL);
 
     if (s->reconfigure(s, &desired_spec, passthrough) >= 0) {
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index abf2d924..638d5069 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -83,6 +83,7 @@ struct pa_sink {
     pa_channel_map channel_map;
     uint32_t default_sample_rate;
     uint32_t alternate_sample_rate;
+    bool avoid_resampling:1;
 
     pa_idxset *inputs;
     unsigned n_corked;
@@ -376,6 +377,7 @@ typedef struct pa_sink_new_data {
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
     uint32_t alternate_sample_rate;
+    bool avoid_resampling:1;
     pa_cvolume volume;
     bool muted:1;
 
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 02ae87a8..dac085ce 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -258,6 +258,8 @@ pa_source* pa_source_new(
     else
         s->alternate_sample_rate = s->core->alternate_sample_rate;
 
+    s->avoid_resampling = data->avoid_resampling;
+
     s->outputs = pa_idxset_new(NULL, NULL);
     s->n_corked = 0;
     s->monitor_of = NULL;
@@ -1025,7 +1027,7 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
     uint32_t alternate_rate = s->alternate_sample_rate;
     bool default_rate_is_usable = false;
     bool alternate_rate_is_usable = false;
-    bool avoid_resampling = s->core->avoid_resampling;
+    bool avoid_resampling = s->avoid_resampling;
 
     /* We currently only try to reconfigure the sample rate */
 
@@ -1093,7 +1095,7 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
     if (!passthrough && pa_source_used_by(s) > 0)
         return -1;
 
-    pa_log_debug("Suspending source %s due to changing the sample rate.", s->name);
+    pa_log_debug("Suspending source %s due to changing the sample rate to %u", s->name, desired_spec.rate);
     pa_source_suspend(s, true, PA_SUSPEND_INTERNAL);
 
     if (s->reconfigure)
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index b0fa608d..f89a0c87 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -84,6 +84,7 @@ struct pa_source {
     pa_channel_map channel_map;
     uint32_t default_sample_rate;
     uint32_t alternate_sample_rate;
+    bool avoid_resampling:1;
 
     pa_idxset *outputs;
     unsigned n_corked;
@@ -314,6 +315,7 @@ typedef struct pa_source_new_data {
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
     uint32_t alternate_sample_rate;
+    bool avoid_resampling:1;
     pa_cvolume volume;
     bool muted:1;
 

commit 3b2a5bdc106fcdca8653a5d36470958d29a542b8
Author: Nazar Mokrynskyi <nazar at mokrynskyi.com>
Date:   Wed May 9 01:51:23 2018 +0300

    alsa-mixer: More output modes for SB Omni Surround 5.1 and cleanup
    
    There are only stereo and 5.1 output modes supported natively on this
    sound card, but with this config more modes like 2.1, 4.0, 4.1 and 5.0
    are now exposed. Also profiles list is cleaner now with all profiles
    explicitly specified.
    
    Last thing is removed support for microphone on Linux kernels older than
    4.3-rc1, which shouldn't be an issue with future version of PulseAudio
    likely be installed on newer kernels anyway.
    
    Signed-off-by: Nazar Mokrynskyi <nazar at mokrynskyi.com>

diff --git a/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf b/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf
index d5922da7..11985bb3 100644
--- a/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf
+++ b/src/modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf
@@ -15,44 +15,98 @@
 
 ; Creative Sound Blaster Omni Surround 5.1
 ;
-; This sound card have Mic/Line in at hw:%f,1,0 on Linux prior to 4.3-rc1,
-; but starting from Linux 4.3-rc1 Mic/Line is at hw:%f,0,0
-; This config supports both cases.
-; Also by default there are some non-existing (physically) inputs
-; and outputs that are not present here.
-; And finally officially supported modes are stereo and 5.1 + stereo S/PDIF,
-; so only these modes included.
+; This config supports Linux 4.3-rc1+.
+; By default there are some non-existing (physically) inputs and outputs that
+; are not present in this config.
+; Also in addition to natively supported modes (such as stereo, 5.1 and stereo
+; S/PDIF) following useful output modes are added: 2.1, 4.0, 4.1 and 5.0.
+;
+; NOTE: in 2.1 and 4.1 physical LFE output will be different than in 5.1 mode.
 ;
 ; See default.conf for an explanation on the directives used here.
 
 [General]
-auto-profiles = yes
+auto-profiles = no
+
+[Mapping analog-stereo-input]
+device-strings = hw:%f
+channel-map = left,right
+paths-input = analog-input-mic analog-input-linein
+direction = input
 
 [Mapping analog-stereo-output]
 device-strings = front:%f
 channel-map = left,right
 paths-output = analog-output
-priority = 10
 direction = output
 
-; Linux 4.2.x- have microphone input as device 1
-; While Linux 4.3-rc1+ have microphone input as device 0
-[Mapping analog-stereo-input]
-device-strings = hw:%f hw:%f,1,0
-paths-input = analog-input-mic analog-input-linein
-channel-map = left,right
-direction = input
+[Mapping analog-surround-21]
+device-strings = surround51:%f
+channel-map = front-left,front-right,lfe
+paths-output = analog-output
+direction = output
+
+[Mapping analog-surround-40]
+device-strings = surround51:%f
+channel-map = front-left,front-right,rear-left,rear-right
+paths-output = analog-output
+direction = output
+
+[Mapping analog-surround-41]
+device-strings = surround51:%f
+channel-map = front-left,front-right,rear-left,rear-right,lfe
+paths-output = analog-output
+direction = output
+
+[Mapping analog-surround-50]
+device-strings = surround51:%f
+channel-map = front-left,front-right,rear-left,rear-right,front-center
+paths-output = analog-output
+direction = output
 
 [Mapping analog-surround-51]
 device-strings = surround51:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
 paths-output = analog-output
-priority = 9
 direction = output
 
 [Mapping iec958-stereo]
 device-strings = iec958:%f
 channel-map = left,right
 paths-output = iec958-stereo-output
-priority = 5
 direction = output
+
+[Profile output:analog-stereo-output+input:analog-stereo-input]
+output-mappings = analog-stereo-output
+input-mappings = analog-stereo-input
+priority = 7
+
+[Profile output:analog-surround-21+input:analog-stereo-input]
+output-mappings = analog-surround-21
+input-mappings = analog-stereo-input
+priority = 6
+
+[Profile output:analog-surround-40+input:analog-stereo-input]
+output-mappings = analog-surround-40
+input-mappings = analog-stereo-input
+priority = 5
+
+[Profile output:analog-surround-41+input:analog-stereo-input]
+output-mappings = analog-surround-41
+input-mappings = analog-stereo-input
+priority = 4
+
+[Profile output:analog-surround-50+input:analog-stereo-input]
+output-mappings = analog-surround-50
+input-mappings = analog-stereo-input
+priority = 3
+
+[Profile output:analog-surround-51+input:analog-stereo-input]
+output-mappings = analog-surround-51
+input-mappings = analog-stereo-input
+priority = 2
+
+[Profile output:iec958-stereo+input:analog-stereo-input]
+output-mappings = iec958-stereo
+input-mappings = analog-stereo-input
+priority = 1

commit 50a7fb1ce3c61ebcf1a88e5d51381fe591087a30
Author: Arun Raghavan <arun at arunraghavan.net>
Date:   Thu May 10 14:31:36 2018 +0530

    map-file: Fix typo while adding pa_thread_make_realtime

diff --git a/src/map-file b/src/map-file
index 7c1216ea..902ce2fd 100644
--- a/src/map-file
+++ b/src/map-file
@@ -225,7 +225,7 @@ pa_mainloop_run;
 pa_mainloop_set_poll_func;
 pa_mainloop_wakeup;
 pa_msleep;
-pa_thread_make_realtime
+pa_thread_make_realtime;
 pa_operation_cancel;
 pa_operation_get_state;
 pa_operation_ref;

commit 55525d75b85960d593ff071d81809ae93716bb91
Author: Arun Raghavan <arun at arunraghavan.net>
Date:   Fri May 4 19:18:15 2018 +0530

    null-sink,null-source: Use realtime scheduling if possible
    
    We do this on other sink/source modules, and in general it makes sense
    to do so here as well.

diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index 6cbe588d..fdab1121 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -28,6 +28,7 @@
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
+#include <pulse/util.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/i18n.h>
@@ -206,6 +207,9 @@ static void thread_func(void *userdata) {
 
     pa_log_debug("Thread starting up");
 
+    if (u->core->realtime_scheduling)
+        pa_thread_make_realtime(u->core->realtime_priority);
+
     pa_thread_mq_install(&u->thread_mq);
 
     u->timestamp = pa_rtclock_now();
diff --git a/src/modules/module-null-source.c b/src/modules/module-null-source.c
index 0e4c8d2f..251d0f52 100644
--- a/src/modules/module-null-source.c
+++ b/src/modules/module-null-source.c
@@ -29,6 +29,7 @@
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
+#include <pulse/util.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-util.h>
@@ -132,6 +133,9 @@ static void thread_func(void *userdata) {
 
     pa_log_debug("Thread starting up");
 
+    if (u->core->realtime_scheduling)
+        pa_thread_make_realtime(u->core->realtime_priority);
+
     pa_thread_mq_install(&u->thread_mq);
 
     u->timestamp = pa_rtclock_now();

commit 78b6c4fe927e076bb53b2b8e7123679763618295
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Sat May 5 16:01:06 2018 +0300

    core-format: fix TrueHD and DTS-HD channel maps
    
    Since these formats use 8 channels, the channel map needs to be
    configured to 8 channels as well.

diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index c3db2678..862a74b5 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -227,13 +227,21 @@ int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *
 
     ss->format = PA_SAMPLE_S16LE;
     if ((f->encoding == PA_ENCODING_TRUEHD_IEC61937) ||
-	(f->encoding == PA_ENCODING_DTSHD_IEC61937))
-	ss->channels = 8;
-    else
-	ss->channels = 2;
-
-    if (map)
-        pa_channel_map_init_stereo(map);
+        (f->encoding == PA_ENCODING_DTSHD_IEC61937)) {
+        ss->channels = 8;
+        if (map) {
+            /* We use the ALSA mapping, because most likely we will be using an
+             * ALSA sink. This doesn't really matter anyway, though, because
+             * the channel map doesn't affect anything with passthrough
+             * streams. The channel map just needs to be consistent with the
+             * sample spec's channel count. */
+            pa_channel_map_init_auto(map, 8, PA_CHANNEL_MAP_ALSA);
+        }
+    } else {
+        ss->channels = 2;
+        if (map)
+            pa_channel_map_init_stereo(map);
+    }
 
     pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID);
     ss->rate = (uint32_t) rate;

commit 878ef440797f0fe319dcb1e866c29cec39b8a36d
Author: Arun Raghavan <arun at arunraghavan.net>
Date:   Sat Apr 21 09:45:26 2018 +0530

    core: Expose API to elevate a thread to realtime priority
    
    This should make it easier for clients to elevate their audio threads to
    real time priority without having to dig through much through specific
    system internals.

diff --git a/src/map-file b/src/map-file
index 9b6cba22..7c1216ea 100644
--- a/src/map-file
+++ b/src/map-file
@@ -225,6 +225,7 @@ pa_mainloop_run;
 pa_mainloop_set_poll_func;
 pa_mainloop_wakeup;
 pa_msleep;
+pa_thread_make_realtime
 pa_operation_cancel;
 pa_operation_get_state;
 pa_operation_ref;
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 51d2d465..8e1fa7b2 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -33,6 +33,7 @@
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
+#include <pulse/util.h>
 #include <pulse/volume.h>
 #include <pulse/xmalloc.h>
 #include <pulse/internal.h>
@@ -1780,7 +1781,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 54a32efb..78b20abe 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -29,6 +29,7 @@
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
+#include <pulse/util.h>
 #include <pulse/volume.h>
 #include <pulse/xmalloc.h>
 
@@ -1504,7 +1505,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 351ad127..9dbdca31 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -30,6 +30,7 @@
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
 #include <pulse/utf8.h>
+#include <pulse/util.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-rtclock.h>
@@ -1500,7 +1501,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("IO Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/jack/module-jack-sink.c b/src/modules/jack/module-jack-sink.c
index eb1d1b15..effa0dd0 100644
--- a/src/modules/jack/module-jack-sink.c
+++ b/src/modules/jack/module-jack-sink.c
@@ -29,6 +29,7 @@
 
 #include <jack/jack.h>
 
+#include <pulse/util.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/sink.h>
@@ -224,7 +225,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
@@ -267,7 +268,7 @@ static void jack_init(void *arg) {
     pa_log_info("JACK thread starting up.");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority+4);
+        pa_thread_make_realtime(u->core->realtime_priority+4);
 }
 
 /* JACK Callback: This is called when JACK kicks us */
diff --git a/src/modules/jack/module-jack-source.c b/src/modules/jack/module-jack-source.c
index 43cb0e15..eaf2cd81 100644
--- a/src/modules/jack/module-jack-source.c
+++ b/src/modules/jack/module-jack-source.c
@@ -29,6 +29,7 @@
 
 #include <jack/jack.h>
 
+#include <pulse/util.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/source.h>
@@ -187,7 +188,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
@@ -225,7 +226,7 @@ static void jack_init(void *arg) {
     pa_log_info("JACK thread starting up.");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority+4);
+        pa_thread_make_realtime(u->core->realtime_priority+4);
 }
 
 static void jack_shutdown(void* arg) {
diff --git a/src/modules/macosx/module-coreaudio-device.c b/src/modules/macosx/module-coreaudio-device.c
index 149109d4..b9dffb93 100644
--- a/src/modules/macosx/module-coreaudio-device.c
+++ b/src/modules/macosx/module-coreaudio-device.c
@@ -722,7 +722,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->module->core->realtime_scheduling)
-        pa_make_realtime(u->module->core->realtime_priority);
+        pa_thread_make_realtime(u->module->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c
index f7649a36..b7dac804 100644
--- a/src/modules/module-combine-sink.c
+++ b/src/modules/module-combine-sink.c
@@ -26,6 +26,7 @@
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
+#include <pulse/util.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/macro.h>
@@ -319,7 +320,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority+1);
+        pa_thread_make_realtime(u->core->realtime_priority+1);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
index 240ed855..038aca11 100644
--- a/src/modules/module-solaris.c
+++ b/src/modules/module-solaris.c
@@ -650,7 +650,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c
index 08b44aff..f7ffdf75 100644
--- a/src/modules/module-waveout.c
+++ b/src/modules/module-waveout.c
@@ -252,7 +252,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index 6a70f9af..ed124cab 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -899,7 +899,7 @@ static void thread_func(void *userdata) {
     pa_log_debug("Thread starting up");
 
     if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
+        pa_thread_make_realtime(u->core->realtime_priority);
 
     pa_thread_mq_install(&u->thread_mq);
 
diff --git a/src/pulse/util.c b/src/pulse/util.c
index 54fe7a28..2be389b2 100644
--- a/src/pulse/util.c
+++ b/src/pulse/util.c
@@ -56,6 +56,7 @@
 #include <pulse/timeval.h>
 
 #include <pulsecore/socket.h>
+#include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/usergroup.h>
@@ -71,6 +72,29 @@
 static int _main() PA_GCC_WEAKREF(main);
 #endif
 
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+
+#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
+#define SCHED_RESET_ON_FORK 0x40000000
+#endif
+#endif
+
+#ifdef __APPLE__
+#include <mach/mach_init.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <sys/sysctl.h>
+#endif
+
+#ifdef HAVE_DBUS
+#include <pulsecore/rtkit.h>
+#endif
+
 char *pa_get_user_name(char *s, size_t l) {
     const char *p;
     char *name = NULL;
@@ -342,3 +366,155 @@ int pa_msleep(unsigned long t) {
 #error "Platform lacks a sleep function."
 #endif
 }
+
+#ifdef _POSIX_PRIORITY_SCHEDULING
+static int set_scheduler(int rtprio) {
+#ifdef HAVE_SCHED_H
+    struct sched_param sp;
+#ifdef HAVE_DBUS
+    int r;
+    long long rttime;
+#ifdef RLIMIT_RTTIME
+    struct rlimit rl;
+#endif
+    DBusError error;
+    DBusConnection *bus;
+
+    dbus_error_init(&error);
+#endif
+
+    pa_zero(sp);
+    sp.sched_priority = rtprio;
+
+#ifdef SCHED_RESET_ON_FORK
+    if (pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp) == 0) {
+        pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked.");
+        return 0;
+    }
+#endif
+
+    if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == 0) {
+        pa_log_debug("SCHED_RR worked.");
+        return 0;
+    }
+#endif  /* HAVE_SCHED_H */
+
+#ifdef HAVE_DBUS
+    /* Try to talk to RealtimeKit */
+
+    if (!(bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
+        pa_log("Failed to connect to system bus: %s", error.message);
+        dbus_error_free(&error);
+        errno = -EIO;
+        return -1;
+    }
+
+    /* We need to disable exit on disconnect because otherwise
+     * dbus_shutdown will kill us. See
+     * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */
+    dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+    rttime = rtkit_get_rttime_usec_max(bus);
+    if (rttime >= 0) {
+#ifdef RLIMIT_RTTIME
+        r = getrlimit(RLIMIT_RTTIME, &rl);
+
+        if (r >= 0 && (long long) rl.rlim_max > rttime) {
+            pa_log_info("Clamping rlimit-rttime to %lld for RealtimeKit", rttime);
+            rl.rlim_cur = rl.rlim_max = rttime;
+            r = setrlimit(RLIMIT_RTTIME, &rl);
+
+            if (r < 0)
+                pa_log("setrlimit() failed: %s", pa_cstrerror(errno));
+        }
+#endif
+        r = rtkit_make_realtime(bus, 0, rtprio);
+        dbus_connection_close(bus);
+        dbus_connection_unref(bus);
+
+        if (r >= 0) {
+            pa_log_debug("RealtimeKit worked.");
+            return 0;
+        }
+
+        errno = -r;
+    } else {
+        dbus_connection_close(bus);
+        dbus_connection_unref(bus);
+        errno = -rttime;
+    }
+
+#else
+    errno = 0;
+#endif
+
+    return -1;
+}
+#endif
+
+/* Make the current thread a realtime thread, and acquire the highest
+ * rtprio we can get that is less or equal the specified parameter. If
+ * the thread is already realtime, don't do anything. */
+int pa_thread_make_realtime(int rtprio) {
+
+#if defined(OS_IS_DARWIN)
+    struct thread_time_constraint_policy ttcpolicy;
+    uint64_t freq = 0;
+    size_t size = sizeof(freq);
+    int ret;
+
+    ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
+    if (ret < 0) {
+        pa_log_info("Unable to read CPU frequency, acquisition of real-time scheduling failed.");
+        return -1;
+    }
+
+    pa_log_debug("sysctl for hw.cpufrequency: %llu", freq);
+
+    /* See http://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html */
+    ttcpolicy.period = freq / 160;
+    ttcpolicy.computation = freq / 3300;
+    ttcpolicy.constraint = freq / 2200;
+    ttcpolicy.preemptible = 1;
+
+    ret = thread_policy_set(mach_thread_self(),
+                            THREAD_TIME_CONSTRAINT_POLICY,
+                            (thread_policy_t) &ttcpolicy,
+                            THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+    if (ret) {
+        pa_log_info("Unable to set real-time thread priority (%08x).", ret);
+        return -1;
+    }
+
+    pa_log_info("Successfully acquired real-time thread priority.");
+    return 0;
+
+#elif defined(_POSIX_PRIORITY_SCHEDULING)
+    int p;
+
+    if (set_scheduler(rtprio) >= 0) {
+        pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio);
+        return 0;
+    }
+
+    for (p = rtprio-1; p >= 1; p--)
+        if (set_scheduler(p) >= 0) {
+            pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
+            return 0;
+        }
+#elif defined(OS_IS_WIN32)
+    /* Windows only allows realtime scheduling to be set on a per process basis.
+     * Therefore, instead of making the thread realtime, just give it the highest non-realtime priority. */
+    if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) {
+        pa_log_info("Successfully enabled THREAD_PRIORITY_TIME_CRITICAL scheduling for thread.");
+        return 0;
+    }
+
+    pa_log_warn("SetThreadPriority() failed: 0x%08X", GetLastError());
+    errno = EPERM;
+#else
+    errno = ENOTSUP;
+#endif
+    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
+    return -1;
+}
diff --git a/src/pulse/util.h b/src/pulse/util.h
index e4a62da6..0717a73f 100644
--- a/src/pulse/util.h
+++ b/src/pulse/util.h
@@ -54,6 +54,12 @@ char *pa_path_get_filename(const char *p);
 /** Wait t milliseconds */
 int pa_msleep(unsigned long t);
 
+/** Make the calling thread realtime if we can. On Linux, this uses RealTimeKit
+ * if available and POSIX APIs otherwise (the latter applies to other UNIX
+ * variants as well). This is also implemented for macOS and Windows.
+ * \since 13.0 */
+int pa_thread_make_realtime(int rtprio);
+
 PA_C_DECL_END
 
 #endif
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 7f627539..367e767d 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -61,14 +61,6 @@
 #endif
 #endif
 
-#ifdef HAVE_SCHED_H
-#include <sched.h>
-
-#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
-#define SCHED_RESET_ON_FORK 0x40000000
-#endif
-#endif
-
 #ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
 #endif
@@ -109,15 +101,8 @@
 #include <samplerate.h>
 #endif
 
-#ifdef __APPLE__
-#include <mach/mach_init.h>
-#include <mach/thread_act.h>
-#include <mach/thread_policy.h>
-#include <sys/sysctl.h>
-#endif
-
 #ifdef HAVE_DBUS
-#include "rtkit.h"
+#include <pulsecore/rtkit.h>
 #endif
 
 #if defined(__linux__) && !defined(__ANDROID__)
@@ -697,158 +682,6 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
     return b;
 }
 
-#ifdef _POSIX_PRIORITY_SCHEDULING
-static int set_scheduler(int rtprio) {
-#ifdef HAVE_SCHED_H
-    struct sched_param sp;
-#ifdef HAVE_DBUS
-    int r;
-    long long rttime;
-#ifdef RLIMIT_RTTIME
-    struct rlimit rl;
-#endif
-    DBusError error;
-    DBusConnection *bus;
-
-    dbus_error_init(&error);
-#endif
-
-    pa_zero(sp);
-    sp.sched_priority = rtprio;
-
-#ifdef SCHED_RESET_ON_FORK
-    if (pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp) == 0) {
-        pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked.");
-        return 0;
-    }
-#endif
-
-    if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == 0) {
-        pa_log_debug("SCHED_RR worked.");
-        return 0;
-    }
-#endif  /* HAVE_SCHED_H */
-
-#ifdef HAVE_DBUS
-    /* Try to talk to RealtimeKit */
-
-    if (!(bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
-        pa_log("Failed to connect to system bus: %s", error.message);
-        dbus_error_free(&error);
-        errno = -EIO;
-        return -1;
-    }
-
-    /* We need to disable exit on disconnect because otherwise
-     * dbus_shutdown will kill us. See
-     * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */
-    dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
-    rttime = rtkit_get_rttime_usec_max(bus);
-    if (rttime >= 0) {
-#ifdef RLIMIT_RTTIME
-        r = getrlimit(RLIMIT_RTTIME, &rl);
-
-        if (r >= 0 && (long long) rl.rlim_max > rttime) {
-            pa_log_info("Clamping rlimit-rttime to %lld for RealtimeKit", rttime);
-            rl.rlim_cur = rl.rlim_max = rttime;
-            r = setrlimit(RLIMIT_RTTIME, &rl);
-
-            if (r < 0)
-                pa_log("setrlimit() failed: %s", pa_cstrerror(errno));
-        }
-#endif
-        r = rtkit_make_realtime(bus, 0, rtprio);
-        dbus_connection_close(bus);
-        dbus_connection_unref(bus);
-
-        if (r >= 0) {
-            pa_log_debug("RealtimeKit worked.");
-            return 0;
-        }
-
-        errno = -r;
-    } else {
-        dbus_connection_close(bus);
-        dbus_connection_unref(bus);
-        errno = -rttime;
-    }
-
-#else
-    errno = 0;
-#endif
-
-    return -1;
-}
-#endif
-
-/* Make the current thread a realtime thread, and acquire the highest
- * rtprio we can get that is less or equal the specified parameter. If
- * the thread is already realtime, don't do anything. */
-int pa_make_realtime(int rtprio) {
-
-#if defined(OS_IS_DARWIN)
-    struct thread_time_constraint_policy ttcpolicy;
-    uint64_t freq = 0;
-    size_t size = sizeof(freq);
-    int ret;
-
-    ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
-    if (ret < 0) {
-        pa_log_info("Unable to read CPU frequency, acquisition of real-time scheduling failed.");
-        return -1;
-    }
-
-    pa_log_debug("sysctl for hw.cpufrequency: %llu", freq);
-
-    /* See http://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html */
-    ttcpolicy.period = freq / 160;
-    ttcpolicy.computation = freq / 3300;
-    ttcpolicy.constraint = freq / 2200;
-    ttcpolicy.preemptible = 1;
-
-    ret = thread_policy_set(mach_thread_self(),
-                            THREAD_TIME_CONSTRAINT_POLICY,
-                            (thread_policy_t) &ttcpolicy,
-                            THREAD_TIME_CONSTRAINT_POLICY_COUNT);
-    if (ret) {
-        pa_log_info("Unable to set real-time thread priority (%08x).", ret);
-        return -1;
-    }
-
-    pa_log_info("Successfully acquired real-time thread priority.");
-    return 0;
-
-#elif defined(_POSIX_PRIORITY_SCHEDULING)
-    int p;
-
-    if (set_scheduler(rtprio) >= 0) {
-        pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio);
-        return 0;
-    }
-
-    for (p = rtprio-1; p >= 1; p--)
-        if (set_scheduler(p) >= 0) {
-            pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
-            return 0;
-        }
-#elif defined(OS_IS_WIN32)
-    /* Windows only allows realtime scheduling to be set on a per process basis.
-     * Therefore, instead of making the thread realtime, just give it the highest non-realtime priority. */
-    if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) {
-        pa_log_info("Successfully enabled THREAD_PRIORITY_TIME_CRITICAL scheduling for thread.");
-        return 0;
-    }
-
-    pa_log_warn("SetThreadPriority() failed: 0x%08X", GetLastError());
-    errno = EPERM;
-#else
-    errno = ENOTSUP;
-#endif
-    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
-    return -1;
-}
-
 #ifdef HAVE_SYS_RESOURCE_H
 static int set_nice(int nice_level) {
 #ifdef HAVE_DBUS
@@ -935,7 +768,7 @@ int pa_raise_priority(int nice_level) {
 }
 
 /* Reset the priority to normal, inverting the changes made by
- * pa_raise_priority() and pa_make_realtime()*/
+ * pa_raise_priority() and pa_thread_make_realtime()*/
 void pa_reset_priority(void) {
 #ifdef HAVE_SYS_RESOURCE_H
     struct sched_param sp;
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index e28b6aa7..32579739 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -81,7 +81,6 @@ char *pa_strlcpy(char *b, const char *s, size_t l);
 
 char *pa_parent_dir(const char *fn);
 
-int pa_make_realtime(int rtprio);
 int pa_raise_priority(int nice_level);
 void pa_reset_priority(void);
 
diff --git a/src/tests/lo-test-util.c b/src/tests/lo-test-util.c
index fae91a22..40002a2c 100644
--- a/src/tests/lo-test-util.c
+++ b/src/tests/lo-test-util.c
@@ -208,7 +208,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_READY: {
             pa_buffer_attr buffer_attr;
 
-            pa_make_realtime(4);
+            pa_thread_make_realtime(4);
 
             /* Create playback stream */
             buffer_attr.maxlength = -1;
diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c
index 7bd88080..56b5146c 100644
--- a/src/tests/rtstutter.c
+++ b/src/tests/rtstutter.c
@@ -57,7 +57,7 @@ static void work(void *p) {
 
     pa_log_notice("CPU%i: Created thread.", PA_PTR_TO_UINT(p));
 
-    pa_make_realtime(12);
+    pa_thread_make_realtime(12);
 
 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
 {

commit 651a3d108e5b4f1f0e5f19c508565c9fce290b6a
Author: Arun Raghavan <arun at arunraghavan.net>
Date:   Fri May 4 22:46:53 2018 +0530

    PROTOCOL: Bump to version 33
    
    Required for the addition of new pa_encoding_t values.

diff --git a/PROTOCOL b/PROTOCOL
index 546998b7..8117d004 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -420,6 +420,13 @@ memfd support only to 10.0+ clients.
 
 Check commit 451d1d676237c81 for further details.
 
+## v33, implemented by >= 13.0
+
+Added two values to the pa_encoding_t enum:
+
+    PA_ENCODING_TRUEHD_IEC61937 := 7
+    PA_ENCODING_DTSHD_IEC61937 := 8
+
 #### If you just changed the protocol, read this
 ## module-tunnel depends on the sink/source/sink-input/source-input protocol
 ## internals, so if you changed these, you might have broken module-tunnel.
diff --git a/configure.ac b/configure.ac
index 681d78cd..8890aa15 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,7 +40,7 @@ AC_SUBST(PA_MINOR, pa_minor)
 AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
 
 AC_SUBST(PA_API_VERSION, 12)
-AC_SUBST(PA_PROTOCOL_VERSION, 32)
+AC_SUBST(PA_PROTOCOL_VERSION, 33)
 
 # The stable ABI for client applications, for the version info x:y:z
 # always will hold y=z

commit cdeac178019ed3e73840702cb1223df5edd9df43
Author: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Date:   Tue Aug 15 12:24:12 2017 -0500

    format: Add support for Dolby TrueHD and DTS-HD HBR passthrough
    
    Add definitions and fixups for channel count
    
    Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 8474978d..07b4420e 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -47,6 +47,8 @@ static const char* const _encoding_str_table[]= {
     [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
     [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
     [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937",
+    [PA_ENCODING_TRUEHD_IEC61937] = "truehd-iec61937",
+    [PA_ENCODING_DTSHD_IEC61937] = "dtshd-iec61937",
     [PA_ENCODING_ANY] = "any",
 };
 
diff --git a/src/pulse/format.h b/src/pulse/format.h
index 2143bb51..584032fb 100644
--- a/src/pulse/format.h
+++ b/src/pulse/format.h
@@ -56,6 +56,12 @@ typedef enum pa_encoding {
     PA_ENCODING_MPEG2_AAC_IEC61937,
     /**< MPEG-2 AAC data encapsulated in IEC 61937 header/padding. \since 4.0 */
 
+    PA_ENCODING_TRUEHD_IEC61937,
+    /**< Dolby TrueHD data encapsulated in IEC 61937 header/padding. \since 13.0 */
+
+    PA_ENCODING_DTSHD_IEC61937,
+    /**< DTS-HD Master Audio encapsulated in IEC 61937 header/padding. \since 13.0 */
+
     PA_ENCODING_MAX,
     /**< Valid encoding types must be less than this value */
 
@@ -71,6 +77,8 @@ typedef enum pa_encoding {
 #define PA_ENCODING_MPEG_IEC61937 PA_ENCODING_MPEG_IEC61937
 #define PA_ENCODING_DTS_IEC61937 PA_ENCODING_DTS_IEC61937
 #define PA_ENCODING_MPEG2_AAC_IEC61937 PA_ENCODING_MPEG2_AAC_IEC61937
+#define PA_ENCODING_TRUEHD_IEC61937 PA_ENCODING_TRUEHD_IEC61937
+#define PA_ENCODING_DTSHD_IEC61937 PA_ENCODING_DTSHD_IEC61937
 #define PA_ENCODING_MAX PA_ENCODING_MAX
 #define PA_ENCODING_INVALID PA_ENCODING_INVALID
 /** \endcond */
diff --git a/src/pulsecore/core-format.c b/src/pulsecore/core-format.c
index 9d3c8d60..c3db2678 100644
--- a/src/pulsecore/core-format.c
+++ b/src/pulsecore/core-format.c
@@ -226,7 +226,11 @@ int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *
      * formats, this function should return a non-zero values for these. */
 
     ss->format = PA_SAMPLE_S16LE;
-    ss->channels = 2;
+    if ((f->encoding == PA_ENCODING_TRUEHD_IEC61937) ||
+	(f->encoding == PA_ENCODING_DTSHD_IEC61937))
+	ss->channels = 8;
+    else
+	ss->channels = 2;
 
     if (map)
         pa_channel_map_init_stereo(map);

commit 47ed9ae1f4dccb19aece9a29ae18a724eb9eb30e
Author: Sangchul Lee <sangchul1011 at gmail.com>
Date:   Fri May 4 01:27:21 2018 +0900

    rtp-send: remove dead code
    
    Signed-off-by: Sangchul Lee <sc11.lee at samsung.com>

diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c
index ceb6df50..61900c01 100644
--- a/src/modules/rtp/module-rtp-send.c
+++ b/src/modules/rtp/module-rtp-send.c
@@ -514,11 +514,6 @@ fail:
     if (sap_fd >= 0)
         pa_close(sap_fd);
 
-    if (o) {
-        pa_source_output_unlink(o);
-        pa_source_output_unref(o);
-    }
-
     return -1;
 }
 

commit 385e73e63e95f1ec787b057ffdc3ed97ff26ea8b
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Tue Apr 17 14:16:16 2018 +0300

    .gitignore: add m4/extern-inline.m4 and remove-ptcdate.sed

diff --git a/m4/.gitignore b/m4/.gitignore
index 7bdfcbf6..abd28caf 100644
--- a/m4/.gitignore
+++ b/m4/.gitignore
@@ -1,4 +1,5 @@
 codeset.m4
+extern-inline.m4
 fcntl-o.m4
 gettext.m4
 glibc2.m4
diff --git a/po/.gitignore b/po/.gitignore
index 47297be9..ac922260 100644
--- a/po/.gitignore
+++ b/po/.gitignore
@@ -8,7 +8,7 @@
 /insert-header.sin
 /pulseaudio.pot
 /quot.sed
-/remove-potcdate.sin
+/remove-potcdate.*
 /*.mo
 /*.gmo
 /Makefile

commit 57e3ccaf51f714eec8ca29005c3cc4fde456e84e
Author: Javier Jardón <jjardon at gnome.org>
Date:   Mon Apr 2 20:48:29 2018 +0100

    Use upstream gettext instead intltool

diff --git a/.gitignore b/.gitignore
index a0f0995f..ef145bbb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,9 +3,6 @@
 .*.swp
 ABOUT-NLS
 build-aux
-intltool-extract.in
-intltool-merge.in
-intltool-update.in
 *~
 *.tar.gz
 *.pc
diff --git a/.travis.yml b/.travis.yml
index c21cb977..cc1d9ae8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,6 @@ before_install:
     autopoint
     autoconf
     automake
-    intltool
     check
     libasound2-dev
     libasyncns-dev
diff --git a/Makefile.am b/Makefile.am
index 275ceeac..d19bf973 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -115,7 +115,4 @@ BUILT_SOURCES = $(top_srcdir)/.version
 $(top_srcdir)/.version:
 	echo $(VERSION) > $@-t && mv $@-t $@
 
-DISTCLEANFILES = \
-        po/.intltool-merge-cache
-
 DISTCHECK_CONFIGURE_FLAGS = --with-udev-rules-dir="$$dc_install_base/lib/udev/rules.d" --with-systemduserunitdir="$$dc_install_base/lib/systemd/user" --with-bash-completion-dir="$$dc_install_base/share/bash-completion/completions"
diff --git a/bootstrap.sh b/bootstrap.sh
index 0a05a3e4..17a9c86b 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -39,12 +39,8 @@ if ! autopoint --version &>/dev/null ; then
     echo "autopoint is required to bootstrap this program"
     exit 1
 fi
-if ! intltoolize --version >/dev/null ; then
-    echo "intltoolize is required to bootstrap this program"
-    exit 1
-fi
-autopoint --force
-AUTOPOINT='intltoolize --automake --copy' autoreconf --force --install --verbose
+
+autoreconf --force --install --verbose
 
 if test "x$NOCONFIGURE" = "x"; then
     CFLAGS="$CFLAGS -g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-force-preopen "$@" && \
diff --git a/configure.ac b/configure.ac
index 808aea23..681d78cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,21 +99,12 @@ PKG_PROG_PKG_CONFIG
 
 # gettext
 
-if test "x$enable_nls" != "xno"; then
-IT_PROG_INTLTOOL([0.35.0])
-
-AM_GNU_GETTEXT_VERSION([0.18.1])
+AM_GNU_GETTEXT_VERSION([0.19.8])
 AM_GNU_GETTEXT([external])
 
 GETTEXT_PACKAGE=pulseaudio
 AC_SUBST([GETTEXT_PACKAGE])
 AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"],[Gettext package])
-else
-# workaround till an intltool m4 bug is fixed upstream
-# (https://bugs.launchpad.net/intltool/+bug/904647)
-USE_NLS=no
-AC_SUBST(USE_NLS)
-fi
 
 
 #### Determine host OS ####
diff --git a/m4/.gitignore b/m4/.gitignore
index db941754..7bdfcbf6 100644
--- a/m4/.gitignore
+++ b/m4/.gitignore
@@ -8,7 +8,6 @@ intdiv0.m4
 intl.m4
 intldir.m4
 intlmacosx.m4
-intltool.m4
 intmax.m4
 inttypes-pri.m4
 inttypes_h.m4
diff --git a/po/.gitignore b/po/.gitignore
index 1ebb4277..47297be9 100644
--- a/po/.gitignore
+++ b/po/.gitignore
@@ -1,4 +1,3 @@
-/.intltool-merge-cache
 /Makefile.in.in
 /Makevars.template
 /POTFILES
diff --git a/po/Makevars b/po/Makevars
new file mode 100644
index 00000000..bd3d3fff
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,78 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=UTF-8
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
+# package.  (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.)  Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright.  The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = PulseAudio contributors
+
+# This tells whether or not to prepend "GNU " prefix to the package
+# name that gets inserted into the header of the $(DOMAIN).pot file.
+# Possible values are "yes", "no", or empty.  If it is empty, try to
+# detect it automatically by scanning the files in $(top_srcdir) for
+# "GNU packagename" string.
+PACKAGE_GNU =
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+#   in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+#   understood.
+# - Strings which make invalid assumptions about notation of date, time or
+#   money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS =
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
+
+# This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt'
+# context.  Possible values are "yes" and "no".  Set this to yes if the
+# package uses functions taking also a message context, like pgettext(), or
+# if in $(XGETTEXT_OPTIONS) you define keywords with a context argument.
+USE_MSGCTXT = no
+
+# These options get passed to msgmerge.
+# Useful options are in particular:
+#   --previous            to keep previous msgids of translated messages,
+#   --quiet               to reduce the verbosity.
+MSGMERGE_OPTIONS =
+
+# These options get passed to msginit.
+# If you want to disable line wrapping when writing PO files, add
+# --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and
+# MSGINIT_OPTIONS.
+MSGINIT_OPTIONS =
+
+# This tells whether or not to regenerate a PO file when $(DOMAIN).pot
+# has changed.  Possible values are "yes" and "no".  Set this to no if
+# the POT file is checked in the repository and the version control
+# program ignores timestamps.
+PO_DEPENDS_ON_POT = no
+
+# This tells whether or not to forcibly update $(DOMAIN).pot and
+# regenerate PO files on "make dist".  Possible values are "yes" and
+# "no".  Set this to no if the POT file and PO files are maintained
+# externally.
+DIST_DEPENDS_ON_UPDATE_PO = no
diff --git a/src/Makefile.am b/src/Makefile.am
index eb711f27..f62e7d5c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -127,7 +127,9 @@ if HAVE_X11
 xdgautostart_in_files = \
 		daemon/pulseaudio.desktop.in
 xdgautostart_DATA = $(xdgautostart_in_files:.desktop.in=.desktop)
- at INTLTOOL_DESKTOP_RULE@
+$(xdgautostart_DATA): $(xdgautostart_in_files)
+	$(AM_V_GEN) $(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@
+
 endif
 
 
diff --git a/src/daemon/pulseaudio.desktop.in b/src/daemon/pulseaudio.desktop.in
index 06cde277..cc3ac807 100644
--- a/src/daemon/pulseaudio.desktop.in
+++ b/src/daemon/pulseaudio.desktop.in
@@ -1,7 +1,7 @@
 [Desktop Entry]
 Version=1.0
-_Name=PulseAudio Sound System
-_Comment=Start the PulseAudio Sound System
+Name=PulseAudio Sound System
+Comment=Start the PulseAudio Sound System
 Exec=start-pulseaudio-x11
 Terminal=false
 Type=Application

commit 63500323ef5f02a19709a7477fa3959977937599
Author: Yuri Chornoivan <yurchor at ukr.net>
Date:   Sun Mar 18 12:37:42 2018 +0200

    i18n: update the Ukrainian translation

diff --git a/po/uk.po b/po/uk.po
index d2638e7a..1dcd6c10 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -609,7 +609,7 @@ msgid "Line In"
 msgstr "Лінійний вхід"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez5-device.c:1750
+#: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Microphone"
 msgstr "Мікрофон"
 
@@ -670,7 +670,7 @@ msgid "No Bass Boost"
 msgstr "Без підсилення"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez5-device.c:1757
+#: ../src/modules/bluetooth/module-bluez5-device.c:1790
 msgid "Speaker"
 msgstr "Гучномовець"
 
@@ -855,7 +855,7 @@ msgstr "Двобічне стерео"
 
 #: ../src/modules/alsa/alsa-mixer.c:4158
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez5-device.c:2005
+#: ../src/modules/bluetooth/module-bluez5-device.c:2038
 msgid "Off"
 msgstr "Вимкнено"
 
@@ -989,48 +989,48 @@ msgstr ""
 "Ймовірно, ви натрапили на ваду у драйвері ALSA «%s». Будь ласка, повідомте "
 "про цю ваду розробникам ALSA."
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1740
+#: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Headset"
 msgstr "Гарнітура"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1745
+#: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "Handsfree"
 msgstr "Пристрій гучного зв’язку"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1763
+#: ../src/modules/bluetooth/module-bluez5-device.c:1796
 msgid "Headphone"
 msgstr "Навушники"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1768
+#: ../src/modules/bluetooth/module-bluez5-device.c:1801
 msgid "Portable"
 msgstr "Портативна система"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1773
+#: ../src/modules/bluetooth/module-bluez5-device.c:1806
 msgid "Car"
 msgstr "Автомобільна система"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1778
+#: ../src/modules/bluetooth/module-bluez5-device.c:1811
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1783
+#: ../src/modules/bluetooth/module-bluez5-device.c:1816
 msgid "Phone"
 msgstr "Телефон"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1735
-#: ../src/modules/bluetooth/module-bluez5-device.c:1751
-#: ../src/modules/bluetooth/module-bluez5-device.c:1789
+#: ../src/modules/bluetooth/module-bluez5-device.c:1768
+#: ../src/modules/bluetooth/module-bluez5-device.c:1784
+#: ../src/modules/bluetooth/module-bluez5-device.c:1822
 msgid "Bluetooth Output"
 msgstr "Bluetooth (відтворення)"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1734
-#: ../src/modules/bluetooth/module-bluez5-device.c:1756
-#: ../src/modules/bluetooth/module-bluez5-device.c:1762
-#: ../src/modules/bluetooth/module-bluez5-device.c:1788
+#: ../src/modules/bluetooth/module-bluez5-device.c:1767
+#: ../src/modules/bluetooth/module-bluez5-device.c:1789
+#: ../src/modules/bluetooth/module-bluez5-device.c:1795
+#: ../src/modules/bluetooth/module-bluez5-device.c:1821
 msgid "Bluetooth Input"
 msgstr "Bluetooth (вхід)"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1830
+#: ../src/modules/bluetooth/module-bluez5-device.c:1863
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Високоточне відтворення (приймач A2DP)"
 

commit 745f0208218b54ffeba27d8b6e9f5aa6a97614f9
Author: Andika Triwidada <andika at gmail.com>
Date:   Sun Mar 4 18:05:14 2018 +0200

    i18n: update the Indonesian translation

diff --git a/po/id.po b/po/id.po
index d61df675..4509d548 100644
--- a/po/id.po
+++ b/po/id.po
@@ -590,7 +590,6 @@ msgid "Line In"
 msgstr "Jalur Masuk"
 
 #: ../src/modules/alsa/alsa-mixer.c:2448 ../src/modules/alsa/alsa-mixer.c:2526
-#: ../src/modules/bluetooth/module-bluez4-device.c:2103
 #: ../src/modules/bluetooth/module-bluez5-device.c:1781
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -652,7 +651,6 @@ msgid "No Bass Boost"
 msgstr "Tanpa Boost Bass"
 
 #: ../src/modules/alsa/alsa-mixer.c:2463
-#: ../src/modules/bluetooth/module-bluez4-device.c:2108
 #: ../src/modules/bluetooth/module-bluez5-device.c:1788
 msgid "Speaker"
 msgstr "Speaker"
@@ -839,7 +837,6 @@ msgstr "Dupleks Stereo"
 
 #: ../src/modules/alsa/alsa-mixer.c:4226
 #: ../src/modules/alsa/module-alsa-card.c:185
-#: ../src/modules/bluetooth/module-bluez4-device.c:2323
 #: ../src/modules/bluetooth/module-bluez5-device.c:2036
 msgid "Off"
 msgstr "Mati"
@@ -974,49 +971,40 @@ msgstr ""
 "Sangat mungkin ini adalah kutu pada driver ALSA '%s'. Silakan laporkan hal "
 "ini ke para pengembang ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2093
 #: ../src/modules/bluetooth/module-bluez5-device.c:1771
 msgid "Headset"
 msgstr "Headset"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2098
 #: ../src/modules/bluetooth/module-bluez5-device.c:1776
 msgid "Handsfree"
 msgstr "Handsfree"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2113
 #: ../src/modules/bluetooth/module-bluez5-device.c:1794
 msgid "Headphone"
 msgstr "Headphone"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2118
 #: ../src/modules/bluetooth/module-bluez5-device.c:1799
 msgid "Portable"
 msgstr "Portabel"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2123
 #: ../src/modules/bluetooth/module-bluez5-device.c:1804
 msgid "Car"
 msgstr "Mobil"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2128
 #: ../src/modules/bluetooth/module-bluez5-device.c:1809
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2133
 #: ../src/modules/bluetooth/module-bluez5-device.c:1814
 msgid "Phone"
 msgstr "Telepon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2141
 #: ../src/modules/bluetooth/module-bluez5-device.c:1766
 #: ../src/modules/bluetooth/module-bluez5-device.c:1782
 #: ../src/modules/bluetooth/module-bluez5-device.c:1820
 msgid "Bluetooth Output"
 msgstr "Keluaran Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2144
 #: ../src/modules/bluetooth/module-bluez5-device.c:1765
 #: ../src/modules/bluetooth/module-bluez5-device.c:1787
 #: ../src/modules/bluetooth/module-bluez5-device.c:1793
@@ -1024,22 +1012,6 @@ msgstr "Keluaran Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Masukan Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2185
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Main Ulang High Fidelity (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2197
-msgid "High Fidelity Capture (A2DP)"
-msgstr "High Fidelity Capture (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2209
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Dupleks Teleponi (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2222
-msgid "Handsfree Gateway"
-msgstr "Gateway Handsfree"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1861
 #, fuzzy
 msgid "High Fidelity Playback (A2DP Sink)"

commit db8588c9873e323c82701e18eeaa62754f87747c
Author: Mr. M <hazap at hotmail.com>
Date:   Thu Feb 15 10:29:48 2018 +0200

    i18n: update the Lithuanian translation

diff --git a/po/lt.po b/po/lt.po
index 6555b0bf..a704bec7 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -602,7 +602,7 @@ msgid "Line In"
 msgstr "Įvadinė linija"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez5-device.c:1750
+#: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Microphone"
 msgstr "Mikrofonas"
 
@@ -663,7 +663,7 @@ msgid "No Bass Boost"
 msgstr "Be žemų tonų pastiprinimo"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez5-device.c:1757
+#: ../src/modules/bluetooth/module-bluez5-device.c:1790
 msgid "Speaker"
 msgstr "Garsiakalbis"
 
@@ -847,7 +847,7 @@ msgstr "Dvipusė stereo"
 
 #: ../src/modules/alsa/alsa-mixer.c:4158
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez5-device.c:2005
+#: ../src/modules/bluetooth/module-bluez5-device.c:2038
 msgid "Off"
 msgstr "Išjungta"
 
@@ -981,48 +981,48 @@ msgstr ""
 "Greičiausiai, tai yra klaida ALSA \"'%s\" tvarkyklėje. Prašome apie šią "
 "klaidą pranešti ALSA kūrėjams."
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1740
+#: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Headset"
 msgstr "Ausinės su mikrofonu"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1745
+#: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "Handsfree"
 msgstr "Laisvų rankų įranga"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1763
+#: ../src/modules/bluetooth/module-bluez5-device.c:1796
 msgid "Headphone"
 msgstr "Ausinė"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1768
+#: ../src/modules/bluetooth/module-bluez5-device.c:1801
 msgid "Portable"
 msgstr "Portatyvi sistema"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1773
+#: ../src/modules/bluetooth/module-bluez5-device.c:1806
 msgid "Car"
 msgstr "Automobilis"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1778
+#: ../src/modules/bluetooth/module-bluez5-device.c:1811
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1783
+#: ../src/modules/bluetooth/module-bluez5-device.c:1816
 msgid "Phone"
 msgstr "Telefonas"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1735
-#: ../src/modules/bluetooth/module-bluez5-device.c:1751
-#: ../src/modules/bluetooth/module-bluez5-device.c:1789
+#: ../src/modules/bluetooth/module-bluez5-device.c:1768
+#: ../src/modules/bluetooth/module-bluez5-device.c:1784
+#: ../src/modules/bluetooth/module-bluez5-device.c:1822
 msgid "Bluetooth Output"
 msgstr "Bluetooth išvestis"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1734
-#: ../src/modules/bluetooth/module-bluez5-device.c:1756
-#: ../src/modules/bluetooth/module-bluez5-device.c:1762
-#: ../src/modules/bluetooth/module-bluez5-device.c:1788
+#: ../src/modules/bluetooth/module-bluez5-device.c:1767
+#: ../src/modules/bluetooth/module-bluez5-device.c:1789
+#: ../src/modules/bluetooth/module-bluez5-device.c:1795
+#: ../src/modules/bluetooth/module-bluez5-device.c:1821
 msgid "Bluetooth Input"
 msgstr "Bluetooth įvestis"
 
-#: ../src/modules/bluetooth/module-bluez5-device.c:1830
+#: ../src/modules/bluetooth/module-bluez5-device.c:1863
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Aukštos kokybės atkūrimas (A2DP rinktuvas)"
 

commit 493892434a63e0e3e1ef2bd4347c0c21e69c6ba1
Author: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Date:   Mon Mar 26 17:15:51 2018 +0300

    bluetooth: policy: Remove BlueZ 4 related code
    
    This removes hfpw option and profile which were only used by BlueZ 4.

diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c
index a6a812b5..4d3126f6 100644
--- a/src/modules/bluetooth/module-bluetooth-policy.c
+++ b/src/modules/bluetooth/module-bluetooth-policy.c
@@ -38,8 +38,7 @@ PA_MODULE_LOAD_ONCE(true);
 PA_MODULE_USAGE(
         "auto_switch=<Switch between hsp and a2dp profile? (0 - never, 1 - media.role=phone, 2 - heuristic> "
         "a2dp_source=<Handle a2dp_source card profile (sink role)?> "
-        "ag=<Handle headset_audio_gateway card profile (headset role)?> "
-        "hfgw=<Handle hfgw card profile (headset role)?> DEPRECATED");
+        "ag=<Handle headset_audio_gateway card profile (headset role)?> ");
 
 static const char* const valid_modargs[] = {
     "auto_switch",
@@ -88,8 +87,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
 
     if (u->enable_a2dp_source && pa_streq(s, "a2dp_source"))
         role = "music";
-    /* TODO: remove hfgw when we remove BlueZ 4 support */
-    else if (u->enable_ag && (pa_streq(s, "hfgw") || pa_streq(s, "headset_audio_gateway")))
+    else if (u->enable_ag && pa_streq(s, "headset_audio_gateway"))
         role = "phone";
     else {
         pa_log_debug("Profile %s cannot be selected for loopback", s);
@@ -128,8 +126,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *
     if (!s)
         return PA_HOOK_OK;
 
-    /* TODO: remove hfgw when we remove BlueZ 4 support */
-    if (u->enable_ag && (pa_streq(s, "hfgw") || pa_streq(s, "headset_audio_gateway")))
+    if (u->enable_ag && pa_streq(s, "headset_audio_gateway"))
         role = "phone";
     else {
         pa_log_debug("Profile %s cannot be selected for loopback", s);
@@ -363,9 +360,7 @@ static pa_hook_result_t profile_available_hook_callback(pa_core *c, pa_card_prof
         return PA_HOOK_OK;
 
     /* Do not automatically switch profiles for headsets, just in case */
-    /* TODO: remove a2dp and hsp when we remove BlueZ 4 support */
-    if (pa_streq(profile->name, "hsp") || pa_streq(profile->name, "a2dp") || pa_streq(profile->name, "a2dp_sink") ||
-        pa_streq(profile->name, "headset_head_unit"))
+    if (pa_streq(profile->name, "a2dp_sink") || pa_streq(profile->name, "headset_head_unit"))
         return PA_HOOK_OK;
 
     is_active_profile = card->active_profile == profile;
@@ -448,10 +443,6 @@ int pa__init(pa_module *m) {
     }
 
     u->enable_ag = true;
-    if (pa_modargs_get_value_boolean(ma, "hfgw", &u->enable_ag) < 0) {
-        pa_log("Failed to parse hfgw argument.");
-        goto fail;
-    }
     if (pa_modargs_get_value_boolean(ma, "ag", &u->enable_ag) < 0) {
         pa_log("Failed to parse ag argument.");
         goto fail;

commit 3b1093c0ad882640ef7cf2b88088d77988be7610
Author: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Date:   Mon Mar 26 17:15:50 2018 +0300

    bluetooth: Remove BlueZ 4 support
    
    BlueZ 4 is no longer supported by BlueZ community for a long long time,
    also by moving to BlueZ 5 it should make it even more clearer that
    BlueZ 4 is no longer an option.

diff --git a/configure.ac b/configure.ac
index c9c414f8..808aea23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1071,24 +1071,14 @@ AX_DEFINE_DIR(PA_MACHINE_ID_FALLBACK, PA_MACHINE_ID_FALLBACK,
 
 #### BlueZ support (optional, dependent on D-Bus and SBC) ####
 
-AC_ARG_ENABLE([bluez4],
-    AS_HELP_STRING([--disable-bluez4],[Disable optional BlueZ 4 support]))
 AC_ARG_ENABLE([bluez5],
     AS_HELP_STRING([--disable-bluez5],[Disable optional BlueZ 5 support]))
 
 ## SBC ##
-AS_IF([test "x$enable_bluez4" != "xno" || test "x$enable_bluez5" != "xno"],
+AS_IF([test "x$enable_bluez5" != "xno"],
     [PKG_CHECK_MODULES(SBC, [ sbc >= 1.0 ], HAVE_SBC=1, HAVE_SBC=0)],
     HAVE_SBC=0)
 
-## BlueZ 4 ##
-AS_IF([test "x$enable_bluez4" != "xno" && test "x$HAVE_DBUS" = "x1" && test "x$HAVE_SBC" = "x1"], HAVE_BLUEZ_4=1,
-      HAVE_BLUEZ_4=0)
-AS_IF([test "x$enable_bluez4" = "xyes" && test "x$HAVE_BLUEZ_4" != "x1"],
-    [AC_MSG_ERROR([*** BLUEZ 4 support not found (requires sbc and D-Bus)])])
-AC_SUBST(HAVE_BLUEZ_4)
-AM_CONDITIONAL([HAVE_BLUEZ_4], [test "x$HAVE_BLUEZ_4" = x1])
-
 ## BlueZ 5 ##
 AS_IF([test "x$enable_bluez5" != "xno" && test "x$HAVE_DBUS" = "x1" && test "x$HAVE_SBC" = "x1"], HAVE_BLUEZ_5=1,
       HAVE_BLUEZ_5=0)
@@ -1097,7 +1087,7 @@ AS_IF([test "x$enable_bluez5" = "xyes" && test "x$HAVE_BLUEZ_5" != "x1"],
 AC_SUBST(HAVE_BLUEZ_5)
 AM_CONDITIONAL([HAVE_BLUEZ_5], [test "x$HAVE_BLUEZ_5" = x1])
 
-AS_IF([test "x$HAVE_BLUEZ_4" = "x1" || test "x$HAVE_BLUEZ_5" = "x1"], HAVE_BLUEZ=1, HAVE_BLUEZ=0)
+AS_IF([test "x$HAVE_BLUEZ_5" = "x1"], HAVE_BLUEZ=1, HAVE_BLUEZ=0)
 AC_SUBST(HAVE_BLUEZ)
 AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
 
@@ -1604,7 +1594,6 @@ AS_IF([test "x$HAVE_UDEV" = "x1"], ENABLE_UDEV=yes, ENABLE_UDEV=no)
 AS_IF([test "x$HAVE_SYSTEMD_DAEMON" = "x1"], ENABLE_SYSTEMD_DAEMON=yes, ENABLE_SYSTEMD_DAEMON=no)
 AS_IF([test "x$HAVE_SYSTEMD_LOGIN" = "x1"], ENABLE_SYSTEMD_LOGIN=yes, ENABLE_SYSTEMD_LOGIN=no)
 AS_IF([test "x$HAVE_SYSTEMD_JOURNAL" = "x1"], ENABLE_SYSTEMD_JOURNAL=yes, ENABLE_SYSTEMD_JOURNAL=no)
-AS_IF([test "x$HAVE_BLUEZ_4" = "x1"], ENABLE_BLUEZ_4=yes, ENABLE_BLUEZ_4=no)
 AS_IF([test "x$HAVE_BLUEZ_5" = "x1"], ENABLE_BLUEZ_5=yes, ENABLE_BLUEZ_5=no)
 AS_IF([test "x$HAVE_BLUEZ_5_OFONO_HEADSET" = "x1"], ENABLE_BLUEZ_5_OFONO_HEADSET=yes, ENABLE_BLUEZ_5_OFONO_HEADSET=no)
 AS_IF([test "x$HAVE_BLUEZ_5_NATIVE_HEADSET" = "x1"], ENABLE_BLUEZ_5_NATIVE_HEADSET=yes, ENABLE_BLUEZ_5_NATIVE_HEADSET=no)
@@ -1663,7 +1652,6 @@ echo "
     Enable Async DNS:              ${ENABLE_LIBASYNCNS}
     Enable LIRC:                   ${ENABLE_LIRC}
     Enable D-Bus:                  ${ENABLE_DBUS}
-      Enable BlueZ 4:              ${ENABLE_BLUEZ_4}
       Enable BlueZ 5:              ${ENABLE_BLUEZ_5}
         Enable ofono headsets:     ${ENABLE_BLUEZ_5_OFONO_HEADSET}
         Enable native headsets:    ${ENABLE_BLUEZ_5_NATIVE_HEADSET}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 75a35c39..0b519464 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -14,7 +14,6 @@ src/modules/alsa/alsa-util.c
 src/modules/alsa/module-alsa-card.c
 src/modules/alsa/module-alsa-sink.c
 src/modules/alsa/module-alsa-source.c
-src/modules/bluetooth/module-bluez4-device.c
 src/modules/bluetooth/module-bluez5-device.c
 src/modules/echo-cancel/module-echo-cancel.c
 src/modules/gconf/gconf-helper.c
diff --git a/po/be.po b/po/be.po
index 162c555a..8c3baba2 100644
--- a/po/be.po
+++ b/po/be.po
@@ -591,7 +591,6 @@ msgid "Line In"
 msgstr "Лінейны ўваход"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1710
 msgid "Microphone"
 msgstr "Мікрафон"
@@ -653,7 +652,6 @@ msgid "No Bass Boost"
 msgstr "Без ўзмацнення басоў"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 msgid "Speaker"
 msgstr "Дынамік"
@@ -826,7 +824,6 @@ msgstr "Шматканальны дуплекс"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2295
 #: ../src/modules/bluetooth/module-bluez5-device.c:1941
 msgid "Off"
 msgstr "Адключаны"
@@ -961,49 +958,40 @@ msgstr ""
 "Хутчэй за ўсё, гэта памылка ў ALSA-драйверы «%s». Калі ласка, паведаміце аб"
 " гэтым распрацоўнікам ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2089
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 msgid "Headset"
 msgstr "Гарнітура"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1705
 msgid "Handsfree"
 msgstr "Хэндс-фры"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Headphone"
 msgstr "Навушнік"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
 msgid "Portable"
 msgstr "Партатыўная сістэма"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1733
 msgid "Car"
 msgstr "Аўтамабільная сістэма"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1738
 msgid "HiFi"
 msgstr "Hi-Fi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1743
 msgid "Phone"
 msgstr "Тэлефон"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2137
 #: ../src/modules/bluetooth/module-bluez5-device.c:1695
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Bluetooth Output"
 msgstr "Bluetooth-выхад"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2140
 #: ../src/modules/bluetooth/module-bluez5-device.c:1694
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
@@ -1011,22 +999,6 @@ msgstr "Bluetooth-выхад"
 msgid "Bluetooth Input"
 msgstr "Bluetooth-уваход"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2176
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Прайграванне высокай якасці (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2187
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Захоп высокай якасці (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Тэлефонны дуплекс (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Handsfree Gateway"
-msgstr "Шлюз хэндс-фры"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1786
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Прайграванне высокай якасці (A2DP-прыёмнік)"
diff --git a/po/de.po b/po/de.po
index e73b652f..77aa79ef 100644
--- a/po/de.po
+++ b/po/de.po
@@ -602,7 +602,6 @@ msgid "Line In"
 msgstr "Line-Eingang"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1710
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -664,7 +663,6 @@ msgid "No Bass Boost"
 msgstr "Keine Bassverstärkung"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 msgid "Speaker"
 msgstr "Lautsprecher"
@@ -837,7 +835,6 @@ msgstr "Mehrkanal-Duplex"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2319
 #: ../src/modules/bluetooth/module-bluez5-device.c:1965
 msgid "Off"
 msgstr "Aus"
@@ -976,49 +973,40 @@ msgstr ""
 "Dies ist wahrscheinlich ein Fehler im ALSA-Treiber »%s«. Bitte melden Sie "
 "dieses Problem den ALSA-Entwicklern."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2089
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 msgid "Headset"
 msgstr "Headset"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1705
 msgid "Handsfree"
 msgstr "Freisprecheinrichtung"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Headphone"
 msgstr "Kopfhörer"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
 msgid "Portable"
 msgstr ""
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1733
 msgid "Car"
 msgstr "Auto"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1738
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1743
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2137
 #: ../src/modules/bluetooth/module-bluez5-device.c:1695
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Bluetooth Output"
 msgstr "Bluetooth-Ausgabe"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2140
 #: ../src/modules/bluetooth/module-bluez5-device.c:1694
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
@@ -1026,22 +1014,6 @@ msgstr "Bluetooth-Ausgabe"
 msgid "Bluetooth Input"
 msgstr "Bluetooth-Eingabe"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2181
-msgid "High Fidelity Playback (A2DP)"
-msgstr "High Fidelity Playback (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2193
-msgid "High Fidelity Capture (A2DP)"
-msgstr "High Fidelity Capture (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2205
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telephony Duplex (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2218
-msgid "Handsfree Gateway"
-msgstr ""
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1790
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "High Fidelity Playback (A2DP-Ziel)"
diff --git a/po/el.po b/po/el.po
index cfa0e46a..c877b096 100644
--- a/po/el.po
+++ b/po/el.po
@@ -840,7 +840,6 @@ msgid "Line In"
 msgstr "Γραμμή εισόδου"
 
 #: ../src/modules/alsa/alsa-mixer.c:2256 ../src/modules/alsa/alsa-mixer.c:2334
-#: ../src/modules/bluetooth/module-bluez4-device.c:2101
 #: ../src/modules/bluetooth/module-bluez5-device.c:1451
 msgid "Microphone"
 msgstr "Μικρόφωνο"
@@ -902,7 +901,6 @@ msgid "No Bass Boost"
 msgstr "Χωρίς ενίσχυση μπάσων"
 
 #: ../src/modules/alsa/alsa-mixer.c:2271
-#: ../src/modules/bluetooth/module-bluez4-device.c:2106
 #: ../src/modules/bluetooth/module-bluez5-device.c:1458
 msgid "Speaker"
 msgstr "Ηχείο"
@@ -1057,7 +1055,6 @@ msgstr "Ψηφιακός στερεοφωνικός αμφίδρομος (IEC958
 
 #: ../src/modules/alsa/alsa-mixer.c:3959
 #: ../src/modules/alsa/module-alsa-card.c:193
-#: ../src/modules/bluetooth/module-bluez4-device.c:2297
 #: ../src/modules/bluetooth/module-bluez5-device.c:1656
 msgid "Off"
 msgstr "Ανενεργό"
@@ -1158,49 +1155,40 @@ msgstr ""
 "Το πιθανότερο αυτό είναι ένα σφάλμα στον οδηγό ALSA '%s'. Παρακαλούμε, "
 "αναφέρτε αυτό το θέμα στους προγραμματιστές ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2091
 #: ../src/modules/bluetooth/module-bluez5-device.c:1441
 msgid "Headset"
 msgstr "Ακουστικά"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2096
 #: ../src/modules/bluetooth/module-bluez5-device.c:1446
 msgid "Handsfree"
 msgstr "Ανοιχτής ακρόασης"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2111
 #: ../src/modules/bluetooth/module-bluez5-device.c:1464
 msgid "Headphone"
 msgstr "Ακουστικό"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2116
 #: ../src/modules/bluetooth/module-bluez5-device.c:1469
 msgid "Portable"
 msgstr "Φορητό"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2121
 #: ../src/modules/bluetooth/module-bluez5-device.c:1474
 msgid "Car"
 msgstr "Αυτοκίνητο"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2126
 #: ../src/modules/bluetooth/module-bluez5-device.c:1479
 msgid "HiFi"
 msgstr "Υψηλή πιστότητα"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2131
 #: ../src/modules/bluetooth/module-bluez5-device.c:1484
 msgid "Phone"
 msgstr "Τηλέφωνο"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2139
 #: ../src/modules/bluetooth/module-bluez5-device.c:1436
 #: ../src/modules/bluetooth/module-bluez5-device.c:1452
 #: ../src/modules/bluetooth/module-bluez5-device.c:1490
 msgid "Bluetooth Output"
 msgstr "Έξοδος μπλουτούθ"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1435
 #: ../src/modules/bluetooth/module-bluez5-device.c:1457
 #: ../src/modules/bluetooth/module-bluez5-device.c:1463
@@ -1208,22 +1196,6 @@ msgstr "Έξοδος μπλουτούθ"
 msgid "Bluetooth Input"
 msgstr "Είσοδος μπλουτούθ"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2178
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Αναπαραγωγή υψηλής ποιότητα (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2189
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Λήψη υψηλής ποιότητας (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2200
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Αμφίδρομη τηλεφωνία (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2212
-msgid "Handsfree Gateway"
-msgstr "Πύλη ανοιχτής ακρόασης"
-
 #. TODO: Change this profile's name to a2dp_sink, to reflect the remote
 #. * device's role and be consistent with the a2dp source profile
 #: ../src/modules/bluetooth/module-bluez5-device.c:1529
diff --git a/po/fr.po b/po/fr.po
index 6a682c52..2abbfb72 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -606,7 +606,6 @@ msgid "Line In"
 msgstr "Entrée ligne"
 
 #: ../src/modules/alsa/alsa-mixer.c:2296 ../src/modules/alsa/alsa-mixer.c:2374
-#: ../src/modules/bluetooth/module-bluez4-device.c:2102
 #: ../src/modules/bluetooth/module-bluez5-device.c:1710
 msgid "Microphone"
 msgstr "Microphone"
@@ -668,7 +667,6 @@ msgid "No Bass Boost"
 msgstr "Pas de booster de basses"
 
 #: ../src/modules/alsa/alsa-mixer.c:2311
-#: ../src/modules/bluetooth/module-bluez4-device.c:2107
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 msgid "Speaker"
 msgstr "Haut-parleur"
@@ -823,7 +821,6 @@ msgstr "Duplex stéréo numérique (IEC958)"
 
 #: ../src/modules/alsa/alsa-mixer.c:4052
 #: ../src/modules/alsa/module-alsa-card.c:190
-#: ../src/modules/bluetooth/module-bluez4-device.c:2298
 #: ../src/modules/bluetooth/module-bluez5-device.c:1941
 msgid "Off"
 msgstr "Éteint"
@@ -924,49 +921,40 @@ msgstr ""
 "Il s'agit très probablement d'un bogue dans le pilote ALSA « %s ». Veuillez "
 "rapporter ce problème aux développeurs d'ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2092
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 msgid "Headset"
 msgstr "Casque"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2097
 #: ../src/modules/bluetooth/module-bluez5-device.c:1705
 msgid "Handsfree"
 msgstr "Mains-libres"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2112
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Headphone"
 msgstr "Écouteurs"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2117
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
 msgid "Portable"
 msgstr "Portable"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2122
 #: ../src/modules/bluetooth/module-bluez5-device.c:1733
 msgid "Car"
 msgstr "Voiture"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2127
 #: ../src/modules/bluetooth/module-bluez5-device.c:1738
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2132
 #: ../src/modules/bluetooth/module-bluez5-device.c:1743
 msgid "Phone"
 msgstr "Téléphone"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2140
 #: ../src/modules/bluetooth/module-bluez5-device.c:1695
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Bluetooth Output"
 msgstr "Sortie Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2143
 #: ../src/modules/bluetooth/module-bluez5-device.c:1694
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
@@ -974,22 +962,6 @@ msgstr "Sortie Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Entrée Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2179
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Lecture haute fidélité (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2190
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Capture haute fidélité (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2201
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telephonie en duplex (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2213
-msgid "Handsfree Gateway"
-msgstr "Passerelle Mains-libres"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1786
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Lecture haute fidélité (A2DP Sink)"
diff --git a/po/hr.po b/po/hr.po
index 3afd7200..fd9322d9 100644
--- a/po/hr.po
+++ b/po/hr.po
@@ -597,7 +597,6 @@ msgid "Line In"
 msgstr "Ulaz"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1696
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -659,7 +658,6 @@ msgid "No Bass Boost"
 msgstr "Bez pojačanja basa"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1703
 msgid "Speaker"
 msgstr "Zvučnik"
@@ -832,7 +830,6 @@ msgstr "Višekanalni obostrani"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
 #: ../src/modules/bluetooth/module-bluez5-device.c:1951
 msgid "Off"
 msgstr "Isključeno"
@@ -967,49 +964,40 @@ msgstr ""
 "Najvjerojatnije je ovo greška ALSA upravljačkog programa '%s'. Prijavite "
 "problem ALSA razvijateljima."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1686
 msgid "Headset"
 msgstr "Slušalice s mikrofonom"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1691
 msgid "Handsfree"
 msgstr "Bez-ruku"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1709
 msgid "Headphone"
 msgstr "Slušalice"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1714
 msgid "Portable"
 msgstr "Prijenosnik"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1719
 msgid "Car"
 msgstr "Automobil"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1724
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
 #: ../src/modules/bluetooth/module-bluez5-device.c:1729
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1681
 #: ../src/modules/bluetooth/module-bluez5-device.c:1697
 #: ../src/modules/bluetooth/module-bluez5-device.c:1735
 msgid "Bluetooth Output"
 msgstr "Bluetooth izlaz"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
 #: ../src/modules/bluetooth/module-bluez5-device.c:1680
 #: ../src/modules/bluetooth/module-bluez5-device.c:1702
 #: ../src/modules/bluetooth/module-bluez5-device.c:1708
@@ -1017,22 +1005,6 @@ msgstr "Bluetooth izlaz"
 msgid "Bluetooth Input"
 msgstr "Bluetooth ulaz"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Reprodukcija visoke autentičnosti (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Snimanje visoke autentičnosti (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Obostrana telefonija (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Bezručni pristupnik"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1776
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Reprodukcija visoke autentičnosti (A2DP slivnik)"
diff --git a/po/hu.po b/po/hu.po
index bcb39d8c..64b57b7c 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -609,7 +609,6 @@ msgid "Line In"
 msgstr "Vonalbemenet"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1710
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -671,7 +670,6 @@ msgid "No Bass Boost"
 msgstr "Nincs basszuskiemelés"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 msgid "Speaker"
 msgstr "Hangszóró"
@@ -844,7 +842,6 @@ msgstr "Többcsatornás duplex"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2319
 #: ../src/modules/bluetooth/module-bluez5-device.c:1965
 msgid "Off"
 msgstr "Kikapcsolva"
@@ -983,50 +980,41 @@ msgstr ""
 "Ez valószínűleg egy hiba eredménye az ALSA „%s” illesztőprogramban. Jelentse "
 "ezt a problémát az ALSA fejlesztői felé."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2089
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 msgid "Headset"
 msgstr "Fejhallgató"
 
 # FIXME: utánanézni
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1705
 msgid "Handsfree"
 msgstr "Kihangosító"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Headphone"
 msgstr "Fülhallgató"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
 msgid "Portable"
 msgstr "Hordozható"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1733
 msgid "Car"
 msgstr "Autó"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1738
 msgid "HiFi"
 msgstr "Hi-Fi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1743
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2137
 #: ../src/modules/bluetooth/module-bluez5-device.c:1695
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Bluetooth Output"
 msgstr "Bluetooth kimenet"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2140
 #: ../src/modules/bluetooth/module-bluez5-device.c:1694
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
@@ -1034,22 +1022,6 @@ msgstr "Bluetooth kimenet"
 msgid "Bluetooth Input"
 msgstr "Bluetooth bemenet"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2181
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Hi-Fi lejátszás (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2193
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Hi-Fi felvétel (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2205
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telefon duplex (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2218
-msgid "Handsfree Gateway"
-msgstr "Kihangosító átjáró"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1790
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Hi-Fi lejátszás (A2DP bemenet)"
diff --git a/po/it.po b/po/it.po
index d71d74c9..151ff318 100644
--- a/po/it.po
+++ b/po/it.po
@@ -619,7 +619,6 @@ msgid "Line In"
 msgstr "Line-In"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1750
 msgid "Microphone"
 msgstr "Microfono"
@@ -681,7 +680,6 @@ msgid "No Bass Boost"
 msgstr "Nessun incremento bassi"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1757
 msgid "Speaker"
 msgstr "Altoparlante"
@@ -862,7 +860,6 @@ msgstr "Duplex stereo"
 
 #: ../src/modules/alsa/alsa-mixer.c:4157
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
 #: ../src/modules/bluetooth/module-bluez5-device.c:2005
 msgid "Off"
 msgstr "Spento"
@@ -995,49 +992,40 @@ msgstr ""
 "Molto probabilmente si tratta di un bug nel driver ALSA \"%s\". Segnalare "
 "questo problema agli sviluppatori ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1740
 msgid "Headset"
 msgstr "Cuffie con microfono"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1745
 msgid "Handsfree"
 msgstr "Sistema mani-libere"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1763
 msgid "Headphone"
 msgstr "Cuffie"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1768
 msgid "Portable"
 msgstr "Portabile"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Car"
 msgstr "Automobile"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
 #: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Phone"
 msgstr "Telefono"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1735
 #: ../src/modules/bluetooth/module-bluez5-device.c:1751
 #: ../src/modules/bluetooth/module-bluez5-device.c:1789
 msgid "Bluetooth Output"
 msgstr "Uscita Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
 #: ../src/modules/bluetooth/module-bluez5-device.c:1734
 #: ../src/modules/bluetooth/module-bluez5-device.c:1756
 #: ../src/modules/bluetooth/module-bluez5-device.c:1762
@@ -1045,22 +1033,6 @@ msgstr "Uscita Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Ingresso Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Riproduzione ad alta fedeltà (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Cattura ad alta fedeltà (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Doppino telefonico (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Gateway handsfree"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1830
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Riproduzione ad alta fedeltà (sink A2DP)"
diff --git a/po/lt.po b/po/lt.po
index d8bee2f7..6555b0bf 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -602,8 +602,7 @@ msgid "Line In"
 msgstr "Įvadinė linija"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
-#: ../src/modules/bluetooth/module-bluez5-device.c:1783
+#: ../src/modules/bluetooth/module-bluez5-device.c:1750
 msgid "Microphone"
 msgstr "Mikrofonas"
 
@@ -664,8 +663,7 @@ msgid "No Bass Boost"
 msgstr "Be žemų tonų pastiprinimo"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
-#: ../src/modules/bluetooth/module-bluez5-device.c:1790
+#: ../src/modules/bluetooth/module-bluez5-device.c:1757
 msgid "Speaker"
 msgstr "Garsiakalbis"
 
@@ -849,8 +847,7 @@ msgstr "Dvipusė stereo"
 
 #: ../src/modules/alsa/alsa-mixer.c:4158
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
-#: ../src/modules/bluetooth/module-bluez5-device.c:2038
+#: ../src/modules/bluetooth/module-bluez5-device.c:2005
 msgid "Off"
 msgstr "Išjungta"
 
@@ -984,73 +981,48 @@ msgstr ""
 "Greičiausiai, tai yra klaida ALSA \"'%s\" tvarkyklėje. Prašome apie šią "
 "klaidą pranešti ALSA kūrėjams."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
-#: ../src/modules/bluetooth/module-bluez5-device.c:1773
+#: ../src/modules/bluetooth/module-bluez5-device.c:1740
 msgid "Headset"
 msgstr "Ausinės su mikrofonu"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
-#: ../src/modules/bluetooth/module-bluez5-device.c:1778
+#: ../src/modules/bluetooth/module-bluez5-device.c:1745
 msgid "Handsfree"
 msgstr "Laisvų rankų įranga"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
-#: ../src/modules/bluetooth/module-bluez5-device.c:1796
+#: ../src/modules/bluetooth/module-bluez5-device.c:1763
 msgid "Headphone"
 msgstr "Ausinė"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
-#: ../src/modules/bluetooth/module-bluez5-device.c:1801
+#: ../src/modules/bluetooth/module-bluez5-device.c:1768
 msgid "Portable"
 msgstr "Portatyvi sistema"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
-#: ../src/modules/bluetooth/module-bluez5-device.c:1806
+#: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Car"
 msgstr "Automobilis"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
-#: ../src/modules/bluetooth/module-bluez5-device.c:1811
+#: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
-#: ../src/modules/bluetooth/module-bluez5-device.c:1816
+#: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Phone"
 msgstr "Telefonas"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
-#: ../src/modules/bluetooth/module-bluez5-device.c:1768
-#: ../src/modules/bluetooth/module-bluez5-device.c:1784
-#: ../src/modules/bluetooth/module-bluez5-device.c:1822
+#: ../src/modules/bluetooth/module-bluez5-device.c:1735
+#: ../src/modules/bluetooth/module-bluez5-device.c:1751
+#: ../src/modules/bluetooth/module-bluez5-device.c:1789
 msgid "Bluetooth Output"
 msgstr "Bluetooth išvestis"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
-#: ../src/modules/bluetooth/module-bluez5-device.c:1767
-#: ../src/modules/bluetooth/module-bluez5-device.c:1789
-#: ../src/modules/bluetooth/module-bluez5-device.c:1795
-#: ../src/modules/bluetooth/module-bluez5-device.c:1821
+#: ../src/modules/bluetooth/module-bluez5-device.c:1734
+#: ../src/modules/bluetooth/module-bluez5-device.c:1756
+#: ../src/modules/bluetooth/module-bluez5-device.c:1762
+#: ../src/modules/bluetooth/module-bluez5-device.c:1788
 msgid "Bluetooth Input"
 msgstr "Bluetooth įvestis"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Aukštos kokybės atkūrimas (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Aukštos kokybės paėmimas (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telefoninė dvipusė (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Laisvų rankų įrangos tinklų sietuvas"
-
-#: ../src/modules/bluetooth/module-bluez5-device.c:1863
+#: ../src/modules/bluetooth/module-bluez5-device.c:1830
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Aukštos kokybės atkūrimas (A2DP rinktuvas)"
 
diff --git a/po/nn.po b/po/nn.po
index f6121d1e..7bce7386 100644
--- a/po/nn.po
+++ b/po/nn.po
@@ -568,7 +568,6 @@ msgid "Line In"
 msgstr "Linje inn"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1750
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -643,7 +642,6 @@ msgid "No Bass Boost"
 msgstr "Inga bassforsterking"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1757
 msgid "Speaker"
 msgstr "Høgtalar"
@@ -845,7 +843,6 @@ msgstr "Stereo dupleks"
 
 #: ../src/modules/alsa/alsa-mixer.c:4157
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
 #: ../src/modules/bluetooth/module-bluez5-device.c:2005
 msgid "Off"
 msgstr "Av"
@@ -943,50 +940,42 @@ msgstr ""
 "snd_pcm_mmap_begin() gav ein verdi som er uvanleg stor: %lu byte (%lu ms).\n"
 "Dette kjem truleg av ein feil i ALSA-drivaren «%s». Meld frå om problemet til ALSA-utviklarane."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1740
 #| msgctxt "This device is a Headset"
 #| msgid "Headset"
 msgid "Headset"
 msgstr "Hovudsett"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1745
 #| msgctxt "For holding pieces"
 #| msgid "Hand"
 msgid "Handsfree"
 msgstr "Handfri"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1763
 msgid "Headphone"
 msgstr "Hovudtelefonar"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1768
 #| msgctxt "portugal_districts.kgm"
 #| msgid "Portalegre"
 msgid "Portable"
 msgstr "Portabel"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Car"
 msgstr "Bil"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "HiFi"
 msgstr "Hi-fi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
 #: ../src/modules/bluetooth/module-bluez5-device.c:1783
 #| msgctxt "Name"
 #| msgid "Phone"
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1735
 #: ../src/modules/bluetooth/module-bluez5-device.c:1751
 #: ../src/modules/bluetooth/module-bluez5-device.c:1789
@@ -995,7 +984,6 @@ msgstr "Telefon"
 msgid "Bluetooth Output"
 msgstr "Bluetooth-utlyd"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
 #: ../src/modules/bluetooth/module-bluez5-device.c:1734
 #: ../src/modules/bluetooth/module-bluez5-device.c:1756
 #: ../src/modules/bluetooth/module-bluez5-device.c:1762
@@ -1005,22 +993,6 @@ msgstr "Bluetooth-utlyd"
 msgid "Bluetooth Input"
 msgstr "Bluetooth-innlyd"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Hi-fi-avspeling (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Hi-fi-opptak (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telefon dupleks (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Handfri-portnar"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1830
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Hi-fi-avspeling (A2DP-sluk)"
diff --git a/po/oc.po b/po/oc.po
index 4a65fb56..3fe1f655 100644
--- a/po/oc.po
+++ b/po/oc.po
@@ -521,7 +521,6 @@ msgid "Line In"
 msgstr "Entrada linha"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2173
 #: ../src/modules/bluetooth/module-bluez5-device.c:1937
 msgid "Microphone"
 msgstr "Micrò"
@@ -583,7 +582,6 @@ msgid "No Bass Boost"
 msgstr "Pas d'amplificacion de las bassas"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2178
 #: ../src/modules/bluetooth/module-bluez5-device.c:1944
 msgid "Speaker"
 msgstr "Nautparlaire"
@@ -756,7 +754,6 @@ msgstr ""
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2369
 #: ../src/modules/bluetooth/module-bluez5-device.c:2173
 #: ../src/modules/droid/module-droid-card.c:221
 msgid "Off"
@@ -880,49 +877,40 @@ msgstr ""
 "S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
 "aqueste problèma als desvolopaires d'ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2163
 #: ../src/modules/bluetooth/module-bluez5-device.c:1927
 msgid "Headset"
 msgstr "Casc àudio"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2168
 #: ../src/modules/bluetooth/module-bluez5-device.c:1932
 msgid "Handsfree"
 msgstr "Mans liuras"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2183
 #: ../src/modules/bluetooth/module-bluez5-device.c:1950
 msgid "Headphone"
 msgstr "Escotadors"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2188
 #: ../src/modules/bluetooth/module-bluez5-device.c:1955
 msgid "Portable"
 msgstr "Portable"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2193
 #: ../src/modules/bluetooth/module-bluez5-device.c:1960
 msgid "Car"
 msgstr "Telefòn de veitura"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
 #: ../src/modules/bluetooth/module-bluez5-device.c:1965
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2203
 #: ../src/modules/bluetooth/module-bluez5-device.c:1970
 msgid "Phone"
 msgstr "Telefòn"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2211
 #: ../src/modules/bluetooth/module-bluez5-device.c:1922
 #: ../src/modules/bluetooth/module-bluez5-device.c:1938
 #: ../src/modules/bluetooth/module-bluez5-device.c:1976
 msgid "Bluetooth Output"
 msgstr "Sortida Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2214
 #: ../src/modules/bluetooth/module-bluez5-device.c:1921
 #: ../src/modules/bluetooth/module-bluez5-device.c:1943
 #: ../src/modules/bluetooth/module-bluez5-device.c:1949
@@ -930,22 +918,6 @@ msgstr "Sortida Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Entrada Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2250
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Lectura nauta fidelitat (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2261
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Captura Hi-Fi (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2272
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telefonia en duplèx (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2284
-msgid "Handsfree Gateway"
-msgstr "Pòrt mans liuras"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:2013
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr ""
diff --git a/po/pl.po b/po/pl.po
index 9591ceaf..fb432274 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -593,9 +593,8 @@ msgstr "Wejście liniowe stacji dokującej"
 msgid "Line In"
 msgstr "Wejście liniowe"
 
-#: ../src/modules/alsa/alsa-mixer.c:2448 ../src/modules/alsa/alsa-mixer.c:2526
-#: ../src/modules/bluetooth/module-bluez4-device.c:2111
-#: ../src/modules/bluetooth/module-bluez5-device.c:1789
+#: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
+#: ../src/modules/bluetooth/module-bluez5-device.c:1750
 msgid "Microphone"
 msgstr "Mikrofon"
 
@@ -655,9 +654,8 @@ msgstr "Podbicie basów"
 msgid "No Bass Boost"
 msgstr "Brak podbicia basów"
 
-#: ../src/modules/alsa/alsa-mixer.c:2463
-#: ../src/modules/bluetooth/module-bluez4-device.c:2116
-#: ../src/modules/bluetooth/module-bluez5-device.c:1796
+#: ../src/modules/alsa/alsa-mixer.c:2398
+#: ../src/modules/bluetooth/module-bluez5-device.c:1757
 msgid "Speaker"
 msgstr "Głośnik"
 
@@ -839,10 +837,9 @@ msgstr "Dupleks wielokanałowy"
 msgid "Stereo Duplex"
 msgstr "Dupleks stereo"
 
-#: ../src/modules/alsa/alsa-mixer.c:4226
-#: ../src/modules/alsa/module-alsa-card.c:185
-#: ../src/modules/bluetooth/module-bluez4-device.c:2331
-#: ../src/modules/bluetooth/module-bluez5-device.c:2044
+#: ../src/modules/alsa/alsa-mixer.c:4157
+#: ../src/modules/alsa/module-alsa-card.c:186
+#: ../src/modules/bluetooth/module-bluez5-device.c:2005
 msgid "Off"
 msgstr "Wyłączone"
 
@@ -973,73 +970,48 @@ msgstr ""
 "Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem "
 "programistom usługi ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2101
-#: ../src/modules/bluetooth/module-bluez5-device.c:1779
+#: ../src/modules/bluetooth/module-bluez5-device.c:1740
 msgid "Headset"
 msgstr "Słuchawki z mikrofonem"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2106
-#: ../src/modules/bluetooth/module-bluez5-device.c:1784
+#: ../src/modules/bluetooth/module-bluez5-device.c:1745
 msgid "Handsfree"
 msgstr "Zestaw głośnomówiący"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2121
-#: ../src/modules/bluetooth/module-bluez5-device.c:1802
+#: ../src/modules/bluetooth/module-bluez5-device.c:1763
 msgid "Headphone"
 msgstr "Słuchawki"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2126
-#: ../src/modules/bluetooth/module-bluez5-device.c:1807
+#: ../src/modules/bluetooth/module-bluez5-device.c:1768
 msgid "Portable"
 msgstr "Przenośne"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2131
-#: ../src/modules/bluetooth/module-bluez5-device.c:1812
+#: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Car"
 msgstr "Samochód"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2136
-#: ../src/modules/bluetooth/module-bluez5-device.c:1817
+#: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2141
-#: ../src/modules/bluetooth/module-bluez5-device.c:1822
+#: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2149
-#: ../src/modules/bluetooth/module-bluez5-device.c:1774
-#: ../src/modules/bluetooth/module-bluez5-device.c:1790
-#: ../src/modules/bluetooth/module-bluez5-device.c:1828
+#: ../src/modules/bluetooth/module-bluez5-device.c:1735
+#: ../src/modules/bluetooth/module-bluez5-device.c:1751
+#: ../src/modules/bluetooth/module-bluez5-device.c:1789
 msgid "Bluetooth Output"
 msgstr "Wyjście Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2152
-#: ../src/modules/bluetooth/module-bluez5-device.c:1773
-#: ../src/modules/bluetooth/module-bluez5-device.c:1795
-#: ../src/modules/bluetooth/module-bluez5-device.c:1801
-#: ../src/modules/bluetooth/module-bluez5-device.c:1827
+#: ../src/modules/bluetooth/module-bluez5-device.c:1734
+#: ../src/modules/bluetooth/module-bluez5-device.c:1756
+#: ../src/modules/bluetooth/module-bluez5-device.c:1762
+#: ../src/modules/bluetooth/module-bluez5-device.c:1788
 msgid "Bluetooth Input"
 msgstr "Wejście Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2193
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Odtwarzanie o wysokiej dokładności (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2205
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Przechwytywanie o wysokiej dokładności (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2217
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Dupleks telefoniczny (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2230
-msgid "Handsfree Gateway"
-msgstr "Zestaw głośnomówiący"
-
-#: ../src/modules/bluetooth/module-bluez5-device.c:1869
+#: ../src/modules/bluetooth/module-bluez5-device.c:1830
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP)"
 
diff --git a/po/pt_BR.po b/po/pt_BR.po
index a9fd40b7..e918c042 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -605,7 +605,6 @@ msgid "Line In"
 msgstr "Entrada de linha"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2103
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 msgid "Microphone"
 msgstr "Microfone"
@@ -673,7 +672,6 @@ msgid "No Bass Boost"
 msgstr "Sem reforço de graves"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2108
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Speaker"
 msgstr "Auto-falante"
@@ -846,7 +844,6 @@ msgstr "Duplex multicanal"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2323
 #: ../src/modules/bluetooth/module-bluez5-device.c:1971
 msgid "Off"
 msgstr "Desligado"
@@ -982,50 +979,41 @@ msgstr ""
 "relate esse problema aos desenvolvedores do ALSA."
 
 # Fone de ouvido não se encaixa como tradução aqui, pois há ou pode haver microfone junto.
-#: ../src/modules/bluetooth/module-bluez4-device.c:2093
 #: ../src/modules/bluetooth/module-bluez5-device.c:1706
 msgid "Headset"
 msgstr "Headset"
 
 # Desconheço tradução comum para esta palavra.
-#: ../src/modules/bluetooth/module-bluez4-device.c:2098
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 msgid "Handsfree"
 msgstr "Handsfree"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2113
 #: ../src/modules/bluetooth/module-bluez5-device.c:1729
 msgid "Headphone"
 msgstr "Fones de ouvido"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2118
 #: ../src/modules/bluetooth/module-bluez5-device.c:1734
 msgid "Portable"
 msgstr "Portátil"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2123
 #: ../src/modules/bluetooth/module-bluez5-device.c:1739
 msgid "Car"
 msgstr "Carro"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2128
 #: ../src/modules/bluetooth/module-bluez5-device.c:1744
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2133
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Phone"
 msgstr "Telefone"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2141
 #: ../src/modules/bluetooth/module-bluez5-device.c:1701
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 #: ../src/modules/bluetooth/module-bluez5-device.c:1755
 msgid "Bluetooth Output"
 msgstr "Saída Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2144
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
@@ -1033,22 +1021,6 @@ msgstr "Saída Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Entrada Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2185
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Reprodução de alta fidelidade (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2197
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Captura de alta fidelidade (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2209
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Duplex telefônico (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2222
-msgid "Handsfree Gateway"
-msgstr "Gateway de handsfree"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1796
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Reprodução de alta fidelidade (Destino A2DP)"
diff --git a/po/ru.po b/po/ru.po
index 2e81b071..1888c4cf 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -779,7 +779,6 @@ msgid "Line In"
 msgstr "Линейный вход"
 
 #: ../src/modules/alsa/alsa-mixer.c:2256 ../src/modules/alsa/alsa-mixer.c:2334
-#: ../src/modules/bluetooth/module-bluez4-device.c:2101
 #: ../src/modules/bluetooth/module-bluez5-device.c:1451
 msgid "Microphone"
 msgstr "Микрофон"
@@ -843,7 +842,6 @@ msgid "No Bass Boost"
 msgstr "Нет усиления басов"
 
 #: ../src/modules/alsa/alsa-mixer.c:2271
-#: ../src/modules/bluetooth/module-bluez4-device.c:2106
 #: ../src/modules/bluetooth/module-bluez5-device.c:1458
 msgid "Speaker"
 msgstr "Динамик"
@@ -998,7 +996,6 @@ msgstr "Цифровой стерео дуплекс (IEC958)"
 
 #: ../src/modules/alsa/alsa-mixer.c:3959
 #: ../src/modules/alsa/module-alsa-card.c:193
-#: ../src/modules/bluetooth/module-bluez4-device.c:2297
 #: ../src/modules/bluetooth/module-bluez5-device.c:1656
 msgid "Off"
 msgstr "Выключено"
@@ -1101,50 +1098,41 @@ msgstr ""
 "Вероятно, это ошибка в драйвере ALSA «%s». Пожалуйста, сообщите об этой "
 "проблеме разработчикам ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2091
 #: ../src/modules/bluetooth/module-bluez5-device.c:1441
 msgid "Headset"
 msgstr "Гарнитура"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2096
 #: ../src/modules/bluetooth/module-bluez5-device.c:1446
 msgid "Handsfree"
 msgstr "Хендс-фри"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2111
 #: ../src/modules/bluetooth/module-bluez5-device.c:1464
 msgid "Headphone"
 msgstr "Наушник"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2116
 #: ../src/modules/bluetooth/module-bluez5-device.c:1469
 msgid "Portable"
 msgstr "Портативный динамик"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2121
 #: ../src/modules/bluetooth/module-bluez5-device.c:1474
 msgid "Car"
 msgstr "Автомобильный динамик"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2126
 #: ../src/modules/bluetooth/module-bluez5-device.c:1479
 msgid "HiFi"
 msgstr "Hi-Fi"
 
 # BUGME: please clarify, does this mean a cell phone? --aspotashev
-#: ../src/modules/bluetooth/module-bluez4-device.c:2131
 #: ../src/modules/bluetooth/module-bluez5-device.c:1484
 msgid "Phone"
 msgstr "Телефон"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2139
 #: ../src/modules/bluetooth/module-bluez5-device.c:1436
 #: ../src/modules/bluetooth/module-bluez5-device.c:1452
 #: ../src/modules/bluetooth/module-bluez5-device.c:1490
 msgid "Bluetooth Output"
 msgstr "Выход Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1435
 #: ../src/modules/bluetooth/module-bluez5-device.c:1457
 #: ../src/modules/bluetooth/module-bluez5-device.c:1463
@@ -1152,22 +1140,6 @@ msgstr "Выход Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Вход Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2178
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Воспроизведение высокого качества (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2189
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Запись высокого качества (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2200
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Дуплексная телефония (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2212
-msgid "Handsfree Gateway"
-msgstr "Шлюз передачи данных для хендс-фри"
-
 #. TODO: Change this profile's name to a2dp_sink, to reflect the remote
 #. * device's role and be consistent with the a2dp source profile
 #: ../src/modules/bluetooth/module-bluez5-device.c:1529
diff --git a/po/sk.po b/po/sk.po
index 730c2344..322de4f5 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -495,7 +495,6 @@ msgid "Line In"
 msgstr "Vstupná linka"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1710
 msgid "Microphone"
 msgstr "Mikrofón"
@@ -557,7 +556,6 @@ msgid "No Bass Boost"
 msgstr "Bez zosilnenia basov"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 msgid "Speaker"
 msgstr "Reproduktor"
@@ -730,7 +728,6 @@ msgstr "Obojsmerný viackanálový"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2295
 #: ../src/modules/bluetooth/module-bluez5-device.c:1941
 msgid "Off"
 msgstr "Vypnuté"
@@ -825,49 +822,40 @@ msgid ""
 "to the ALSA developers."
 msgstr ""
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2089
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 msgid "Headset"
 msgstr "Headset"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1705
 msgid "Handsfree"
 msgstr "Handsfree"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Headphone"
 msgstr "Slúchadlo"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
 msgid "Portable"
 msgstr "Prenosné"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1733
 msgid "Car"
 msgstr "Automobil"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1738
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1743
 msgid "Phone"
 msgstr "Telefón"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2137
 #: ../src/modules/bluetooth/module-bluez5-device.c:1695
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Bluetooth Output"
 msgstr "Výstup cez Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2140
 #: ../src/modules/bluetooth/module-bluez5-device.c:1694
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
@@ -875,22 +863,6 @@ msgstr "Výstup cez Bluetooth"
 msgid "Bluetooth Input"
 msgstr "Vstup cez Bluetooth"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2176
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Hi-Fi prehrávanie (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2187
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Hi-Fi zaznamenávanie (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr ""
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Handsfree Gateway"
-msgstr "Brána pre handsfree"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1786
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr ""
diff --git a/po/sv.po b/po/sv.po
index a5b6d6fb..a8689595 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -594,7 +594,6 @@ msgid "Line In"
 msgstr "Linje in"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -656,7 +655,6 @@ msgid "No Bass Boost"
 msgstr "Ingen basökning"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1790
 msgid "Speaker"
 msgstr "Högtalare"
@@ -841,7 +839,6 @@ msgstr "Stereo duplex"
 
 #: ../src/modules/alsa/alsa-mixer.c:4158
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
 #: ../src/modules/bluetooth/module-bluez5-device.c:2038
 msgid "Off"
 msgstr "Av"
@@ -976,49 +973,40 @@ msgstr ""
 "Förmodligen är detta ett fel i ALSA-drivrutinen ”%s”. Vänligen rapportera "
 "problemet till ALSA-utvecklarna."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Headset"
 msgstr "Headset"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "Handsfree"
 msgstr "Handsfree"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1796
 msgid "Headphone"
 msgstr "Hörlurar"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1801
 msgid "Portable"
 msgstr "Bärbar"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1806
 msgid "Car"
 msgstr "Bil"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1811
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
 #: ../src/modules/bluetooth/module-bluez5-device.c:1816
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1768
 #: ../src/modules/bluetooth/module-bluez5-device.c:1784
 #: ../src/modules/bluetooth/module-bluez5-device.c:1822
 msgid "Bluetooth Output"
 msgstr "Bluetooth-utgång"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
 #: ../src/modules/bluetooth/module-bluez5-device.c:1767
 #: ../src/modules/bluetooth/module-bluez5-device.c:1789
 #: ../src/modules/bluetooth/module-bluez5-device.c:1795
@@ -1026,22 +1014,6 @@ msgstr "Bluetooth-utgång"
 msgid "Bluetooth Input"
 msgstr "Bluetooth-ingång"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "High fidelity playback (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "High fidelity capture (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Telephony duplex (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Handsfree gateway"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1863
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "High fidelity playback (A2DP Sink)"
diff --git a/po/tr.po b/po/tr.po
index 9a72759a..2600f8aa 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -678,7 +678,6 @@ msgid "Line In"
 msgstr "Hat girişi"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1696
 msgid "Microphone"
 msgstr "Mikrofon"
@@ -740,7 +739,6 @@ msgid "No Bass Boost"
 msgstr "Bas Artırma"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1703
 msgid "Speaker"
 msgstr "Hoparlör"
@@ -922,7 +920,6 @@ msgstr "İkili Stereo"
 
 #: ../src/modules/alsa/alsa-mixer.c:4157
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
 #: ../src/modules/bluetooth/module-bluez5-device.c:1951
 msgid "Off"
 msgstr "Kapalı"
@@ -1054,49 +1051,40 @@ msgstr ""
 "Büyük ihtimalle bu bir ALSA sürücüsü '%s' hatasıdır. Lütfen bu sorunu ALSA "
 "geliştiricilerine bildirin."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1686
 msgid "Headset"
 msgstr "Kulaklık"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1691
 msgid "Handsfree"
 msgstr "Ahizesiz"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1709
 msgid "Headphone"
 msgstr "Kulaklık"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1714
 msgid "Portable"
 msgstr "Taşınabilir"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1719
 msgid "Car"
 msgstr "Araba"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1724
 msgid "HiFi"
 msgstr "Yüksek duyarlılık"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
 #: ../src/modules/bluetooth/module-bluez5-device.c:1729
 msgid "Phone"
 msgstr "Telefon"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1681
 #: ../src/modules/bluetooth/module-bluez5-device.c:1697
 #: ../src/modules/bluetooth/module-bluez5-device.c:1735
 msgid "Bluetooth Output"
 msgstr "Bluetooth Çıkışı"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
 #: ../src/modules/bluetooth/module-bluez5-device.c:1680
 #: ../src/modules/bluetooth/module-bluez5-device.c:1702
 #: ../src/modules/bluetooth/module-bluez5-device.c:1708
@@ -1104,22 +1092,6 @@ msgstr "Bluetooth Çıkışı"
 msgid "Bluetooth Input"
 msgstr "Bluetooth Girişi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Yüksek Kaliteli Çalma (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Yüksek Kaliteli Yakalama (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Çift yönlü Telefon (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Eller Serbest Geçidi"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1776
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Yüksek Kaliteli Çalma (A2DP Alıcı)"
diff --git a/po/uk.po b/po/uk.po
index 48160aef..d2638e7a 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -609,8 +609,7 @@ msgid "Line In"
 msgstr "Лінійний вхід"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
-#: ../src/modules/bluetooth/module-bluez5-device.c:1783
+#: ../src/modules/bluetooth/module-bluez5-device.c:1750
 msgid "Microphone"
 msgstr "Мікрофон"
 
@@ -671,8 +670,7 @@ msgid "No Bass Boost"
 msgstr "Без підсилення"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
-#: ../src/modules/bluetooth/module-bluez5-device.c:1790
+#: ../src/modules/bluetooth/module-bluez5-device.c:1757
 msgid "Speaker"
 msgstr "Гучномовець"
 
@@ -857,8 +855,7 @@ msgstr "Двобічне стерео"
 
 #: ../src/modules/alsa/alsa-mixer.c:4158
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
-#: ../src/modules/bluetooth/module-bluez5-device.c:2038
+#: ../src/modules/bluetooth/module-bluez5-device.c:2005
 msgid "Off"
 msgstr "Вимкнено"
 
@@ -992,73 +989,48 @@ msgstr ""
 "Ймовірно, ви натрапили на ваду у драйвері ALSA «%s». Будь ласка, повідомте "
 "про цю ваду розробникам ALSA."
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
-#: ../src/modules/bluetooth/module-bluez5-device.c:1773
+#: ../src/modules/bluetooth/module-bluez5-device.c:1740
 msgid "Headset"
 msgstr "Гарнітура"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
-#: ../src/modules/bluetooth/module-bluez5-device.c:1778
+#: ../src/modules/bluetooth/module-bluez5-device.c:1745
 msgid "Handsfree"
 msgstr "Пристрій гучного зв’язку"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
-#: ../src/modules/bluetooth/module-bluez5-device.c:1796
+#: ../src/modules/bluetooth/module-bluez5-device.c:1763
 msgid "Headphone"
 msgstr "Навушники"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
-#: ../src/modules/bluetooth/module-bluez5-device.c:1801
+#: ../src/modules/bluetooth/module-bluez5-device.c:1768
 msgid "Portable"
 msgstr "Портативна система"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
-#: ../src/modules/bluetooth/module-bluez5-device.c:1806
+#: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Car"
 msgstr "Автомобільна система"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
-#: ../src/modules/bluetooth/module-bluez5-device.c:1811
+#: ../src/modules/bluetooth/module-bluez5-device.c:1778
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
-#: ../src/modules/bluetooth/module-bluez5-device.c:1816
+#: ../src/modules/bluetooth/module-bluez5-device.c:1783
 msgid "Phone"
 msgstr "Телефон"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
-#: ../src/modules/bluetooth/module-bluez5-device.c:1768
-#: ../src/modules/bluetooth/module-bluez5-device.c:1784
-#: ../src/modules/bluetooth/module-bluez5-device.c:1822
+#: ../src/modules/bluetooth/module-bluez5-device.c:1735
+#: ../src/modules/bluetooth/module-bluez5-device.c:1751
+#: ../src/modules/bluetooth/module-bluez5-device.c:1789
 msgid "Bluetooth Output"
 msgstr "Bluetooth (відтворення)"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
-#: ../src/modules/bluetooth/module-bluez5-device.c:1767
-#: ../src/modules/bluetooth/module-bluez5-device.c:1789
-#: ../src/modules/bluetooth/module-bluez5-device.c:1795
-#: ../src/modules/bluetooth/module-bluez5-device.c:1821
+#: ../src/modules/bluetooth/module-bluez5-device.c:1734
+#: ../src/modules/bluetooth/module-bluez5-device.c:1756
+#: ../src/modules/bluetooth/module-bluez5-device.c:1762
+#: ../src/modules/bluetooth/module-bluez5-device.c:1788
 msgid "Bluetooth Input"
 msgstr "Bluetooth (вхід)"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "Високоточне відтворення (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "Високоточне захоплення (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "Телефонний дуплекс (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "Пристрій гучного зв’язку"
-
-#: ../src/modules/bluetooth/module-bluez5-device.c:1863
+#: ../src/modules/bluetooth/module-bluez5-device.c:1830
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "Високоточне відтворення (приймач A2DP)"
 
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 19a7ae5c..daa8b5d8 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -555,7 +555,6 @@ msgid "Line In"
 msgstr "输入插孔"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1710
 msgid "Microphone"
 msgstr "话筒"
@@ -617,7 +616,6 @@ msgid "No Bass Boost"
 msgstr "无重低音增强"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1717
 msgid "Speaker"
 msgstr "扬声器"
@@ -790,7 +788,6 @@ msgstr "多声道双工"
 
 #: ../src/modules/alsa/alsa-mixer.c:4155
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2295
 #: ../src/modules/bluetooth/module-bluez5-device.c:1941
 msgid "Off"
 msgstr "关"
@@ -911,49 +908,40 @@ msgstr ""
 "snd_pcm_mmap_begin() 返回的值非常大:%lu 字节(%lu ms)。\n"
 "这很可能是由 ALSA 驱动程序 %s 中的 bug。请向 ALSA 开发者举报这个问题。"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2089
 #: ../src/modules/bluetooth/module-bluez5-device.c:1700
 msgid "Headset"
 msgstr "耳机"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1705
 msgid "Handsfree"
 msgstr "免手操作"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1723
 msgid "Headphone"
 msgstr "头戴耳机"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1728
 msgid "Portable"
 msgstr "便携式"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1733
 msgid "Car"
 msgstr "车内"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1738
 msgid "HiFi"
 msgstr "高保真"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1743
 msgid "Phone"
 msgstr "电话"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2137
 #: ../src/modules/bluetooth/module-bluez5-device.c:1695
 #: ../src/modules/bluetooth/module-bluez5-device.c:1711
 #: ../src/modules/bluetooth/module-bluez5-device.c:1749
 msgid "Bluetooth Output"
 msgstr "蓝牙输出"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2140
 #: ../src/modules/bluetooth/module-bluez5-device.c:1694
 #: ../src/modules/bluetooth/module-bluez5-device.c:1716
 #: ../src/modules/bluetooth/module-bluez5-device.c:1722
@@ -961,22 +949,6 @@ msgstr "蓝牙输出"
 msgid "Bluetooth Input"
 msgstr "蓝牙输入"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2176
-msgid "High Fidelity Playback (A2DP)"
-msgstr "高保真回放(A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2187
-msgid "High Fidelity Capture (A2DP)"
-msgstr "高保真采集(A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "双工电话(HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Handsfree Gateway"
-msgstr "蓝牙音频网关"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1786
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "高保真回放 (A2DP 信宿)"
diff --git a/po/zh_TW.po b/po/zh_TW.po
index 6f6dc9ac..5233a9ec 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -558,7 +558,6 @@ msgid "Line In"
 msgstr "線路輸入"
 
 #: ../src/modules/alsa/alsa-mixer.c:2383 ../src/modules/alsa/alsa-mixer.c:2461
-#: ../src/modules/bluetooth/module-bluez4-device.c:2104
 #: ../src/modules/bluetooth/module-bluez5-device.c:1773
 msgid "Microphone"
 msgstr "麥克風"
@@ -620,7 +619,6 @@ msgid "No Bass Boost"
 msgstr "無低音增強"
 
 #: ../src/modules/alsa/alsa-mixer.c:2398
-#: ../src/modules/bluetooth/module-bluez4-device.c:2109
 #: ../src/modules/bluetooth/module-bluez5-device.c:1780
 msgid "Speaker"
 msgstr "喇叭"
@@ -805,7 +803,6 @@ msgstr "立體聲雙工"
 
 #: ../src/modules/alsa/alsa-mixer.c:4158
 #: ../src/modules/alsa/module-alsa-card.c:186
-#: ../src/modules/bluetooth/module-bluez4-device.c:2324
 #: ../src/modules/bluetooth/module-bluez5-device.c:2028
 msgid "Off"
 msgstr "關閉"
@@ -924,49 +921,40 @@ msgstr ""
 "snd_pcm_mmap_begin() 傳回超出預期的大值:%lu bytes (%lu ms)。\n"
 "這很能是 ALSA 驅動程式「%s」的臭蟲。請回報這個問題給 ALSA 開發者。"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2094
 #: ../src/modules/bluetooth/module-bluez5-device.c:1763
 msgid "Headset"
 msgstr "耳麥"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2099
 #: ../src/modules/bluetooth/module-bluez5-device.c:1768
 msgid "Handsfree"
 msgstr "免持裝置"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2114
 #: ../src/modules/bluetooth/module-bluez5-device.c:1786
 msgid "Headphone"
 msgstr "頭戴式耳機"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2119
 #: ../src/modules/bluetooth/module-bluez5-device.c:1791
 msgid "Portable"
 msgstr "可攜裝置"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2124
 #: ../src/modules/bluetooth/module-bluez5-device.c:1796
 msgid "Car"
 msgstr "汽車"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2129
 #: ../src/modules/bluetooth/module-bluez5-device.c:1801
 msgid "HiFi"
 msgstr "HiFi"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2134
 #: ../src/modules/bluetooth/module-bluez5-device.c:1806
 msgid "Phone"
 msgstr "手機"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2142
 #: ../src/modules/bluetooth/module-bluez5-device.c:1758
 #: ../src/modules/bluetooth/module-bluez5-device.c:1774
 #: ../src/modules/bluetooth/module-bluez5-device.c:1812
 msgid "Bluetooth Output"
 msgstr "藍牙輸出"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2145
 #: ../src/modules/bluetooth/module-bluez5-device.c:1757
 #: ../src/modules/bluetooth/module-bluez5-device.c:1779
 #: ../src/modules/bluetooth/module-bluez5-device.c:1785
@@ -974,22 +962,6 @@ msgstr "藍牙輸出"
 msgid "Bluetooth Input"
 msgstr "藍牙輸入"
 
-#: ../src/modules/bluetooth/module-bluez4-device.c:2186
-msgid "High Fidelity Playback (A2DP)"
-msgstr "高傳真播放裝置 (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2198
-msgid "High Fidelity Capture (A2DP)"
-msgstr "高傳真擷取裝置 (A2DP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2210
-msgid "Telephony Duplex (HSP/HFP)"
-msgstr "電話雙工 (HSP/HFP)"
-
-#: ../src/modules/bluetooth/module-bluez4-device.c:2223
-msgid "Handsfree Gateway"
-msgstr "免持閘道"
-
 #: ../src/modules/bluetooth/module-bluez5-device.c:1853
 msgid "High Fidelity Playback (A2DP Sink)"
 msgstr "高傳真播放裝置 (A2DP Sink)"
diff --git a/src/Makefile.am b/src/Makefile.am
index 6fbd7050..eb711f27 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1462,13 +1462,6 @@ modlibexec_LTLIBRARIES += \
 		module-bluetooth-policy.la
 endif
 
-if HAVE_BLUEZ_4
-modlibexec_LTLIBRARIES += \
-		libbluez4-util.la \
-		module-bluez4-discover.la \
-		module-bluez4-device.la
-endif
-
 if HAVE_BLUEZ_5
 modlibexec_LTLIBRARIES += \
 		libbluez5-util.la \
@@ -2118,25 +2111,6 @@ module_bluetooth_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_bluetooth_discover_la_LIBADD = $(MODULE_LIBADD)
 module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_bluetooth_discover
 
-# Bluetooth BlueZ 4 sink / source
-module_bluez4_discover_la_SOURCES = modules/bluetooth/module-bluez4-discover.c
-module_bluez4_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_bluez4_discover_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libbluez4-util.la
-module_bluez4_discover_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DPA_MODULE_NAME=module_bluez4_discover
-
-libbluez4_util_la_SOURCES = \
-		modules/bluetooth/a2dp-codecs.h \
-		modules/bluetooth/bluez4-util.c \
-		modules/bluetooth/bluez4-util.h
-libbluez4_util_la_LDFLAGS = -avoid-version
-libbluez4_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
-libbluez4_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-
-module_bluez4_device_la_SOURCES = modules/bluetooth/module-bluez4-device.c modules/bluetooth/rtp.h
-module_bluez4_device_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_bluez4_device_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(SBC_LIBS) libbluez4-util.la
-module_bluez4_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SBC_CFLAGS) -DPA_MODULE_NAME=module_bluez4_device
-
 # Bluetooth BlueZ 5 sink / source
 libbluez5_util_la_SOURCES = \
 		modules/bluetooth/bluez5-util.c \
diff --git a/src/modules/bluetooth/bluez4-util.c b/src/modules/bluetooth/bluez4-util.c
deleted file mode 100644
index ca606193..00000000
--- a/src/modules/bluetooth/bluez4-util.c
+++ /dev/null
@@ -1,1851 +0,0 @@
-/***
-  This file is part of PulseAudio.
-
-  Copyright 2008-2013 João Paulo Rechi Vita
-
-  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, see <http://www.gnu.org/licenses/>.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/shared.h>
-#include <pulsecore/dbus-shared.h>
-
-#include "bluez4-util.h"
-#include "a2dp-codecs.h"
-
-#define ENDPOINT_PATH_HFP_AG "/MediaEndpoint/BlueZ4/HFPAG"
-#define ENDPOINT_PATH_HFP_HS "/MediaEndpoint/BlueZ4/HFPHS"
-#define ENDPOINT_PATH_A2DP_SOURCE "/MediaEndpoint/BlueZ4/A2DPSource"
-#define ENDPOINT_PATH_A2DP_SINK "/MediaEndpoint/BlueZ4/A2DPSink"
-
-#define ENDPOINT_INTROSPECT_XML                                         \
-    DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                           \
-    "<node>"                                                            \
-    " <interface name=\"org.bluez.MediaEndpoint\">"                     \
-    "  <method name=\"SetConfiguration\">"                              \
-    "   <arg name=\"transport\" direction=\"in\" type=\"o\"/>"          \
-    "   <arg name=\"configuration\" direction=\"in\" type=\"ay\"/>"     \
-    "  </method>"                                                       \
-    "  <method name=\"SelectConfiguration\">"                           \
-    "   <arg name=\"capabilities\" direction=\"in\" type=\"ay\"/>"      \
-    "   <arg name=\"configuration\" direction=\"out\" type=\"ay\"/>"    \
-    "  </method>"                                                       \
-    "  <method name=\"ClearConfiguration\">"                            \
-    "  </method>"                                                       \
-    "  <method name=\"Release\">"                                       \
-    "  </method>"                                                       \
-    " </interface>"                                                     \
-    " <interface name=\"org.freedesktop.DBus.Introspectable\">"         \
-    "  <method name=\"Introspect\">"                                    \
-    "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"              \
-    "  </method>"                                                       \
-    " </interface>"                                                     \
-    "</node>"
-
-struct pa_bluez4_discovery {
-    PA_REFCNT_DECLARE;
-
-    pa_core *core;
-    pa_dbus_connection *connection;
-    PA_LLIST_HEAD(pa_dbus_pending, pending);
-    bool adapters_listed;
-    pa_hashmap *devices;
-    pa_hashmap *transports;
-    pa_hook hooks[PA_BLUEZ4_HOOK_MAX];
-    bool filter_added;
-};
-
-static void get_properties_reply(DBusPendingCall *pending, void *userdata);
-static pa_dbus_pending* send_and_add_to_pending(pa_bluez4_discovery *y, DBusMessage *m, DBusPendingCallNotifyFunction func,
-                                                void *call_data);
-static void found_adapter(pa_bluez4_discovery *y, const char *path);
-static pa_bluez4_device *found_device(pa_bluez4_discovery *y, const char* path);
-static void transport_set_state(pa_bluez4_transport *transport, pa_bluez4_transport_state_t state);
-
-static pa_bluez4_audio_state_t audio_state_from_string(const char* value) {
-    pa_assert(value);
-
-    if (pa_streq(value, "disconnected"))
-        return PA_BLUEZ4_AUDIO_STATE_DISCONNECTED;
-    else if (pa_streq(value, "connecting"))
-        return PA_BLUEZ4_AUDIO_STATE_CONNECTING;
-    else if (pa_streq(value, "connected"))
-        return PA_BLUEZ4_AUDIO_STATE_CONNECTED;
-    else if (pa_streq(value, "playing"))
-        return PA_BLUEZ4_AUDIO_STATE_PLAYING;
-
-    return PA_BLUEZ4_AUDIO_STATE_INVALID;
-}
-
-const char *pa_bluez4_profile_to_string(pa_bluez4_profile_t profile) {
-    switch(profile) {
-        case PA_BLUEZ4_PROFILE_A2DP_SINK:
-            return "a2dp";
-        case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
-            return "a2dp_source";
-        case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
-            return "hsp";
-        case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
-            return "hfgw";
-        case PA_BLUEZ4_PROFILE_OFF:
-            pa_assert_not_reached();
-    }
-
-    pa_assert_not_reached();
-}
-
-static int profile_from_interface(const char *interface, pa_bluez4_profile_t *p) {
-    pa_assert(interface);
-    pa_assert(p);
-
-    if (pa_streq(interface, "org.bluez.AudioSink")) {
-        *p = PA_BLUEZ4_PROFILE_A2DP_SINK;
-        return 0;
-    } else if (pa_streq(interface, "org.bluez.AudioSource")) {
-        *p = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
-        return 0;
-    } else if (pa_streq(interface, "org.bluez.Headset")) {
-        *p = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
-        return 0;
-    } else if (pa_streq(interface, "org.bluez.HandsfreeGateway")) {
-        *p = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
-        return 0;
-    }
-
-    return -1;
-}
-
-static pa_bluez4_transport_state_t audio_state_to_transport_state(pa_bluez4_audio_state_t state) {
-    switch (state) {
-        case PA_BLUEZ4_AUDIO_STATE_INVALID: /* Typically if state hasn't been received yet */
-        case PA_BLUEZ4_AUDIO_STATE_DISCONNECTED:
-        case PA_BLUEZ4_AUDIO_STATE_CONNECTING:
-            return PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED;
-        case PA_BLUEZ4_AUDIO_STATE_CONNECTED:
-            return PA_BLUEZ4_TRANSPORT_STATE_IDLE;
-        case PA_BLUEZ4_AUDIO_STATE_PLAYING:
-            return PA_BLUEZ4_TRANSPORT_STATE_PLAYING;
-    }
-
-    pa_assert_not_reached();
-}
-
-static pa_bluez4_device* device_new(pa_bluez4_discovery *discovery, const char *path) {
-    pa_bluez4_device *d;
-    unsigned i;
-
-    pa_assert(discovery);
-    pa_assert(path);
-
-    d = pa_xnew0(pa_bluez4_device, 1);
-
-    d->discovery = discovery;
-    d->dead = false;
-
-    d->device_info_valid = 0;
-
-    d->name = NULL;
-    d->path = pa_xstrdup(path);
-    d->paired = -1;
-    d->alias = NULL;
-    d->uuids = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
-    d->address = NULL;
-    d->class = -1;
-    d->trusted = -1;
-
-    d->audio_state = PA_BLUEZ4_AUDIO_STATE_INVALID;
-
-    for (i = 0; i < PA_BLUEZ4_PROFILE_COUNT; i++)
-        d->profile_state[i] = PA_BLUEZ4_AUDIO_STATE_INVALID;
-
-    return d;
-}
-
-static void transport_free(pa_bluez4_transport *t) {
-    pa_assert(t);
-
-    pa_xfree(t->owner);
-    pa_xfree(t->path);
-    pa_xfree(t->config);
-    pa_xfree(t);
-}
-
-static void device_free(pa_bluez4_device *d) {
-    pa_bluez4_transport *t;
-    unsigned i;
-
-    pa_assert(d);
-
-    for (i = 0; i < PA_BLUEZ4_PROFILE_COUNT; i++) {
-        if (!(t = d->transports[i]))
-            continue;
-
-        d->transports[i] = NULL;
-        pa_hashmap_remove(d->discovery->transports, t->path);
-        transport_set_state(t, PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED);
-        transport_free(t);
-    }
-
-    if (d->uuids)
-        pa_hashmap_free(d->uuids);
-
-    pa_xfree(d->name);
-    pa_xfree(d->path);
-    pa_xfree(d->alias);
-    pa_xfree(d->address);
-    pa_xfree(d);
-}
-
-static const char *check_variant_property(DBusMessageIter *i) {
-    const char *key;
-
-    pa_assert(i);
-
-    if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
-        pa_log("Property name not a string.");
-        return NULL;
-    }
-
-    dbus_message_iter_get_basic(i, &key);
-
-    if (!dbus_message_iter_next(i)) {
-        pa_log("Property value missing");
-        return NULL;
-    }
-
-    if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
-        pa_log("Property value not a variant.");
-        return NULL;
-    }
-
-    return key;
-}
-
-static int parse_manager_property(pa_bluez4_discovery *y, DBusMessageIter *i, bool is_property_change) {
-    const char *key;
-    DBusMessageIter variant_i;
-
-    pa_assert(y);
-
-    key = check_variant_property(i);
-    if (key == NULL)
-        return -1;
-
-    dbus_message_iter_recurse(i, &variant_i);
-
-    switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
-        case DBUS_TYPE_ARRAY: {
-
-            DBusMessageIter ai;
-            dbus_message_iter_recurse(&variant_i, &ai);
-
-            if (pa_streq(key, "Adapters")) {
-                y->adapters_listed = true;
-
-                if (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_OBJECT_PATH)
-                    break;
-
-                while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
-                    const char *value;
-
-                    dbus_message_iter_get_basic(&ai, &value);
-
-                    found_adapter(y, value);
-
-                    dbus_message_iter_next(&ai);
-                }
-            }
-
-            break;
-        }
-    }
-
-    return 0;
-}
-
-static int parse_adapter_property(pa_bluez4_discovery *y, DBusMessageIter *i, bool is_property_change) {
-    const char *key;
-    DBusMessageIter variant_i;
-
-    pa_assert(y);
-
-    key = check_variant_property(i);
-    if (key == NULL)
-        return -1;
-
-    dbus_message_iter_recurse(i, &variant_i);
-
-    switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
-        case DBUS_TYPE_ARRAY: {
-
-            DBusMessageIter ai;
-            dbus_message_iter_recurse(&variant_i, &ai);
-
-            if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_OBJECT_PATH &&
-                pa_streq(key, "Devices")) {
-
-                while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
-                    const char *value;
-
-                    dbus_message_iter_get_basic(&ai, &value);
-
-                    found_device(y, value);
-
-                    dbus_message_iter_next(&ai);
-                }
-            }
-
-            break;
-        }
-    }
-
-    return 0;
-}
-
-static int parse_device_property(pa_bluez4_device *d, DBusMessageIter *i, bool is_property_change) {
-    const char *key;
-    DBusMessageIter variant_i;
-
-    pa_assert(d);
-
-    key = check_variant_property(i);
-    if (key == NULL)
-        return -1;
-
-    dbus_message_iter_recurse(i, &variant_i);
-
-/*     pa_log_debug("Parsing property org.bluez.Device.%s", key); */
-
-    switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
-        case DBUS_TYPE_STRING: {
-
-            const char *value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "Name")) {
-                pa_xfree(d->name);
-                d->name = pa_xstrdup(value);
-            } else if (pa_streq(key, "Alias")) {
-                pa_xfree(d->alias);
-                d->alias = pa_xstrdup(value);
-            } else if (pa_streq(key, "Address")) {
-                if (is_property_change) {
-                    pa_log("Device property 'Address' expected to be constant but changed for %s", d->path);
-                    return -1;
-                }
-
-                if (d->address) {
-                    pa_log("Device %s: Received a duplicate Address property.", d->path);
-                    return -1;
-                }
-
-                d->address = pa_xstrdup(value);
-            }
-
-/*             pa_log_debug("Value %s", value); */
-
-            break;
-        }
-
-        case DBUS_TYPE_BOOLEAN: {
-
-            dbus_bool_t value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "Paired"))
-                d->paired = !!value;
-            else if (pa_streq(key, "Trusted"))
-                d->trusted = !!value;
-
-/*             pa_log_debug("Value %s", pa_yes_no(value)); */
-
-            break;
-        }
-
-        case DBUS_TYPE_UINT32: {
-
-            uint32_t value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "Class"))
-                d->class = (int) value;
-
-/*             pa_log_debug("Value %u", (unsigned) value); */
-
-            break;
-        }
-
-        case DBUS_TYPE_ARRAY: {
-            DBusMessageIter ai;
-            dbus_message_iter_recurse(&variant_i, &ai);
-
-            if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING && pa_streq(key, "UUIDs")) {
-                DBusMessage *m;
-                bool has_audio = false;
-
-                /* bluetoothd never removes UUIDs from a device object so we
-                 * don't need to check for disappeared UUIDs here. */
-                while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
-                    const char *value;
-                    char *uuid;
-                    struct pa_bluez4_hook_uuid_data uuiddata;
-
-                    dbus_message_iter_get_basic(&ai, &value);
-
-                    if (pa_hashmap_get(d->uuids, value)) {
-                        dbus_message_iter_next(&ai);
-                        continue;
-                    }
-
-                    uuid = pa_xstrdup(value);
-                    pa_hashmap_put(d->uuids, uuid, uuid);
-
-                    pa_log_debug("%s: %s", key, value);
-
-                    uuiddata.device = d;
-                    uuiddata.uuid = value;
-                    pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_DEVICE_UUID_ADDED], &uuiddata);
-
-                    /* Vudentz said the interfaces are here when the UUIDs are announced */
-                    if (pa_streq(PA_BLUEZ4_UUID_HSP_AG, value) || pa_streq(PA_BLUEZ4_UUID_HFP_AG, value)) {
-                        pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.HandsfreeGateway",
-                                                                      "GetProperties"));
-                        send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
-                        has_audio = true;
-                    } else if (pa_streq(PA_BLUEZ4_UUID_HSP_HS, value) || pa_streq(PA_BLUEZ4_UUID_HFP_HF, value)) {
-                        pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset",
-                                                                      "GetProperties"));
-                        send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
-                        has_audio = true;
-                    } else if (pa_streq(PA_BLUEZ4_UUID_A2DP_SINK, value)) {
-                        pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSink",
-                                                                      "GetProperties"));
-                        send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
-                        has_audio = true;
-                    } else if (pa_streq(PA_BLUEZ4_UUID_A2DP_SOURCE, value)) {
-                        pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSource",
-                                                                      "GetProperties"));
-                        send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
-                        has_audio = true;
-                    }
-
-                    dbus_message_iter_next(&ai);
-                }
-
-                /* this might eventually be racy if .Audio is not there yet, but
-                   the State change will come anyway later, so this call is for
-                   cold-detection mostly */
-                if (has_audio) {
-                    pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Audio", "GetProperties"));
-                    send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
-                }
-            }
-
-            break;
-        }
-    }
-
-    return 0;
-}
-
-static const char *transport_state_to_string(pa_bluez4_transport_state_t state) {
-    switch (state) {
-        case PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED:
-            return "disconnected";
-        case PA_BLUEZ4_TRANSPORT_STATE_IDLE:
-            return "idle";
-        case PA_BLUEZ4_TRANSPORT_STATE_PLAYING:
-            return "playing";
-    }
-
-    pa_assert_not_reached();
-}
-
-static int parse_audio_property(pa_bluez4_device *d, const char *interface, DBusMessageIter *i, bool is_property_change) {
-    pa_bluez4_transport *transport;
-    const char *key;
-    DBusMessageIter variant_i;
-    bool is_audio_interface;
-    pa_bluez4_profile_t p = PA_BLUEZ4_PROFILE_OFF;
-
-    pa_assert(d);
-    pa_assert(interface);
-    pa_assert(i);
-
-    if (!(is_audio_interface = pa_streq(interface, "org.bluez.Audio")))
-        if (profile_from_interface(interface, &p) < 0)
-            return 0; /* Interface not known so silently ignore property */
-
-    key = check_variant_property(i);
-    if (key == NULL)
-        return -1;
-
-    transport = p == PA_BLUEZ4_PROFILE_OFF ? NULL : d->transports[p];
-
-    dbus_message_iter_recurse(i, &variant_i);
-
-/*     pa_log_debug("Parsing property org.bluez.{Audio|AudioSink|AudioSource|Headset}.%s", key); */
-
-    switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
-        case DBUS_TYPE_STRING: {
-
-            const char *value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "State")) {
-                pa_bluez4_audio_state_t state = audio_state_from_string(value);
-
-                pa_log_debug("Device %s interface %s property 'State' changed to value '%s'", d->path, interface, value);
-
-                if (state == PA_BLUEZ4_AUDIO_STATE_INVALID)
-                    return -1;
-
-                if (is_audio_interface) {
-                    d->audio_state = state;
-                    break;
-                }
-
-                pa_assert(p != PA_BLUEZ4_PROFILE_OFF);
-
-                d->profile_state[p] = state;
-
-                if (!transport)
-                    break;
-
-                transport_set_state(transport, audio_state_to_transport_state(state));
-            }
-
-            break;
-        }
-
-        case DBUS_TYPE_UINT16: {
-            uint16_t value;
-
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "MicrophoneGain")) {
-                uint16_t gain;
-
-                pa_log_debug("dbus: property '%s' changed to value '%u'", key, value);
-
-                if (!transport) {
-                    pa_log("Volume change does not have an associated transport");
-                    return -1;
-                }
-
-                if ((gain = PA_MIN(value, HSP_MAX_GAIN)) == transport->microphone_gain)
-                    break;
-
-                transport->microphone_gain = gain;
-                pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED], transport);
-            } else if (pa_streq(key, "SpeakerGain")) {
-                uint16_t gain;
-
-                pa_log_debug("dbus: property '%s' changed to value '%u'", key, value);
-
-                if (!transport) {
-                    pa_log("Volume change does not have an associated transport");
-                    return -1;
-                }
-
-                if ((gain = PA_MIN(value, HSP_MAX_GAIN)) == transport->speaker_gain)
-                    break;
-
-                transport->speaker_gain = gain;
-                pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED], transport);
-            }
-
-            break;
-        }
-    }
-
-    return 0;
-}
-
-static void run_callback(pa_bluez4_device *d, bool dead) {
-    pa_assert(d);
-
-    if (d->device_info_valid != 1)
-        return;
-
-    d->dead = dead;
-    pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_DEVICE_CONNECTION_CHANGED], d);
-}
-
-static void remove_all_devices(pa_bluez4_discovery *y) {
-    pa_bluez4_device *d;
-
-    pa_assert(y);
-
-    while ((d = pa_hashmap_steal_first(y->devices))) {
-        run_callback(d, true);
-        device_free(d);
-    }
-}
-
-static pa_bluez4_device *found_device(pa_bluez4_discovery *y, const char* path) {
-    DBusMessage *m;
-    pa_bluez4_device *d;
-
-    pa_assert(y);
-    pa_assert(path);
-
-    d = pa_hashmap_get(y->devices, path);
-    if (d)
-        return d;
-
-    d = device_new(y, path);
-
-    pa_hashmap_put(y->devices, d->path, d);
-
-    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Device", "GetProperties"));
-    send_and_add_to_pending(y, m, get_properties_reply, d);
-
-    /* Before we read the other properties (Audio, AudioSink, AudioSource,
-     * Headset) we wait that the UUID is read */
-    return d;
-}
-
-static void get_properties_reply(DBusPendingCall *pending, void *userdata) {
-    DBusMessage *r;
-    DBusMessageIter arg_i, element_i;
-    pa_dbus_pending *p;
-    pa_bluez4_device *d;
-    pa_bluez4_discovery *y;
-    int valid;
-    bool old_any_connected;
-
-    pa_assert_se(p = userdata);
-    pa_assert_se(y = p->context_data);
-    pa_assert_se(r = dbus_pending_call_steal_reply(pending));
-
-/*     pa_log_debug("Got %s.GetProperties response for %s", */
-/*                  dbus_message_get_interface(p->message), */
-/*                  dbus_message_get_path(p->message)); */
-
-    /* We don't use p->call_data here right-away since the device
-     * might already be invalidated at this point */
-
-    if (dbus_message_has_interface(p->message, "org.bluez.Manager") ||
-        dbus_message_has_interface(p->message, "org.bluez.Adapter"))
-        d = NULL;
-    else if (!(d = pa_hashmap_get(y->devices, dbus_message_get_path(p->message)))) {
-        pa_log_warn("Received GetProperties() reply from unknown device: %s (device removed?)", dbus_message_get_path(p->message));
-        goto finish2;
-    }
-
-    pa_assert(p->call_data == d);
-
-    if (d != NULL) {
-        old_any_connected = pa_bluez4_device_any_audio_connected(d);
-        valid = dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR ? -1 : 1;
-
-        if (dbus_message_is_method_call(p->message, "org.bluez.Device", "GetProperties"))
-            d->device_info_valid = valid;
-    }
-
-    if (dbus_message_is_error(r, DBUS_ERROR_SERVICE_UNKNOWN)) {
-        pa_log_debug("Bluetooth daemon is apparently not available.");
-        remove_all_devices(y);
-        goto finish2;
-    }
-
-    if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
-        pa_log("%s.GetProperties() failed: %s: %s", dbus_message_get_interface(p->message), dbus_message_get_error_name(r),
-               pa_dbus_get_error_message(r));
-        goto finish;
-    }
-
-    if (!dbus_message_iter_init(r, &arg_i)) {
-        pa_log("GetProperties reply has no arguments.");
-        goto finish;
-    }
-
-    if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
-        pa_log("GetProperties argument is not an array.");
-        goto finish;
-    }
-
-    dbus_message_iter_recurse(&arg_i, &element_i);
-    while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
-
-        if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
-            DBusMessageIter dict_i;
-
-            dbus_message_iter_recurse(&element_i, &dict_i);
-
-            if (dbus_message_has_interface(p->message, "org.bluez.Manager")) {
-                if (parse_manager_property(y, &dict_i, false) < 0)
-                    goto finish;
-
-            } else if (dbus_message_has_interface(p->message, "org.bluez.Adapter")) {
-                if (parse_adapter_property(y, &dict_i, false) < 0)
-                    goto finish;
-
-            } else if (dbus_message_has_interface(p->message, "org.bluez.Device")) {
-                if (parse_device_property(d, &dict_i, false) < 0)
-                    goto finish;
-
-            } else if (parse_audio_property(d, dbus_message_get_interface(p->message), &dict_i, false) < 0)
-                goto finish;
-
-        }
-
-        dbus_message_iter_next(&element_i);
-    }
-
-finish:
-    if (d != NULL && old_any_connected != pa_bluez4_device_any_audio_connected(d))
-        run_callback(d, false);
-
-finish2:
-    dbus_message_unref(r);
-
-    PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p);
-    pa_dbus_pending_free(p);
-}
-
-static pa_dbus_pending* send_and_add_to_pending(pa_bluez4_discovery *y, DBusMessage *m, DBusPendingCallNotifyFunction func,
-                                                void *call_data) {
-    pa_dbus_pending *p;
-    DBusPendingCall *call;
-
-    pa_assert(y);
-    pa_assert(m);
-
-    pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(y->connection), m, &call, -1));
-
-    p = pa_dbus_pending_new(pa_dbus_connection_get(y->connection), m, call, y, call_data);
-    PA_LLIST_PREPEND(pa_dbus_pending, y->pending, p);
-    dbus_pending_call_set_notify(call, func, p, NULL);
-
-    return p;
-}
-
-static void register_endpoint_reply(DBusPendingCall *pending, void *userdata) {
-    DBusMessage *r;
-    pa_dbus_pending *p;
-    pa_bluez4_discovery *y;
-    char *endpoint;
-
-    pa_assert(pending);
-    pa_assert_se(p = userdata);
-    pa_assert_se(y = p->context_data);
-    pa_assert_se(endpoint = p->call_data);
-    pa_assert_se(r = dbus_pending_call_steal_reply(pending));
-
-    if (dbus_message_is_error(r, DBUS_ERROR_SERVICE_UNKNOWN)) {
-        pa_log_debug("Bluetooth daemon is apparently not available.");
-        remove_all_devices(y);
-        goto finish;
-    }
-
-    if (dbus_message_is_error(r, PA_BLUEZ4_ERROR_NOT_SUPPORTED)) {
-        pa_log_info("Couldn't register endpoint %s, because BlueZ is configured to disable the endpoint type.", endpoint);
-        goto finish;
-    }
-
-    if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
-        pa_log("org.bluez.Media.RegisterEndpoint() failed: %s: %s", dbus_message_get_error_name(r),
-               pa_dbus_get_error_message(r));
-        goto finish;
-    }
-
-finish:
-    dbus_message_unref(r);
-
-    PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p);
-    pa_dbus_pending_free(p);
-
-    pa_xfree(endpoint);
-}
-
-static void register_endpoint(pa_bluez4_discovery *y, const char *path, const char *endpoint, const char *uuid) {
-    DBusMessage *m;
-    DBusMessageIter i, d;
-    uint8_t codec = 0;
-
-    pa_log_debug("Registering %s on adapter %s.", endpoint, path);
-
-    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Media", "RegisterEndpoint"));
-
-    dbus_message_iter_init_append(m, &i);
-
-    pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, &endpoint));
-
-    dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                                    DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
-                                    &d);
-
-    pa_dbus_append_basic_variant_dict_entry(&d, "UUID", DBUS_TYPE_STRING, &uuid);
-
-    pa_dbus_append_basic_variant_dict_entry(&d, "Codec", DBUS_TYPE_BYTE, &codec);
-
-    if (pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_HF)) {
-        uint8_t capability = 0;
-        pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capability, 1);
-    } else {
-        a2dp_sbc_t capabilities;
-
-        capabilities.channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL |
-                                    SBC_CHANNEL_MODE_STEREO | SBC_CHANNEL_MODE_JOINT_STEREO;
-        capabilities.frequency = SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 |
-                                 SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_48000;
-        capabilities.allocation_method = SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS;
-        capabilities.subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8;
-        capabilities.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 |
-                                    SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16;
-        capabilities.min_bitpool = MIN_BITPOOL;
-        capabilities.max_bitpool = MAX_BITPOOL;
-
-        pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
-    }
-
-    dbus_message_iter_close_container(&i, &d);
-
-    send_and_add_to_pending(y, m, register_endpoint_reply, pa_xstrdup(endpoint));
-}
-
-static void found_adapter(pa_bluez4_discovery *y, const char *path) {
-    DBusMessage *m;
-
-    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "GetProperties"));
-    send_and_add_to_pending(y, m, get_properties_reply, NULL);
-
-    register_endpoint(y, path, ENDPOINT_PATH_HFP_AG, PA_BLUEZ4_UUID_HFP_AG);
-    register_endpoint(y, path, ENDPOINT_PATH_HFP_HS, PA_BLUEZ4_UUID_HFP_HF);
-    register_endpoint(y, path, ENDPOINT_PATH_A2DP_SOURCE, PA_BLUEZ4_UUID_A2DP_SOURCE);
-    register_endpoint(y, path, ENDPOINT_PATH_A2DP_SINK, PA_BLUEZ4_UUID_A2DP_SINK);
-}
-
-static void list_adapters(pa_bluez4_discovery *y) {
-    DBusMessage *m;
-    pa_assert(y);
-
-    pa_assert_se(m = dbus_message_new_method_call("org.bluez", "/", "org.bluez.Manager", "GetProperties"));
-    send_and_add_to_pending(y, m, get_properties_reply, NULL);
-}
-
-static int transport_parse_property(pa_bluez4_transport *t, DBusMessageIter *i) {
-    const char *key;
-    DBusMessageIter variant_i;
-
-    key = check_variant_property(i);
-    if (key == NULL)
-        return -1;
-
-    dbus_message_iter_recurse(i, &variant_i);
-
-    switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
-        case DBUS_TYPE_BOOLEAN: {
-
-            dbus_bool_t value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "NREC") && t->nrec != value) {
-                t->nrec = value;
-                pa_log_debug("Transport %s: Property 'NREC' changed to %s.", t->path, t->nrec ? "True" : "False");
-                pa_hook_fire(&t->device->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_NREC_CHANGED], t);
-            }
-
-            break;
-         }
-    }
-
-    return 0;
-}
-
-static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
-    DBusError err;
-    pa_bluez4_discovery *y;
-
-    pa_assert(bus);
-    pa_assert(m);
-
-    pa_assert_se(y = userdata);
-
-    dbus_error_init(&err);
-
-    pa_log_debug("dbus: interface=%s, path=%s, member=%s",
-            dbus_message_get_interface(m),
-            dbus_message_get_path(m),
-            dbus_message_get_member(m));
-
-    if (dbus_message_is_signal(m, "org.bluez.Adapter", "DeviceRemoved")) {
-        const char *path;
-        pa_bluez4_device *d;
-
-        if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
-            pa_log("Failed to parse org.bluez.Adapter.DeviceRemoved: %s", err.message);
-            goto fail;
-        }
-
-        pa_log_debug("Device %s removed", path);
-
-        if ((d = pa_hashmap_remove(y->devices, path))) {
-            run_callback(d, true);
-            device_free(d);
-        }
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-    } else if (dbus_message_is_signal(m, "org.bluez.Adapter", "DeviceCreated")) {
-        const char *path;
-
-        if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
-            pa_log("Failed to parse org.bluez.Adapter.DeviceCreated: %s", err.message);
-            goto fail;
-        }
-
-        pa_log_debug("Device %s created", path);
-
-        found_device(y, path);
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-    } else if (dbus_message_is_signal(m, "org.bluez.Manager", "AdapterAdded")) {
-        const char *path;
-
-        if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
-            pa_log("Failed to parse org.bluez.Manager.AdapterAdded: %s", err.message);
-            goto fail;
-        }
-
-        if (!y->adapters_listed) {
-            pa_log_debug("Ignoring 'AdapterAdded' because initial adapter list has not been received yet.");
-            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-        }
-
-        pa_log_debug("Adapter %s created", path);
-
-        found_adapter(y, path);
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-    } else if (dbus_message_is_signal(m, "org.bluez.Audio", "PropertyChanged") ||
-               dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") ||
-               dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged") ||
-               dbus_message_is_signal(m, "org.bluez.AudioSource", "PropertyChanged") ||
-               dbus_message_is_signal(m, "org.bluez.HandsfreeGateway", "PropertyChanged") ||
-               dbus_message_is_signal(m, "org.bluez.Device", "PropertyChanged")) {
-
-        pa_bluez4_device *d;
-
-        if ((d = pa_hashmap_get(y->devices, dbus_message_get_path(m)))) {
-            DBusMessageIter arg_i;
-            bool old_any_connected = pa_bluez4_device_any_audio_connected(d);
-
-            if (!dbus_message_iter_init(m, &arg_i)) {
-                pa_log("Failed to parse PropertyChanged for device %s", d->path);
-                goto fail;
-            }
-
-            if (dbus_message_has_interface(m, "org.bluez.Device")) {
-                if (parse_device_property(d, &arg_i, true) < 0)
-                    goto fail;
-
-            } else if (parse_audio_property(d, dbus_message_get_interface(m), &arg_i, true) < 0)
-                goto fail;
-
-            if (old_any_connected != pa_bluez4_device_any_audio_connected(d))
-                run_callback(d, false);
-        }
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-    } else if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
-        const char *name, *old_owner, *new_owner;
-
-        if (!dbus_message_get_args(m, &err,
-                                   DBUS_TYPE_STRING, &name,
-                                   DBUS_TYPE_STRING, &old_owner,
-                                   DBUS_TYPE_STRING, &new_owner,
-                                   DBUS_TYPE_INVALID)) {
-            pa_log("Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
-            goto fail;
-        }
-
-        if (pa_streq(name, "org.bluez")) {
-            if (old_owner && *old_owner) {
-                pa_log_debug("Bluetooth daemon disappeared.");
-                remove_all_devices(y);
-                y->adapters_listed = false;
-            }
-
-            if (new_owner && *new_owner) {
-                pa_log_debug("Bluetooth daemon appeared.");
-                list_adapters(y);
-            }
-        }
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-    } else if (dbus_message_is_signal(m, "org.bluez.MediaTransport", "PropertyChanged")) {
-        pa_bluez4_transport *t;
-        DBusMessageIter arg_i;
-
-        if (!(t = pa_hashmap_get(y->transports, dbus_message_get_path(m))))
-            goto fail;
-
-        if (!dbus_message_iter_init(m, &arg_i)) {
-            pa_log("Failed to parse PropertyChanged for transport %s", t->path);
-            goto fail;
-        }
-
-        if (transport_parse_property(t, &arg_i) < 0)
-            goto fail;
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-    }
-
-fail:
-    dbus_error_free(&err);
-
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-pa_bluez4_device* pa_bluez4_discovery_get_by_address(pa_bluez4_discovery *y, const char* address) {
-    pa_bluez4_device *d;
-    void *state = NULL;
-
-    pa_assert(y);
-    pa_assert(PA_REFCNT_VALUE(y) > 0);
-    pa_assert(address);
-
-    while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
-        if (pa_streq(d->address, address))
-            return d->device_info_valid == 1 ? d : NULL;
-
-    return NULL;
-}
-
-pa_bluez4_device* pa_bluez4_discovery_get_by_path(pa_bluez4_discovery *y, const char* path) {
-    pa_bluez4_device *d;
-
-    pa_assert(y);
-    pa_assert(PA_REFCNT_VALUE(y) > 0);
-    pa_assert(path);
-
-    if ((d = pa_hashmap_get(y->devices, path)))
-        if (d->device_info_valid == 1)
-            return d;
-
-    return NULL;
-}
-
-bool pa_bluez4_device_any_audio_connected(const pa_bluez4_device *d) {
-    unsigned i;
-
-    pa_assert(d);
-
-    if (d->dead || d->device_info_valid != 1)
-        return false;
-
-    if (d->audio_state == PA_BLUEZ4_AUDIO_STATE_INVALID)
-        return false;
-
-    /* Make sure audio_state is *not* in CONNECTING state before we fire the
-     * hook to report the new device state. This is actually very important in
-     * order to make module-card-restore work well with headsets: if the headset
-     * supports both HSP and A2DP, one of those profiles is connected first and
-     * then the other, and lastly the Audio interface becomes connected.
-     * Checking only audio_state means that this function will return false at
-     * the time when only the first connection has been made. This is good,
-     * because otherwise, if the first connection is for HSP and we would
-     * already load a new device module instance, and module-card-restore tries
-     * to restore the A2DP profile, that would fail because A2DP is not yet
-     * connected. Waiting until the Audio interface gets connected means that
-     * both headset profiles will be connected when the device module is
-     * loaded. */
-    if (d->audio_state == PA_BLUEZ4_AUDIO_STATE_CONNECTING)
-        return false;
-
-    for (i = 0; i < PA_BLUEZ4_PROFILE_COUNT; i++)
-        if (d->transports[i] && d->transports[i]->state != PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED)
-            return true;
-
-    return false;
-}
-
-int pa_bluez4_transport_acquire(pa_bluez4_transport *t, bool optional, size_t *imtu, size_t *omtu) {
-    const char *accesstype = "rw";
-    DBusMessage *m, *r;
-    DBusError err;
-    int ret;
-    uint16_t i, o;
-
-    pa_assert(t);
-    pa_assert(t->device);
-    pa_assert(t->device->discovery);
-
-    if (optional) {
-        /* FIXME: we are trying to acquire the transport only if the stream is
-           playing, without actually initiating the stream request from our side
-           (which is typically undesireable specially for hfgw use-cases.
-           However this approach is racy, since the stream could have been
-           suspended in the meantime, so we can't really guarantee that the
-           stream will not be requested until BlueZ's API supports this
-           atomically. */
-        if (t->state < PA_BLUEZ4_TRANSPORT_STATE_PLAYING) {
-            pa_log_info("Failed optional acquire of transport %s", t->path);
-            return -1;
-        }
-    }
-
-    dbus_error_init(&err);
-
-    pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport", "Acquire"));
-    pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
-    r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
-    dbus_message_unref(m);
-    m = NULL;
-
-    if (!r) {
-        dbus_error_free(&err);
-        return -1;
-    }
-
-    if (!dbus_message_get_args(r, &err, DBUS_TYPE_UNIX_FD, &ret, DBUS_TYPE_UINT16, &i, DBUS_TYPE_UINT16, &o,
-                               DBUS_TYPE_INVALID)) {
-        pa_log("Failed to parse org.bluez.MediaTransport.Acquire(): %s", err.message);
-        ret = -1;
-        dbus_error_free(&err);
-        goto fail;
-    }
-
-    if (imtu)
-        *imtu = i;
-
-    if (omtu)
-        *omtu = o;
-
-fail:
-    dbus_message_unref(r);
-    return ret;
-}
-
-void pa_bluez4_transport_release(pa_bluez4_transport *t) {
-    const char *accesstype = "rw";
-    DBusMessage *m, *r;
-    DBusError err;
-
-    pa_assert(t);
-    pa_assert(t->device);
-    pa_assert(t->device->discovery);
-
-    dbus_error_init(&err);
-
-    pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport", "Release"));
-    pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
-    r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
-    dbus_message_unref(m);
-    m = NULL;
-    if (r) {
-        dbus_message_unref(r);
-        r = NULL;
-    }
-
-    if (dbus_error_is_set(&err)) {
-        pa_log("Failed to release transport %s: %s", t->path, err.message);
-        dbus_error_free(&err);
-    } else
-        pa_log_info("Transport %s released", t->path);
-}
-
-static void set_property(pa_bluez4_discovery *y, const char *bus, const char *path, const char *interface,
-                         const char *prop_name, int prop_type, void *prop_value) {
-    DBusMessage *m;
-    DBusMessageIter i;
-
-    pa_assert(y);
-    pa_assert(path);
-    pa_assert(interface);
-    pa_assert(prop_name);
-
-    pa_assert_se(m = dbus_message_new_method_call(bus, path, interface, "SetProperty"));
-    dbus_message_iter_init_append(m, &i);
-    pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &prop_name));
-    pa_dbus_append_basic_variant(&i, prop_type, prop_value);
-
-    dbus_message_set_no_reply(m, true);
-    pa_assert_se(dbus_connection_send(pa_dbus_connection_get(y->connection), m, NULL));
-    dbus_message_unref(m);
-}
-
-void pa_bluez4_transport_set_microphone_gain(pa_bluez4_transport *t, uint16_t value) {
-    dbus_uint16_t gain = PA_MIN(value, HSP_MAX_GAIN);
-
-    pa_assert(t);
-    pa_assert(t->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
-
-    set_property(t->device->discovery, "org.bluez", t->device->path, "org.bluez.Headset",
-                 "MicrophoneGain", DBUS_TYPE_UINT16, &gain);
-}
-
-void pa_bluez4_transport_set_speaker_gain(pa_bluez4_transport *t, uint16_t value) {
-    dbus_uint16_t gain = PA_MIN(value, HSP_MAX_GAIN);
-
-    pa_assert(t);
-    pa_assert(t->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
-
-    set_property(t->device->discovery, "org.bluez", t->device->path, "org.bluez.Headset",
-                 "SpeakerGain", DBUS_TYPE_UINT16, &gain);
-}
-
-static int setup_dbus(pa_bluez4_discovery *y) {
-    DBusError err;
-
-    dbus_error_init(&err);
-
-    if (!(y->connection = pa_dbus_bus_get(y->core, DBUS_BUS_SYSTEM, &err))) {
-        pa_log("Failed to get D-Bus connection: %s", err.message);
-        dbus_error_free(&err);
-        return -1;
-    }
-
-    return 0;
-}
-
-static pa_bluez4_transport *transport_new(pa_bluez4_device *d, const char *owner, const char *path, pa_bluez4_profile_t p,
-                                             const uint8_t *config, int size) {
-    pa_bluez4_transport *t;
-
-    t = pa_xnew0(pa_bluez4_transport, 1);
-    t->device = d;
-    t->owner = pa_xstrdup(owner);
-    t->path = pa_xstrdup(path);
-    t->profile = p;
-    t->config_size = size;
-
-    if (size > 0) {
-        t->config = pa_xnew(uint8_t, size);
-        memcpy(t->config, config, size);
-    }
-
-    t->state = audio_state_to_transport_state(d->profile_state[p]);
-
-    return t;
-}
-
-static void transport_set_state(pa_bluez4_transport *transport, pa_bluez4_transport_state_t state) {
-    if (transport->state == state)
-        return;
-
-    pa_log_debug("Transport %s state: %s -> %s",
-                 transport->path, transport_state_to_string(transport->state), transport_state_to_string(state));
-
-    transport->state = state;
-
-    pa_hook_fire(&transport->device->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED], transport);
-}
-
-static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) {
-    pa_bluez4_discovery *y = userdata;
-    pa_bluez4_device *d;
-    pa_bluez4_transport *t;
-    const char *sender, *path, *dev_path = NULL, *uuid = NULL;
-    uint8_t *config = NULL;
-    int size = 0;
-    bool nrec = false;
-    pa_bluez4_profile_t p;
-    DBusMessageIter args, props;
-    DBusMessage *r;
-    bool old_any_connected;
-
-    if (!dbus_message_iter_init(m, &args) || !pa_streq(dbus_message_get_signature(m), "oa{sv}")) {
-        pa_log("Invalid signature for method SetConfiguration");
-        goto fail2;
-    }
-
-    dbus_message_iter_get_basic(&args, &path);
-
-    if (pa_hashmap_get(y->transports, path)) {
-        pa_log("org.bluez.MediaEndpoint.SetConfiguration: Transport %s is already configured.", path);
-        goto fail2;
-    }
-
-    pa_assert_se(dbus_message_iter_next(&args));
-
-    dbus_message_iter_recurse(&args, &props);
-    if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
-        goto fail;
-
-    /* Read transport properties */
-    while (dbus_message_iter_get_arg_type(&props) == DBUS_TYPE_DICT_ENTRY) {
-        const char *key;
-        DBusMessageIter value, entry;
-        int var;
-
-        dbus_message_iter_recurse(&props, &entry);
-        dbus_message_iter_get_basic(&entry, &key);
-
-        dbus_message_iter_next(&entry);
-        dbus_message_iter_recurse(&entry, &value);
-
-        var = dbus_message_iter_get_arg_type(&value);
-
-        if (strcasecmp(key, "UUID") == 0) {
-            if (var != DBUS_TYPE_STRING)
-                goto fail;
-
-            dbus_message_iter_get_basic(&value, &uuid);
-        } else if (strcasecmp(key, "Device") == 0) {
-            if (var != DBUS_TYPE_OBJECT_PATH)
-                goto fail;
-
-            dbus_message_iter_get_basic(&value, &dev_path);
-        } else if (strcasecmp(key, "NREC") == 0) {
-            dbus_bool_t tmp_boolean;
-            if (var != DBUS_TYPE_BOOLEAN)
-                goto fail;
-
-            dbus_message_iter_get_basic(&value, &tmp_boolean);
-            nrec = tmp_boolean;
-        } else if (strcasecmp(key, "Configuration") == 0) {
-            DBusMessageIter array;
-            if (var != DBUS_TYPE_ARRAY)
-                goto fail;
-
-            dbus_message_iter_recurse(&value, &array);
-            dbus_message_iter_get_fixed_array(&array, &config, &size);
-        }
-
-        dbus_message_iter_next(&props);
-    }
-
-    d = found_device(y, dev_path);
-    if (!d)
-        goto fail;
-
-    if (dbus_message_has_path(m, ENDPOINT_PATH_HFP_AG))
-        p = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
-    else if (dbus_message_has_path(m, ENDPOINT_PATH_HFP_HS))
-        p = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
-    else if (dbus_message_has_path(m, ENDPOINT_PATH_A2DP_SOURCE))
-        p = PA_BLUEZ4_PROFILE_A2DP_SINK;
-    else
-        p = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
-
-    if (d->transports[p] != NULL) {
-        pa_log("Cannot configure transport %s because profile %d is already used", path, p);
-        goto fail2;
-    }
-
-    old_any_connected = pa_bluez4_device_any_audio_connected(d);
-
-    sender = dbus_message_get_sender(m);
-
-    t = transport_new(d, sender, path, p, config, size);
-    if (nrec)
-        t->nrec = nrec;
-
-    d->transports[p] = t;
-    pa_assert_se(pa_hashmap_put(y->transports, t->path, t) >= 0);
-
-    pa_log_debug("Transport %s profile %d available", t->path, t->profile);
-
-    pa_assert_se(r = dbus_message_new_method_return(m));
-    pa_assert_se(dbus_connection_send(pa_dbus_connection_get(y->connection), r, NULL));
-    dbus_message_unref(r);
-
-    if (old_any_connected != pa_bluez4_device_any_audio_connected(d))
-        run_callback(d, false);
-
-    return NULL;
-
-fail:
-    pa_log("org.bluez.MediaEndpoint.SetConfiguration: invalid arguments");
-
-fail2:
-    pa_assert_se(r = dbus_message_new_error(m, "org.bluez.MediaEndpoint.Error.InvalidArguments",
-                                            "Unable to set configuration"));
-    return r;
-}
-
-static DBusMessage *endpoint_clear_configuration(DBusConnection *c, DBusMessage *m, void *userdata) {
-    pa_bluez4_discovery *y = userdata;
-    pa_bluez4_transport *t;
-    DBusMessage *r;
-    DBusError e;
-    const char *path;
-
-    dbus_error_init(&e);
-
-    if (!dbus_message_get_args(m, &e, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
-        pa_log("org.bluez.MediaEndpoint.ClearConfiguration: %s", e.message);
-        dbus_error_free(&e);
-        goto fail;
-    }
-
-    if ((t = pa_hashmap_get(y->transports, path))) {
-        bool old_any_connected = pa_bluez4_device_any_audio_connected(t->device);
-
-        pa_log_debug("Clearing transport %s profile %d", t->path, t->profile);
-        t->device->transports[t->profile] = NULL;
-        pa_hashmap_remove(y->transports, t->path);
-        transport_set_state(t, PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED);
-
-        if (old_any_connected != pa_bluez4_device_any_audio_connected(t->device))
-            run_callback(t->device, false);
-
-        transport_free(t);
-    }
-
-    pa_assert_se(r = dbus_message_new_method_return(m));
-
-    return r;
-
-fail:
-    pa_assert_se(r = dbus_message_new_error(m, "org.bluez.MediaEndpoint.Error.InvalidArguments",
-                                            "Unable to clear configuration"));
-    return r;
-}
-
-static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
-
-    switch (freq) {
-        case SBC_SAMPLING_FREQ_16000:
-        case SBC_SAMPLING_FREQ_32000:
-            return 53;
-
-        case SBC_SAMPLING_FREQ_44100:
-
-            switch (mode) {
-                case SBC_CHANNEL_MODE_MONO:
-                case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-                    return 31;
-
-                case SBC_CHANNEL_MODE_STEREO:
-                case SBC_CHANNEL_MODE_JOINT_STEREO:
-                    return 53;
-
-                default:
-                    pa_log_warn("Invalid channel mode %u", mode);
-                    return 53;
-            }
-
-        case SBC_SAMPLING_FREQ_48000:
-
-            switch (mode) {
-                case SBC_CHANNEL_MODE_MONO:
-                case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-                    return 29;
-
-                case SBC_CHANNEL_MODE_STEREO:
-                case SBC_CHANNEL_MODE_JOINT_STEREO:
-                    return 51;
-
-                default:
-                    pa_log_warn("Invalid channel mode %u", mode);
-                    return 51;
-            }
-
-        default:
-            pa_log_warn("Invalid sampling freq %u", freq);
-            return 53;
-    }
-}
-
-static DBusMessage *endpoint_select_configuration(DBusConnection *c, DBusMessage *m, void *userdata) {
-    pa_bluez4_discovery *y = userdata;
-    a2dp_sbc_t *cap, config;
-    uint8_t *pconf = (uint8_t *) &config;
-    int i, size;
-    DBusMessage *r;
-    DBusError e;
-
-    static const struct {
-        uint32_t rate;
-        uint8_t cap;
-    } freq_table[] = {
-        { 16000U, SBC_SAMPLING_FREQ_16000 },
-        { 32000U, SBC_SAMPLING_FREQ_32000 },
-        { 44100U, SBC_SAMPLING_FREQ_44100 },
-        { 48000U, SBC_SAMPLING_FREQ_48000 }
-    };
-
-    dbus_error_init(&e);
-
-    if (!dbus_message_get_args(m, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
-        pa_log("org.bluez.MediaEndpoint.SelectConfiguration: %s", e.message);
-        dbus_error_free(&e);
-        goto fail;
-    }
-
-    if (dbus_message_has_path(m, ENDPOINT_PATH_HFP_AG) || dbus_message_has_path(m, ENDPOINT_PATH_HFP_HS))
-        goto done;
-
-    pa_assert(size == sizeof(config));
-
-    memset(&config, 0, sizeof(config));
-
-    /* Find the lowest freq that is at least as high as the requested
-     * sampling rate */
-    for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++)
-        if (freq_table[i].rate >= y->core->default_sample_spec.rate && (cap->frequency & freq_table[i].cap)) {
-            config.frequency = freq_table[i].cap;
-            break;
-        }
-
-    if ((unsigned) i == PA_ELEMENTSOF(freq_table)) {
-        for (--i; i >= 0; i--) {
-            if (cap->frequency & freq_table[i].cap) {
-                config.frequency = freq_table[i].cap;
-                break;
-            }
-        }
-
-        if (i < 0) {
-            pa_log("Not suitable sample rate");
-            goto fail;
-        }
-    }
-
-    pa_assert((unsigned) i < PA_ELEMENTSOF(freq_table));
-
-    if (y->core->default_sample_spec.channels <= 1) {
-        if (cap->channel_mode & SBC_CHANNEL_MODE_MONO)
-            config.channel_mode = SBC_CHANNEL_MODE_MONO;
-    }
-
-    if (y->core->default_sample_spec.channels >= 2) {
-        if (cap->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
-            config.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
-        else if (cap->channel_mode & SBC_CHANNEL_MODE_STEREO)
-            config.channel_mode = SBC_CHANNEL_MODE_STEREO;
-        else if (cap->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
-            config.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
-        else if (cap->channel_mode & SBC_CHANNEL_MODE_MONO) {
-            config.channel_mode = SBC_CHANNEL_MODE_MONO;
-        } else {
-            pa_log("No supported channel modes");
-            goto fail;
-        }
-    }
-
-    if (cap->block_length & SBC_BLOCK_LENGTH_16)
-        config.block_length = SBC_BLOCK_LENGTH_16;
-    else if (cap->block_length & SBC_BLOCK_LENGTH_12)
-        config.block_length = SBC_BLOCK_LENGTH_12;
-    else if (cap->block_length & SBC_BLOCK_LENGTH_8)
-        config.block_length = SBC_BLOCK_LENGTH_8;
-    else if (cap->block_length & SBC_BLOCK_LENGTH_4)
-        config.block_length = SBC_BLOCK_LENGTH_4;
-    else {
-        pa_log_error("No supported block lengths");
-        goto fail;
-    }
-
-    if (cap->subbands & SBC_SUBBANDS_8)
-        config.subbands = SBC_SUBBANDS_8;
-    else if (cap->subbands & SBC_SUBBANDS_4)
-        config.subbands = SBC_SUBBANDS_4;
-    else {
-        pa_log_error("No supported subbands");
-        goto fail;
-    }
-
-    if (cap->allocation_method & SBC_ALLOCATION_LOUDNESS)
-        config.allocation_method = SBC_ALLOCATION_LOUDNESS;
-    else if (cap->allocation_method & SBC_ALLOCATION_SNR)
-        config.allocation_method = SBC_ALLOCATION_SNR;
-
-    config.min_bitpool = (uint8_t) PA_MAX(MIN_BITPOOL, cap->min_bitpool);
-    config.max_bitpool = (uint8_t) PA_MIN(a2dp_default_bitpool(config.frequency, config.channel_mode), cap->max_bitpool);
-
-done:
-    pa_assert_se(r = dbus_message_new_method_return(m));
-
-    pa_assert_se(dbus_message_append_args(
-                                     r,
-                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pconf, size,
-                                     DBUS_TYPE_INVALID));
-
-    return r;
-
-fail:
-    pa_assert_se(r = dbus_message_new_error(m, "org.bluez.MediaEndpoint.Error.InvalidArguments",
-                                            "Unable to select configuration"));
-    return r;
-}
-
-static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
-    struct pa_bluez4_discovery *y = userdata;
-    DBusMessage *r = NULL;
-    DBusError e;
-    const char *path, *interface, *member;
-
-    pa_assert(y);
-
-    path = dbus_message_get_path(m);
-    interface = dbus_message_get_interface(m);
-    member = dbus_message_get_member(m);
-
-    pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
-
-    dbus_error_init(&e);
-
-    if (!pa_streq(path, ENDPOINT_PATH_A2DP_SOURCE) && !pa_streq(path, ENDPOINT_PATH_A2DP_SINK)
-            && !pa_streq(path, ENDPOINT_PATH_HFP_AG) && !pa_streq(path, ENDPOINT_PATH_HFP_HS))
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-    if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-        const char *xml = ENDPOINT_INTROSPECT_XML;
-
-        pa_assert_se(r = dbus_message_new_method_return(m));
-        pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
-
-    } else if (dbus_message_is_method_call(m, "org.bluez.MediaEndpoint", "SetConfiguration"))
-        r = endpoint_set_configuration(c, m, userdata);
-    else if (dbus_message_is_method_call(m, "org.bluez.MediaEndpoint", "SelectConfiguration"))
-        r = endpoint_select_configuration(c, m, userdata);
-    else if (dbus_message_is_method_call(m, "org.bluez.MediaEndpoint", "ClearConfiguration"))
-        r = endpoint_clear_configuration(c, m, userdata);
-    else
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-    if (r) {
-        pa_assert_se(dbus_connection_send(pa_dbus_connection_get(y->connection), r, NULL));
-        dbus_message_unref(r);
-    }
-
-    return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-pa_bluez4_discovery* pa_bluez4_discovery_get(pa_core *c) {
-    DBusError err;
-    pa_bluez4_discovery *y;
-    DBusConnection *conn;
-    unsigned i;
-    static const DBusObjectPathVTable vtable_endpoint = {
-        .message_function = endpoint_handler,
-    };
-
-    pa_assert(c);
-
-    dbus_error_init(&err);
-
-    if ((y = pa_shared_get(c, "bluez4-discovery")))
-        return pa_bluez4_discovery_ref(y);
-
-    y = pa_xnew0(pa_bluez4_discovery, 1);
-    PA_REFCNT_INIT(y);
-    y->core = c;
-    y->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    y->transports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    PA_LLIST_HEAD_INIT(pa_dbus_pending, y->pending);
-
-    for (i = 0; i < PA_BLUEZ4_HOOK_MAX; i++)
-        pa_hook_init(&y->hooks[i], y);
-
-    pa_shared_set(c, "bluez4-discovery", y);
-
-    if (setup_dbus(y) < 0)
-        goto fail;
-
-    conn = pa_dbus_connection_get(y->connection);
-
-    /* dynamic detection of bluetooth audio devices */
-    if (!dbus_connection_add_filter(conn, filter_cb, y, NULL)) {
-        pa_log_error("Failed to add filter function");
-        goto fail;
-    }
-
-    y->filter_added = true;
-
-    if (pa_dbus_add_matches(
-                conn, &err,
-                "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
-                ",arg0='org.bluez'",
-                "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'",
-                "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'",
-                "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'",
-                "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
-                "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
-                NULL) < 0) {
-        pa_log("Failed to add D-Bus matches: %s", err.message);
-        goto fail;
-    }
-
-    pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_HFP_AG, &vtable_endpoint, y));
-    pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_HFP_HS, &vtable_endpoint, y));
-    pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_A2DP_SOURCE, &vtable_endpoint, y));
-    pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_A2DP_SINK, &vtable_endpoint, y));
-
-    list_adapters(y);
-
-    return y;
-
-fail:
-    if (y)
-        pa_bluez4_discovery_unref(y);
-
-    dbus_error_free(&err);
-
-    return NULL;
-}
-
-pa_bluez4_discovery* pa_bluez4_discovery_ref(pa_bluez4_discovery *y) {
-    pa_assert(y);
-    pa_assert(PA_REFCNT_VALUE(y) > 0);
-
-    PA_REFCNT_INC(y);
-
-    return y;
-}
-
-void pa_bluez4_discovery_unref(pa_bluez4_discovery *y) {
-    unsigned i;
-
-    pa_assert(y);
-    pa_assert(PA_REFCNT_VALUE(y) > 0);
-
-    if (PA_REFCNT_DEC(y) > 0)
-        return;
-
-    pa_dbus_free_pending_list(&y->pending);
-
-    if (y->devices) {
-        remove_all_devices(y);
-        pa_hashmap_free(y->devices);
-    }
-
-    if (y->transports) {
-        pa_assert(pa_hashmap_isempty(y->transports));
-        pa_hashmap_free(y->transports);
-    }
-
-    if (y->connection) {
-        dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_HFP_AG);
-        dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_HFP_HS);
-        dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_A2DP_SOURCE);
-        dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_A2DP_SINK);
-        pa_dbus_remove_matches(
-            pa_dbus_connection_get(y->connection),
-            "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
-            ",arg0='org.bluez'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterRemoved'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
-            "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
-            "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
-            "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
-            "type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
-            "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
-            NULL);
-
-        if (y->filter_added)
-            dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y);
-
-        pa_dbus_connection_unref(y->connection);
-    }
-
-    for (i = 0; i < PA_BLUEZ4_HOOK_MAX; i++)
-        pa_hook_done(&y->hooks[i]);
-
-    if (y->core)
-        pa_shared_remove(y->core, "bluez4-discovery");
-
-    pa_xfree(y);
-}
-
-pa_hook* pa_bluez4_discovery_hook(pa_bluez4_discovery *y, pa_bluez4_hook_t hook) {
-    pa_assert(y);
-    pa_assert(PA_REFCNT_VALUE(y) > 0);
-
-    return &y->hooks[hook];
-}
-
-pa_bluez4_form_factor_t pa_bluez4_get_form_factor(uint32_t class) {
-    unsigned major, minor;
-    pa_bluez4_form_factor_t r;
-
-    static const pa_bluez4_form_factor_t table[] = {
-        [1] = PA_BLUEZ4_FORM_FACTOR_HEADSET,
-        [2] = PA_BLUEZ4_FORM_FACTOR_HANDSFREE,
-        [4] = PA_BLUEZ4_FORM_FACTOR_MICROPHONE,
-        [5] = PA_BLUEZ4_FORM_FACTOR_SPEAKER,
-        [6] = PA_BLUEZ4_FORM_FACTOR_HEADPHONE,
-        [7] = PA_BLUEZ4_FORM_FACTOR_PORTABLE,
-        [8] = PA_BLUEZ4_FORM_FACTOR_CAR,
-        [10] = PA_BLUEZ4_FORM_FACTOR_HIFI
-    };
-
-    /*
-     * See Bluetooth Assigned Numbers:
-     * https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
-     */
-    major = (class >> 8) & 0x1F;
-    minor = (class >> 2) & 0x3F;
-
-    switch (major) {
-        case 2:
-            return PA_BLUEZ4_FORM_FACTOR_PHONE;
-        case 4:
-            break;
-        default:
-            pa_log_debug("Unknown Bluetooth major device class %u", major);
-            return PA_BLUEZ4_FORM_FACTOR_UNKNOWN;
-    }
-
-    r = minor < PA_ELEMENTSOF(table) ? table[minor] : PA_BLUEZ4_FORM_FACTOR_UNKNOWN;
-
-    if (!r)
-        pa_log_debug("Unknown Bluetooth minor device class %u", minor);
-
-    return r;
-}
-
-const char *pa_bluez4_form_factor_to_string(pa_bluez4_form_factor_t ff) {
-    switch (ff) {
-        case PA_BLUEZ4_FORM_FACTOR_UNKNOWN:
-            return "unknown";
-        case PA_BLUEZ4_FORM_FACTOR_HEADSET:
-            return "headset";
-        case PA_BLUEZ4_FORM_FACTOR_HANDSFREE:
-            return "hands-free";
-        case PA_BLUEZ4_FORM_FACTOR_MICROPHONE:
-            return "microphone";
-        case PA_BLUEZ4_FORM_FACTOR_SPEAKER:
-            return "speaker";
-        case PA_BLUEZ4_FORM_FACTOR_HEADPHONE:
-            return "headphone";
-        case PA_BLUEZ4_FORM_FACTOR_PORTABLE:
-            return "portable";
-        case PA_BLUEZ4_FORM_FACTOR_CAR:
-            return "car";
-        case PA_BLUEZ4_FORM_FACTOR_HIFI:
-            return "hifi";
-        case PA_BLUEZ4_FORM_FACTOR_PHONE:
-            return "phone";
-    }
-
-    pa_assert_not_reached();
-}
diff --git a/src/modules/bluetooth/bluez4-util.h b/src/modules/bluetooth/bluez4-util.h
deleted file mode 100644
index f4b5ca34..00000000
--- a/src/modules/bluetooth/bluez4-util.h
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef foobluez4utilhfoo
-#define foobluez4utilhfoo
-
-/***
-  This file is part of PulseAudio.
-
-  Copyright 2008-2013 João Paulo Rechi Vita
-
-  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, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include <pulsecore/llist.h>
-#include <pulsecore/macro.h>
-
-#define PA_BLUEZ4_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
-
-#define PA_BLUEZ4_UUID_A2DP_SOURCE "0000110a-0000-1000-8000-00805f9b34fb"
-#define PA_BLUEZ4_UUID_A2DP_SINK   "0000110b-0000-1000-8000-00805f9b34fb"
-#define PA_BLUEZ4_UUID_HSP_HS      "00001108-0000-1000-8000-00805f9b34fb"
-#define PA_BLUEZ4_UUID_HSP_AG      "00001112-0000-1000-8000-00805f9b34fb"
-#define PA_BLUEZ4_UUID_HFP_HF      "0000111e-0000-1000-8000-00805f9b34fb"
-#define PA_BLUEZ4_UUID_HFP_AG      "0000111f-0000-1000-8000-00805f9b34fb"
-
-#define HSP_MAX_GAIN 15
-
-typedef struct pa_bluez4_device pa_bluez4_device;
-typedef struct pa_bluez4_discovery pa_bluez4_discovery;
-typedef struct pa_bluez4_transport pa_bluez4_transport;
-
-struct userdata;
-
-typedef enum pa_bluez4_profile {
-    PA_BLUEZ4_PROFILE_A2DP_SINK,
-    PA_BLUEZ4_PROFILE_A2DP_SOURCE,
-    PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT,
-    PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY,
-    PA_BLUEZ4_PROFILE_OFF
-} pa_bluez4_profile_t;
-
-#define PA_BLUEZ4_PROFILE_COUNT PA_BLUEZ4_PROFILE_OFF
-
-struct pa_bluez4_hook_uuid_data {
-    pa_bluez4_device *device;
-    const char *uuid;
-};
-
-/* Hook data: pa_bluez4_discovery pointer. */
-typedef enum pa_bluez4_hook {
-    PA_BLUEZ4_HOOK_DEVICE_CONNECTION_CHANGED, /* Call data: pa_bluez4_device */
-    PA_BLUEZ4_HOOK_DEVICE_UUID_ADDED, /* Call data: pa_bluez4_hook_uuid_data */
-    PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluez4_transport */
-    PA_BLUEZ4_HOOK_TRANSPORT_NREC_CHANGED, /* Call data: pa_bluez4_transport */
-    PA_BLUEZ4_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED, /* Call data: pa_bluez4_transport */
-    PA_BLUEZ4_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED, /* Call data: pa_bluez4_transport */
-    PA_BLUEZ4_HOOK_MAX
-} pa_bluez4_hook_t;
-
-typedef enum pa_bluez4_transport_state {
-    PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED,
-    PA_BLUEZ4_TRANSPORT_STATE_IDLE, /* Connected but not playing */
-    PA_BLUEZ4_TRANSPORT_STATE_PLAYING
-} pa_bluez4_transport_state_t;
-
-struct pa_bluez4_transport {
-    pa_bluez4_device *device;
-    char *owner;
-    char *path;
-    pa_bluez4_profile_t profile;
-    uint8_t codec;
-    uint8_t *config;
-    int config_size;
-
-    pa_bluez4_transport_state_t state;
-    bool nrec;
-    uint16_t microphone_gain; /* Used for HSP/HFP */
-    uint16_t speaker_gain; /* Used for HSP/HFP */
-};
-
-/* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */
-typedef enum pa_bluez4_audio_state {
-    PA_BLUEZ4_AUDIO_STATE_INVALID = -1,
-    PA_BLUEZ4_AUDIO_STATE_DISCONNECTED,
-    PA_BLUEZ4_AUDIO_STATE_CONNECTING,
-    PA_BLUEZ4_AUDIO_STATE_CONNECTED,
-    PA_BLUEZ4_AUDIO_STATE_PLAYING
-} pa_bluez4_audio_state_t;
-
-struct pa_bluez4_device {
-    pa_bluez4_discovery *discovery;
-    bool dead;
-
-    int device_info_valid;      /* 0: no results yet; 1: good results; -1: bad results ... */
-
-    /* Device information */
-    char *name;
-    char *path;
-    pa_bluez4_transport *transports[PA_BLUEZ4_PROFILE_COUNT];
-    int paired;
-    char *alias;
-    char *address;
-    int class;
-    pa_hashmap *uuids; /* char* -> char* (hashmap-as-a-set) */
-    int trusted;
-
-    /* Audio state */
-    pa_bluez4_audio_state_t audio_state;
-
-    /* AudioSink, AudioSource, Headset and HandsfreeGateway states */
-    pa_bluez4_audio_state_t profile_state[PA_BLUEZ4_PROFILE_COUNT];
-};
-
-pa_bluez4_discovery* pa_bluez4_discovery_get(pa_core *core);
-pa_bluez4_discovery* pa_bluez4_discovery_ref(pa_bluez4_discovery *y);
-void pa_bluez4_discovery_unref(pa_bluez4_discovery *d);
-
-pa_bluez4_device* pa_bluez4_discovery_get_by_path(pa_bluez4_discovery *d, const char* path);
-pa_bluez4_device* pa_bluez4_discovery_get_by_address(pa_bluez4_discovery *d, const char* address);
-
-bool pa_bluez4_device_any_audio_connected(const pa_bluez4_device *d);
-
-int pa_bluez4_transport_acquire(pa_bluez4_transport *t, bool optional, size_t *imtu, size_t *omtu);
-void pa_bluez4_transport_release(pa_bluez4_transport *t);
-
-void pa_bluez4_transport_set_microphone_gain(pa_bluez4_transport *t, uint16_t value);
-void pa_bluez4_transport_set_speaker_gain(pa_bluez4_transport *t, uint16_t value);
-
-pa_hook* pa_bluez4_discovery_hook(pa_bluez4_discovery *y, pa_bluez4_hook_t hook);
-
-typedef enum pa_bluez4_form_factor {
-    PA_BLUEZ4_FORM_FACTOR_UNKNOWN,
-    PA_BLUEZ4_FORM_FACTOR_HEADSET,
-    PA_BLUEZ4_FORM_FACTOR_HANDSFREE,
-    PA_BLUEZ4_FORM_FACTOR_MICROPHONE,
-    PA_BLUEZ4_FORM_FACTOR_SPEAKER,
-    PA_BLUEZ4_FORM_FACTOR_HEADPHONE,
-    PA_BLUEZ4_FORM_FACTOR_PORTABLE,
-    PA_BLUEZ4_FORM_FACTOR_CAR,
-    PA_BLUEZ4_FORM_FACTOR_HIFI,
-    PA_BLUEZ4_FORM_FACTOR_PHONE,
-} pa_bluez4_form_factor_t;
-
-pa_bluez4_form_factor_t pa_bluez4_get_form_factor(uint32_t class);
-const char *pa_bluez4_form_factor_to_string(pa_bluez4_form_factor_t ff);
-
-const char *pa_bluez4_profile_to_string(pa_bluez4_profile_t profile);
-
-#endif
diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c
index 49718c0c..63195d3e 100644
--- a/src/modules/bluetooth/module-bluetooth-discover.c
+++ b/src/modules/bluetooth/module-bluetooth-discover.c
@@ -36,7 +36,6 @@ PA_MODULE_USAGE(
 
 struct userdata {
     uint32_t bluez5_module_idx;
-    uint32_t bluez4_module_idx;
 };
 
 int pa__init(pa_module* m) {
@@ -47,7 +46,6 @@ int pa__init(pa_module* m) {
 
     m->userdata = u = pa_xnew0(struct userdata, 1);
     u->bluez5_module_idx = PA_INVALID_INDEX;
-    u->bluez4_module_idx = PA_INVALID_INDEX;
 
     if (pa_module_exists("module-bluez5-discover")) {
         pa_module_load(&mm, m->core, "module-bluez5-discover", m->argument);
@@ -55,13 +53,7 @@ int pa__init(pa_module* m) {
             u->bluez5_module_idx = mm->index;
     }
 
-    if (pa_module_exists("module-bluez4-discover")) {
-        pa_module_load(&mm, m->core, "module-bluez4-discover",  NULL);
-        if (mm)
-            u->bluez4_module_idx = mm->index;
-    }
-
-    if (u->bluez5_module_idx == PA_INVALID_INDEX && u->bluez4_module_idx == PA_INVALID_INDEX) {
+    if (u->bluez5_module_idx == PA_INVALID_INDEX) {
         pa_xfree(u);
         return -1;
     }
@@ -80,8 +72,5 @@ void pa__done(pa_module* m) {
     if (u->bluez5_module_idx != PA_INVALID_INDEX)
         pa_module_unload_by_index(m->core, u->bluez5_module_idx, true);
 
-    if (u->bluez4_module_idx != PA_INVALID_INDEX)
-        pa_module_unload_by_index(m->core, u->bluez4_module_idx, true);
-
     pa_xfree(u);
 }
diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
deleted file mode 100644
index 87592834..00000000
--- a/src/modules/bluetooth/module-bluez4-device.c
+++ /dev/null
@@ -1,2664 +0,0 @@
-/***
-  This file is part of PulseAudio.
-
-  Copyright 2008-2013 João Paulo Rechi Vita
-  Copyright 2011-2013 BMW Car IT GmbH.
-
-  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, see <http://www.gnu.org/licenses/>.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <errno.h>
-#include <math.h>
-#include <linux/sockios.h>
-#include <arpa/inet.h>
-
-#include <pulse/rtclock.h>
-#include <pulse/sample.h>
-#include <pulse/timeval.h>
-#include <pulse/utf8.h>
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/i18n.h>
-#include <pulsecore/module.h>
-#include <pulsecore/modargs.h>
-#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>
-#include <pulsecore/poll.h>
-#include <pulsecore/rtpoll.h>
-#include <pulsecore/time-smoother.h>
-#include <pulsecore/namereg.h>
-
-#include <sbc/sbc.h>
-
-#include "a2dp-codecs.h"
-#include "rtp.h"
-#include "bluez4-util.h"
-
-#define BITPOOL_DEC_LIMIT 32
-#define BITPOOL_DEC_STEP 5
-
-PA_MODULE_AUTHOR("João Paulo Rechi Vita");
-PA_MODULE_DESCRIPTION("BlueZ 4 Bluetooth audio sink and source");
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(false);
-PA_MODULE_USAGE(
-        "name=<name for the card/sink/source, to be prefixed> "
-        "card_name=<name for the card> "
-        "card_properties=<properties for the card> "
-        "sink_name=<name for the sink> "
-        "sink_properties=<properties for the sink> "
-        "source_name=<name for the source> "
-        "source_properties=<properties for the source> "
-        "address=<address of the device> "
-        "profile=<a2dp|hsp|hfgw> "
-        "rate=<sample rate> "
-        "channels=<number of channels> "
-        "path=<device object path> "
-        "sco_sink=<SCO over PCM sink name> "
-        "sco_source=<SCO over PCM source name>");
-
-/* TODO: not close fd when entering suspend mode in a2dp */
-
-static const char* const valid_modargs[] = {
-    "name",
-    "card_name",
-    "card_properties",
-    "sink_name",
-    "sink_properties",
-    "source_name",
-    "source_properties",
-    "address",
-    "profile",
-    "rate",
-    "channels",
-    "path",
-    "sco_sink",
-    "sco_source",
-    NULL
-};
-
-struct a2dp_info {
-    sbc_t sbc;                           /* Codec data */
-    bool sbc_initialized;                /* Keep track if the encoder is initialized */
-    size_t codesize, frame_length;       /* SBC Codesize, frame_length. We simply cache those values here */
-
-    void* buffer;                        /* Codec transfer buffer */
-    size_t buffer_size;                  /* Size of the buffer */
-
-    uint16_t seq_num;                    /* Cumulative packet sequence */
-    uint8_t min_bitpool;
-    uint8_t max_bitpool;
-};
-
-struct hsp_info {
-    pa_sink *sco_sink;
-    void (*sco_sink_set_volume)(pa_sink *s);
-    pa_source *sco_source;
-    void (*sco_source_set_volume)(pa_source *s);
-};
-
-struct bluetooth_msg {
-    pa_msgobject parent;
-    pa_card *card;
-};
-
-typedef struct bluetooth_msg bluetooth_msg;
-PA_DEFINE_PRIVATE_CLASS(bluetooth_msg, pa_msgobject);
-#define BLUETOOTH_MSG(o) (bluetooth_msg_cast(o))
-
-struct userdata {
-    pa_core *core;
-    pa_module *module;
-
-    pa_bluez4_device *device;
-    pa_hook_slot *uuid_added_slot;
-    char *address;
-    char *path;
-    pa_bluez4_transport *transport;
-    bool transport_acquired;
-    pa_hook_slot *discovery_slot;
-    pa_hook_slot *sink_state_changed_slot;
-    pa_hook_slot *source_state_changed_slot;
-    pa_hook_slot *transport_state_changed_slot;
-    pa_hook_slot *transport_nrec_changed_slot;
-    pa_hook_slot *transport_microphone_changed_slot;
-    pa_hook_slot *transport_speaker_changed_slot;
-
-    pa_bluez4_discovery *discovery;
-
-    char *output_port_name;
-    char *input_port_name;
-
-    pa_card *card;
-    pa_sink *sink;
-    pa_source *source;
-
-    pa_thread_mq thread_mq;
-    pa_rtpoll *rtpoll;
-    pa_rtpoll_item *rtpoll_item;
-    pa_thread *thread;
-    bluetooth_msg *msg;
-
-    uint64_t read_index, write_index;
-    pa_usec_t started_at;
-    pa_smoother *read_smoother;
-
-    pa_memchunk write_memchunk;
-
-    pa_sample_spec sample_spec, requested_sample_spec;
-
-    int stream_fd;
-
-    size_t read_link_mtu;
-    size_t read_block_size;
-
-    size_t write_link_mtu;
-    size_t write_block_size;
-
-    struct a2dp_info a2dp;
-    struct hsp_info hsp;
-
-    pa_bluez4_profile_t profile;
-
-    pa_modargs *modargs;
-
-    int stream_write_type;
-};
-
-enum {
-    BLUETOOTH_MESSAGE_IO_THREAD_FAILED,
-    BLUETOOTH_MESSAGE_MAX
-};
-
-#define FIXED_LATENCY_PLAYBACK_A2DP (25*PA_USEC_PER_MSEC)
-#define FIXED_LATENCY_RECORD_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)
-
-#define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
-
-#define USE_SCO_OVER_PCM(u) (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT && (u->hsp.sco_sink && u->hsp.sco_source))
-
-static int init_profile(struct userdata *u);
-
-/* from IO thread */
-static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool) {
-    struct a2dp_info *a2dp;
-
-    pa_assert(u);
-
-    a2dp = &u->a2dp;
-
-    if (a2dp->sbc.bitpool == bitpool)
-        return;
-
-    if (bitpool > a2dp->max_bitpool)
-        bitpool = a2dp->max_bitpool;
-    else if (bitpool < a2dp->min_bitpool)
-        bitpool = a2dp->min_bitpool;
-
-    a2dp->sbc.bitpool = bitpool;
-
-    a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
-    a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
-
-    pa_log_debug("Bitpool has changed to %u", a2dp->sbc.bitpool);
-
-    u->read_block_size =
-        (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
-        / a2dp->frame_length * a2dp->codesize;
-
-    u->write_block_size =
-        (u->write_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
-        / a2dp->frame_length * a2dp->codesize;
-
-    pa_sink_set_max_request_within_thread(u->sink, u->write_block_size);
-    pa_sink_set_fixed_latency_within_thread(u->sink,
-            FIXED_LATENCY_PLAYBACK_A2DP + pa_bytes_to_usec(u->write_block_size, &u->sample_spec));
-}
-
-/* from IO thread, except in SCO over PCM */
-static void bt_transport_config_mtu(struct userdata *u) {
-    /* Calculate block sizes */
-    if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY) {
-        u->read_block_size = u->read_link_mtu;
-        u->write_block_size = u->write_link_mtu;
-    } else {
-        u->read_block_size =
-            (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
-            / u->a2dp.frame_length * u->a2dp.codesize;
-
-        u->write_block_size =
-            (u->write_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
-            / u->a2dp.frame_length * u->a2dp.codesize;
-    }
-
-    if (USE_SCO_OVER_PCM(u))
-        return;
-
-    if (u->sink) {
-        pa_sink_set_max_request_within_thread(u->sink, u->write_block_size);
-        pa_sink_set_fixed_latency_within_thread(u->sink,
-                                                (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK ?
-                                                 FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
-                                                pa_bytes_to_usec(u->write_block_size, &u->sample_spec));
-    }
-
-    if (u->source)
-        pa_source_set_fixed_latency_within_thread(u->source,
-                                                  (u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE ?
-                                                   FIXED_LATENCY_RECORD_A2DP : FIXED_LATENCY_RECORD_HSP) +
-                                                  pa_bytes_to_usec(u->read_block_size, &u->sample_spec));
-}
-
-/* from IO thread, except in SCO over PCM */
-
-static void setup_stream(struct userdata *u) {
-    struct pollfd *pollfd;
-    int one;
-
-    pa_log_info("Transport %s resuming", u->transport->path);
-
-    bt_transport_config_mtu(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!");
-
-    if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK)
-        a2dp_set_bitpool(u, u->a2dp.max_bitpool);
-
-    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 = 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_now(),
-                true);
-}
-
-static void teardown_stream(struct userdata *u) {
-    if (u->rtpoll_item) {
-        pa_rtpoll_item_free(u->rtpoll_item);
-        u->rtpoll_item = NULL;
-    }
-
-    if (u->stream_fd >= 0) {
-        pa_close(u->stream_fd);
-        u->stream_fd = -1;
-    }
-
-    if (u->read_smoother) {
-        pa_smoother_free(u->read_smoother);
-        u->read_smoother = NULL;
-    }
-
-    if (u->write_memchunk.memblock) {
-        pa_memblock_unref(u->write_memchunk.memblock);
-        pa_memchunk_reset(&u->write_memchunk);
-    }
-
-    pa_log_debug("Audio stream torn down");
-}
-
-static void bt_transport_release(struct userdata *u) {
-    pa_assert(u->transport);
-
-    /* Ignore if already released */
-    if (!u->transport_acquired)
-        return;
-
-    pa_log_debug("Releasing transport %s", u->transport->path);
-
-    pa_bluez4_transport_release(u->transport);
-
-    u->transport_acquired = false;
-
-    teardown_stream(u);
-}
-
-static int bt_transport_acquire(struct userdata *u, bool optional) {
-    pa_assert(u->transport);
-
-    if (u->transport_acquired)
-        return 0;
-
-    pa_log_debug("Acquiring transport %s", u->transport->path);
-
-    u->stream_fd = pa_bluez4_transport_acquire(u->transport, optional, &u->read_link_mtu, &u->write_link_mtu);
-    if (u->stream_fd < 0) {
-        if (!optional)
-            pa_log("Failed to acquire transport %s", u->transport->path);
-        else
-            pa_log_info("Failed optional acquire of transport %s", u->transport->path);
-
-        return -1;
-    }
-
-    u->transport_acquired = true;
-    pa_log_info("Transport %s acquired: fd %d", u->transport->path, u->stream_fd);
-
-    return 0;
-}
-
-/* Run from IO thread */
-static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
-    struct userdata *u = PA_SINK(o)->userdata;
-
-    pa_assert(u->sink == PA_SINK(o));
-    pa_assert(u->transport);
-
-    switch (code) {
-
-        case PA_SINK_MESSAGE_GET_LATENCY: {
-
-            if (u->read_smoother) {
-                int64_t wi, ri;
-
-                ri = pa_smoother_get(u->read_smoother, pa_rtclock_now());
-                wi = pa_bytes_to_usec(u->write_index + u->write_block_size, &u->sample_spec);
-
-                *((int64_t*) data) = wi - ri;
-            } else {
-                int64_t ri, wi;
-
-                ri = pa_rtclock_now() - u->started_at;
-                wi = pa_bytes_to_usec(u->write_index, &u->sample_spec);
-
-                *((int64_t*) data) = wi - ri;
-            }
-
-            *((int64_t*) data) += u->sink->thread_info.fixed_latency;
-            return 0;
-        }
-    }
-
-    return pa_sink_process_msg(o, code, data, offset, chunk);
-}
-
-/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
-    struct userdata *u;
-
-    pa_assert(s);
-    pa_assert_se(u = s->userdata);
-
-    switch (new_state) {
-
-        case PA_SINK_SUSPENDED:
-            /* Ignore if transition is PA_SINK_INIT->PA_SINK_SUSPENDED */
-            if (!PA_SINK_IS_OPENED(s->thread_info.state))
-                break;
-
-            /* Stop the device if the source is suspended as well */
-            if (!u->source || u->source->state == PA_SOURCE_SUSPENDED)
-                /* We deliberately ignore whether stopping
-                 * actually worked. Since the stream_fd is
-                 * closed it doesn't really matter */
-                bt_transport_release(u);
-
-            break;
-
-        case PA_SINK_IDLE:
-        case PA_SINK_RUNNING:
-            if (s->thread_info.state != PA_SINK_SUSPENDED)
-                break;
-
-            /* Resume the device if the source was suspended as well */
-            if (!u->source || !PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
-                if (bt_transport_acquire(u, false) < 0)
-                    return -1;
-                else
-                    setup_stream(u);
-            }
-            break;
-
-        case PA_SINK_UNLINKED:
-        case PA_SINK_INIT:
-        case PA_SINK_INVALID_STATE:
-            break;
-    }
-
-    return 0;
-}
-
-/* Run from IO thread */
-static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
-    struct userdata *u = PA_SOURCE(o)->userdata;
-
-    pa_assert(u->source == PA_SOURCE(o));
-    pa_assert(u->transport);
-
-    switch (code) {
-
-        case PA_SOURCE_MESSAGE_GET_LATENCY: {
-            int64_t wi, ri;
-
-            if (u->read_smoother) {
-                wi = pa_smoother_get(u->read_smoother, pa_rtclock_now());
-                ri = pa_bytes_to_usec(u->read_index, &u->sample_spec);
-
-                *((int64_t*) data) = wi - ri + u->source->thread_info.fixed_latency;
-            } else
-                *((int64_t*) data) = 0;
-
-            return 0;
-        }
-
-    }
-
-    return pa_source_process_msg(o, code, data, offset, chunk);
-}
-
-/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
-    struct userdata *u;
-
-    pa_assert(s);
-    pa_assert_se(u = s->userdata);
-
-    switch (new_state) {
-
-        case PA_SOURCE_SUSPENDED:
-            /* Ignore if transition is PA_SOURCE_INIT->PA_SOURCE_SUSPENDED */
-            if (!PA_SOURCE_IS_OPENED(s->thread_info.state))
-                break;
-
-            /* Stop the device if the sink is suspended as well */
-            if (!u->sink || u->sink->state == PA_SINK_SUSPENDED)
-                bt_transport_release(u);
-
-            if (u->read_smoother)
-                pa_smoother_pause(u->read_smoother, pa_rtclock_now());
-            break;
-
-        case PA_SOURCE_IDLE:
-        case PA_SOURCE_RUNNING:
-            if (s->thread_info.state != PA_SOURCE_SUSPENDED)
-                break;
-
-            /* Resume the device if the sink was suspended as well */
-            if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
-                if (bt_transport_acquire(u, false) < 0)
-                    return -1;
-                else
-                    setup_stream(u);
-            }
-            /* We don't resume the smoother here. Instead we
-             * wait until the first packet arrives */
-            break;
-
-        case PA_SOURCE_UNLINKED:
-        case PA_SOURCE_INIT:
-        case PA_SOURCE_INVALID_STATE:
-            break;
-    }
-
-    return 0;
-}
-
-/* Called from main thread context */
-static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
-    struct bluetooth_msg *u = BLUETOOTH_MSG(obj);
-
-    switch (code) {
-        case BLUETOOTH_MESSAGE_IO_THREAD_FAILED: {
-            if (u->card->module->unload_requested)
-                break;
-
-            pa_log_debug("Switching the profile to off due to IO thread failure.");
-
-            pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
-            break;
-        }
-    }
-    return 0;
-}
-
-/* Run from IO thread */
-static int hsp_process_render(struct userdata *u) {
-    int ret = 0;
-
-    pa_assert(u);
-    pa_assert(u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY);
-    pa_assert(u->sink);
-
-    /* First, render some data */
-    if (!u->write_memchunk.memblock)
-        pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
-
-    pa_assert(u->write_memchunk.length == u->write_block_size);
-
-    for (;;) {
-        ssize_t l;
-        const void *p;
-
-        /* Now write that data to the socket. The socket is of type
-         * SEQPACKET, and we generated the data of the MTU size, so this
-         * should just work. */
-
-        p = (const uint8_t *) pa_memblock_acquire_chunk(&u->write_memchunk);
-        l = pa_write(u->stream_fd, p, u->write_memchunk.length, &u->stream_write_type);
-        pa_memblock_release(u->write_memchunk.memblock);
-
-        pa_assert(l != 0);
-
-        if (l < 0) {
-
-            if (errno == EINTR)
-                /* Retry right away if we got interrupted */
-                continue;
-
-            else if (errno == EAGAIN)
-                /* Hmm, apparently the socket was not writable, give up for now */
-                break;
-
-            pa_log_error("Failed to write data to SCO socket: %s", pa_cstrerror(errno));
-            ret = -1;
-            break;
-        }
-
-        pa_assert((size_t) l <= u->write_memchunk.length);
-
-        if ((size_t) l != u->write_memchunk.length) {
-            pa_log_error("Wrote memory block to socket only partially! %llu written, wanted to write %llu.",
-                        (unsigned long long) l,
-                        (unsigned long long) u->write_memchunk.length);
-            ret = -1;
-            break;
-        }
-
-        u->write_index += (uint64_t) u->write_memchunk.length;
-        pa_memblock_unref(u->write_memchunk.memblock);
-        pa_memchunk_reset(&u->write_memchunk);
-
-        ret = 1;
-        break;
-    }
-
-    return ret;
-}
-
-/* Run from IO thread */
-static int hsp_process_push(struct userdata *u) {
-    int ret = 0;
-    pa_memchunk memchunk;
-
-    pa_assert(u);
-    pa_assert(u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY);
-    pa_assert(u->source);
-    pa_assert(u->read_smoother);
-
-    memchunk.memblock = pa_memblock_new(u->core->mempool, u->read_block_size);
-    memchunk.index = memchunk.length = 0;
-
-    for (;;) {
-        ssize_t l;
-        void *p;
-        struct msghdr m;
-        struct cmsghdr *cm;
-        uint8_t aux[1024];
-        struct iovec iov;
-        bool 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);
-        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) {
-
-            if (l < 0 && errno == EINTR)
-                /* Retry right away if we got interrupted */
-                continue;
-
-            else if (l < 0 && errno == EAGAIN)
-                /* Hmm, apparently the socket was not readable, give up for now. */
-                break;
-
-            pa_log_error("Failed to read data from SCO socket: %s", l < 0 ? pa_cstrerror(errno) : "EOF");
-            ret = -1;
-            break;
-        }
-
-        pa_assert((size_t) l <= pa_memblock_get_length(memchunk.memblock));
-
-        /* In some rare occasions, we might receive packets of a very strange
-         * size. This could potentially be possible if the SCO packet was
-         * received partially over-the-air, or more probably due to hardware
-         * issues in our Bluetooth adapter. In these cases, in order to avoid
-         * an assertion failure due to unaligned data, just discard the whole
-         * packet */
-        if (!pa_frame_aligned(l, &u->sample_spec)) {
-            pa_log_warn("SCO packet received of unaligned size: %zu", l);
-            break;
-        }
-
-        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_now();
-        }
-
-        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 = l;
-        break;
-    }
-
-    pa_memblock_unref(memchunk.memblock);
-
-    return ret;
-}
-
-/* Run from IO thread */
-static void a2dp_prepare_buffer(struct userdata *u) {
-    size_t min_buffer_size = PA_MAX(u->read_link_mtu, u->write_link_mtu);
-
-    pa_assert(u);
-
-    if (u->a2dp.buffer_size >= min_buffer_size)
-        return;
-
-    u->a2dp.buffer_size = 2 * min_buffer_size;
-    pa_xfree(u->a2dp.buffer);
-    u->a2dp.buffer = pa_xmalloc(u->a2dp.buffer_size);
-}
-
-/* Run from IO thread */
-static int a2dp_process_render(struct userdata *u) {
-    struct a2dp_info *a2dp;
-    struct rtp_header *header;
-    struct rtp_payload *payload;
-    size_t nbytes;
-    void *d;
-    const void *p;
-    size_t to_write, to_encode;
-    unsigned frame_count;
-    int ret = 0;
-
-    pa_assert(u);
-    pa_assert(u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK);
-    pa_assert(u->sink);
-
-    /* First, render some data */
-    if (!u->write_memchunk.memblock)
-        pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
-
-    pa_assert(u->write_memchunk.length == u->write_block_size);
-
-    a2dp_prepare_buffer(u);
-
-    a2dp = &u->a2dp;
-    header = a2dp->buffer;
-    payload = (struct rtp_payload*) ((uint8_t*) a2dp->buffer + sizeof(*header));
-
-    frame_count = 0;
-
-    /* Try to create a packet of the full MTU */
-
-    p = (const uint8_t *) pa_memblock_acquire_chunk(&u->write_memchunk);
-    to_encode = u->write_memchunk.length;
-
-    d = (uint8_t*) a2dp->buffer + sizeof(*header) + sizeof(*payload);
-    to_write = a2dp->buffer_size - sizeof(*header) - sizeof(*payload);
-
-    while (PA_LIKELY(to_encode > 0 && to_write > 0)) {
-        ssize_t written;
-        ssize_t encoded;
-
-        encoded = sbc_encode(&a2dp->sbc,
-                             p, to_encode,
-                             d, to_write,
-                             &written);
-
-        if (PA_UNLIKELY(encoded <= 0)) {
-            pa_log_error("SBC encoding error (%li)", (long) encoded);
-            pa_memblock_release(u->write_memchunk.memblock);
-            return -1;
-        }
-
-/*         pa_log_debug("SBC: encoded: %lu; written: %lu", (unsigned long) encoded, (unsigned long) written); */
-/*         pa_log_debug("SBC: codesize: %lu; frame_length: %lu", (unsigned long) a2dp->codesize, (unsigned long) a2dp->frame_length); */
-
-        pa_assert_fp((size_t) encoded <= to_encode);
-        pa_assert_fp((size_t) encoded == a2dp->codesize);
-
-        pa_assert_fp((size_t) written <= to_write);
-        pa_assert_fp((size_t) written == a2dp->frame_length);
-
-        p = (const uint8_t*) p + encoded;
-        to_encode -= encoded;
-
-        d = (uint8_t*) d + written;
-        to_write -= written;
-
-        frame_count++;
-    }
-
-    pa_memblock_release(u->write_memchunk.memblock);
-
-    pa_assert(to_encode == 0);
-
-    PA_ONCE_BEGIN {
-        pa_log_debug("Using SBC encoder implementation: %s", pa_strnull(sbc_get_implementation_info(&a2dp->sbc)));
-    } PA_ONCE_END;
-
-    /* write it to the fifo */
-    memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload));
-    header->v = 2;
-    header->pt = 1;
-    header->sequence_number = htons(a2dp->seq_num++);
-    header->timestamp = htonl(u->write_index / pa_frame_size(&u->sample_spec));
-    header->ssrc = htonl(1);
-    payload->frame_count = frame_count;
-
-    nbytes = (uint8_t*) d - (uint8_t*) a2dp->buffer;
-
-    for (;;) {
-        ssize_t l;
-
-        l = pa_write(u->stream_fd, a2dp->buffer, nbytes, &u->stream_write_type);
-
-        pa_assert(l != 0);
-
-        if (l < 0) {
-
-            if (errno == EINTR)
-                /* Retry right away if we got interrupted */
-                continue;
-
-            else if (errno == EAGAIN)
-                /* Hmm, apparently the socket was not writable, give up for now */
-                break;
-
-            pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno));
-            ret = -1;
-            break;
-        }
-
-        pa_assert((size_t) l <= nbytes);
-
-        if ((size_t) l != nbytes) {
-            pa_log_warn("Wrote memory block to socket only partially! %llu written, wanted to write %llu.",
-                        (unsigned long long) l,
-                        (unsigned long long) nbytes);
-            ret = -1;
-            break;
-        }
-
-        u->write_index += (uint64_t) u->write_memchunk.length;
-        pa_memblock_unref(u->write_memchunk.memblock);
-        pa_memchunk_reset(&u->write_memchunk);
-
-        ret = 1;
-
-        break;
-    }
-
-    return ret;
-}
-
-static int a2dp_process_push(struct userdata *u) {
-    int ret = 0;
-    pa_memchunk memchunk;
-
-    pa_assert(u);
-    pa_assert(u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE);
-    pa_assert(u->source);
-    pa_assert(u->read_smoother);
-
-    memchunk.memblock = pa_memblock_new(u->core->mempool, u->read_block_size);
-    memchunk.index = memchunk.length = 0;
-
-    for (;;) {
-        bool found_tstamp = false;
-        pa_usec_t tstamp;
-        struct a2dp_info *a2dp;
-        struct rtp_header *header;
-        struct rtp_payload *payload;
-        const void *p;
-        void *d;
-        ssize_t l;
-        size_t to_write, to_decode;
-        size_t total_written = 0;
-
-        a2dp_prepare_buffer(u);
-
-        a2dp = &u->a2dp;
-        header = a2dp->buffer;
-        payload = (struct rtp_payload*) ((uint8_t*) a2dp->buffer + sizeof(*header));
-
-        l = pa_read(u->stream_fd, a2dp->buffer, a2dp->buffer_size, &u->stream_write_type);
-
-        if (l <= 0) {
-
-            if (l < 0 && errno == EINTR)
-                /* Retry right away if we got interrupted */
-                continue;
-
-            else if (l < 0 && errno == EAGAIN)
-                /* Hmm, apparently the socket was not readable, give up for now. */
-                break;
-
-            pa_log_error("Failed to read data from socket: %s", l < 0 ? pa_cstrerror(errno) : "EOF");
-            ret = -1;
-            break;
-        }
-
-        pa_assert((size_t) l <= a2dp->buffer_size);
-
-        /* TODO: get timestamp from rtp */
-        if (!found_tstamp) {
-            /* pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!"); */
-            tstamp = pa_rtclock_now();
-        }
-
-        p = (uint8_t*) a2dp->buffer + sizeof(*header) + sizeof(*payload);
-        to_decode = l - sizeof(*header) - sizeof(*payload);
-
-        d = pa_memblock_acquire(memchunk.memblock);
-        to_write = memchunk.length = pa_memblock_get_length(memchunk.memblock);
-
-        while (PA_LIKELY(to_decode > 0)) {
-            size_t written;
-            ssize_t decoded;
-
-            decoded = sbc_decode(&a2dp->sbc,
-                                 p, to_decode,
-                                 d, to_write,
-                                 &written);
-
-            if (PA_UNLIKELY(decoded <= 0)) {
-                pa_log_error("SBC decoding error (%li)", (long) decoded);
-                pa_memblock_release(memchunk.memblock);
-                pa_memblock_unref(memchunk.memblock);
-                return 0;
-            }
-
-/*             pa_log_debug("SBC: decoded: %lu; written: %lu", (unsigned long) decoded, (unsigned long) written); */
-/*             pa_log_debug("SBC: frame_length: %lu; codesize: %lu", (unsigned long) a2dp->frame_length, (unsigned long) a2dp->codesize); */
-
-            total_written += written;
-
-            /* Reset frame length, it can be changed due to bitpool change */
-            a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
-
-            pa_assert_fp((size_t) decoded <= to_decode);
-            pa_assert_fp((size_t) decoded == a2dp->frame_length);
-
-            pa_assert_fp((size_t) written == a2dp->codesize);
-
-            p = (const uint8_t*) p + decoded;
-            to_decode -= decoded;
-
-            d = (uint8_t*) d + written;
-            to_write -= written;
-        }
-
-        u->read_index += (uint64_t) total_written;
-        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);
-
-        memchunk.length -= to_write;
-
-        pa_memblock_release(memchunk.memblock);
-
-        pa_source_post(u->source, &memchunk);
-
-        ret = l;
-        break;
-    }
-
-    pa_memblock_unref(memchunk.memblock);
-
-    return ret;
-}
-
-static void a2dp_reduce_bitpool(struct userdata *u) {
-    struct a2dp_info *a2dp;
-    uint8_t bitpool;
-
-    pa_assert(u);
-
-    a2dp = &u->a2dp;
-
-    /* Check if bitpool is already at its limit */
-    if (a2dp->sbc.bitpool <= BITPOOL_DEC_LIMIT)
-        return;
-
-    bitpool = a2dp->sbc.bitpool - BITPOOL_DEC_STEP;
-
-    if (bitpool < BITPOOL_DEC_LIMIT)
-        bitpool = BITPOOL_DEC_LIMIT;
-
-    a2dp_set_bitpool(u, bitpool);
-}
-
-static void thread_func(void *userdata) {
-    struct userdata *u = userdata;
-    unsigned do_write = 0;
-    unsigned pending_read_bytes = 0;
-    bool writable = false;
-
-    pa_assert(u);
-    pa_assert(u->transport);
-
-    pa_log_debug("IO Thread starting up");
-
-    if (u->core->realtime_scheduling)
-        pa_make_realtime(u->core->realtime_priority);
-
-    pa_thread_mq_install(&u->thread_mq);
-
-    /* Setup the stream only if the transport was already acquired */
-    if (u->transport_acquired)
-        setup_stream(u);
-
-    for (;;) {
-        struct pollfd *pollfd;
-        int ret;
-        bool disable_timer = true;
-
-        pollfd = u->rtpoll_item ? pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL) : NULL;
-
-        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;
-
-                if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
-                    n_read = hsp_process_push(u);
-                else
-                    n_read = a2dp_process_push(u);
-
-                if (n_read < 0)
-                    goto io_fail;
-
-                if (n_read > 0) {
-                    /* We just read something, so we are supposed to write something, too */
-                    pending_read_bytes += n_read;
-                    do_write += pending_read_bytes / u->write_block_size;
-                    pending_read_bytes = pending_read_bytes % u->write_block_size;
-                }
-            }
-        }
-
-        if (u->sink && PA_SINK_IS_LINKED(u->sink->thread_info.state)) {
-
-            if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
-                pa_sink_process_rewind(u->sink, 0);
-
-            if (pollfd) {
-                if (pollfd->revents & POLLOUT)
-                    writable = true;
-
-                if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0 && writable) {
-                    pa_usec_t time_passed;
-                    pa_usec_t audio_sent;
-
-                    /* Hmm, there is no input stream we could synchronize
-                     * to. So let's do things by time */
-
-                    time_passed = pa_rtclock_now() - u->started_at;
-                    audio_sent = pa_bytes_to_usec(u->write_index, &u->sample_spec);
-
-                    if (audio_sent <= time_passed) {
-                        pa_usec_t audio_to_send = time_passed - audio_sent;
-
-                        /* Never try to catch up for more than 100ms */
-                        if (u->write_index > 0 && audio_to_send > MAX_PLAYBACK_CATCH_UP_USEC) {
-                            pa_usec_t skip_usec;
-                            uint64_t skip_bytes;
-
-                            skip_usec = audio_to_send - MAX_PLAYBACK_CATCH_UP_USEC;
-                            skip_bytes = pa_usec_to_bytes(skip_usec, &u->sample_spec);
-
-                            if (skip_bytes > 0) {
-                                pa_memchunk tmp;
-
-                                pa_log_warn("Skipping %llu us (= %llu bytes) in audio stream",
-                                            (unsigned long long) skip_usec,
-                                            (unsigned long long) skip_bytes);
-
-                                pa_sink_render_full(u->sink, skip_bytes, &tmp);
-                                pa_memblock_unref(tmp.memblock);
-                                u->write_index += skip_bytes;
-
-                                if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK)
-                                    a2dp_reduce_bitpool(u);
-                            }
-                        }
-
-                        do_write = 1;
-                        pending_read_bytes = 0;
-                    }
-                }
-
-                if (writable && do_write > 0) {
-                    int n_written;
-
-                    if (u->write_index <= 0)
-                        u->started_at = pa_rtclock_now();
-
-                    if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK) {
-                        if ((n_written = a2dp_process_render(u)) < 0)
-                            goto io_fail;
-                    } else {
-                        if ((n_written = hsp_process_render(u)) < 0)
-                            goto io_fail;
-                    }
-
-                    if (n_written == 0)
-                        pa_log("Broken kernel: we got EAGAIN on write() after POLLOUT!");
-
-                    do_write -= n_written;
-                    writable = false;
-                }
-
-                if ((!u->source || !PA_SOURCE_IS_LINKED(u->source->thread_info.state)) && do_write <= 0) {
-                    pa_usec_t sleep_for;
-                    pa_usec_t time_passed, next_write_at;
-
-                    if (writable) {
-                        /* 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_now() - u->started_at;
-                        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); */
-                    } else
-                        /* drop stream every 500 ms */
-                        sleep_for = PA_USEC_PER_MSEC * 500;
-
-                    pa_rtpoll_set_timer_relative(u->rtpoll, sleep_for);
-                    disable_timer = false;
-                }
-            }
-        }
-
-        if (disable_timer)
-            pa_rtpoll_set_timer_disabled(u->rtpoll);
-
-        /* Hmm, nothing to do. Let's sleep */
-        if (pollfd)
-            pollfd->events = (short) (((u->sink && PA_SINK_IS_LINKED(u->sink->thread_info.state) && !writable) ? POLLOUT : 0) |
-                                      (u->source && PA_SOURCE_IS_LINKED(u->source->thread_info.state) ? POLLIN : 0));
-
-        if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) {
-            pa_log_debug("pa_rtpoll_run failed with: %d", ret);
-            goto fail;
-        }
-        if (ret == 0) {
-            pa_log_debug("IO thread shutdown requested, stopping cleanly");
-            bt_transport_release(u);
-            goto finish;
-        }
-
-        pollfd = u->rtpoll_item ? pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL) : NULL;
-
-        if (pollfd && (pollfd->revents & ~(POLLOUT|POLLIN))) {
-            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 io_fail;
-        }
-
-        continue;
-
-io_fail:
-        /* In case of HUP, just tear down the streams */
-        if (!pollfd || (pollfd->revents & POLLHUP) == 0)
-            goto fail;
-
-        do_write = 0;
-        pending_read_bytes = 0;
-        writable = false;
-
-        teardown_stream(u);
-    }
-
-fail:
-    /* If this was no regular exit from the loop we have to continue processing messages until we receive PA_MESSAGE_SHUTDOWN */
-    pa_log_debug("IO thread failed");
-    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->msg), BLUETOOTH_MESSAGE_IO_THREAD_FAILED, NULL, 0, NULL, NULL);
-    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
-
-finish:
-    pa_log_debug("IO thread shutting down");
-}
-
-static pa_available_t transport_state_to_availability(pa_bluez4_transport_state_t state) {
-    if (state == PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED)
-        return PA_AVAILABLE_NO;
-    else if (state >= PA_BLUEZ4_TRANSPORT_STATE_PLAYING)
-        return PA_AVAILABLE_YES;
-    else
-        return PA_AVAILABLE_UNKNOWN;
-}
-
-static pa_direction_t get_profile_direction(pa_bluez4_profile_t p) {
-    static const pa_direction_t profile_direction[] = {
-        [PA_BLUEZ4_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
-        [PA_BLUEZ4_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
-        [PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
-        [PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
-        [PA_BLUEZ4_PROFILE_OFF] = 0
-    };
-
-    return profile_direction[p];
-}
-
-/* Run from main thread */
-static pa_available_t get_port_availability(struct userdata *u, pa_direction_t direction) {
-    pa_available_t result = PA_AVAILABLE_NO;
-    unsigned i;
-
-    pa_assert(u);
-    pa_assert(u->device);
-
-    for (i = 0; i < PA_BLUEZ4_PROFILE_COUNT; i++) {
-        pa_bluez4_transport *transport;
-
-        if (!(get_profile_direction(i) & direction))
-            continue;
-
-        if (!(transport = u->device->transports[i]))
-            continue;
-
-        switch(transport->state) {
-            case PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED:
-                continue;
-
-            case PA_BLUEZ4_TRANSPORT_STATE_IDLE:
-                if (result == PA_AVAILABLE_NO)
-                    result = PA_AVAILABLE_UNKNOWN;
-
-                break;
-
-            case PA_BLUEZ4_TRANSPORT_STATE_PLAYING:
-                return PA_AVAILABLE_YES;
-        }
-    }
-
-    return result;
-}
-
-/* Run from main thread */
-static void handle_transport_state_change(struct userdata *u, struct pa_bluez4_transport *transport) {
-    bool acquire = false;
-    bool release = false;
-    pa_bluez4_profile_t profile;
-    pa_card_profile *cp;
-    pa_bluez4_transport_state_t state;
-    pa_device_port *port;
-
-    pa_assert(u);
-    pa_assert(transport);
-
-    profile = transport->profile;
-    state = transport->state;
-
-    /* Update profile availability */
-    if (!(cp = pa_hashmap_get(u->card->profiles, pa_bluez4_profile_to_string(profile))))
-        return;
-
-    pa_card_profile_set_available(cp, transport_state_to_availability(state));
-
-    /* Update port availability */
-    pa_assert_se(port = pa_hashmap_get(u->card->ports, u->output_port_name));
-    pa_device_port_set_available(port, get_port_availability(u, PA_DIRECTION_OUTPUT));
-
-    pa_assert_se(port = pa_hashmap_get(u->card->ports, u->input_port_name));
-    pa_device_port_set_available(port, get_port_availability(u, PA_DIRECTION_INPUT));
-
-    /* Acquire or release transport as needed */
-    acquire = (state == PA_BLUEZ4_TRANSPORT_STATE_PLAYING && u->profile == profile);
-    release = (state != PA_BLUEZ4_TRANSPORT_STATE_PLAYING && u->profile == profile);
-
-    if (acquire)
-        if (bt_transport_acquire(u, true) >= 0) {
-            if (u->source) {
-                pa_log_debug("Resuming source %s, because the bluetooth audio state changed to 'playing'.", u->source->name);
-                pa_source_suspend(u->source, false, PA_SUSPEND_IDLE|PA_SUSPEND_USER);
-            }
-
-            if (u->sink) {
-                pa_log_debug("Resuming sink %s, because the bluetooth audio state changed to 'playing'.", u->sink->name);
-                pa_sink_suspend(u->sink, false, PA_SUSPEND_IDLE|PA_SUSPEND_USER);
-            }
-        }
-
-    if (release && u->transport_acquired) {
-        /* FIXME: this release is racy, since the audio stream might have
-           been set up again in the meantime (but not processed yet by PA).
-           BlueZ should probably release the transport automatically, and
-           in that case we would just mark the transport as released */
-
-        /* Remote side closed the stream so we consider it PA_SUSPEND_USER */
-        if (u->source) {
-            pa_log_debug("Suspending source %s, because the remote end closed the stream.", u->source->name);
-            pa_source_suspend(u->source, true, PA_SUSPEND_USER);
-        }
-
-        if (u->sink) {
-            pa_log_debug("Suspending sink %s, because the remote end closed the stream.", u->sink->name);
-            pa_sink_suspend(u->sink, true, PA_SUSPEND_USER);
-        }
-    }
-}
-
-/* Run from main thread */
-static void sink_set_volume_cb(pa_sink *s) {
-    uint16_t gain;
-    pa_volume_t volume;
-    struct userdata *u;
-    char *k;
-
-    pa_assert(s);
-    pa_assert(s->core);
-
-    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 == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
-    pa_assert(u->transport);
-
-    gain = (dbus_uint16_t) round((double) pa_cvolume_max(&s->real_volume) * HSP_MAX_GAIN / PA_VOLUME_NORM);
-    volume = (pa_volume_t) round((double) gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
-
-    pa_cvolume_set(&s->real_volume, u->sample_spec.channels, volume);
-
-    pa_bluez4_transport_set_speaker_gain(u->transport, gain);
-}
-
-/* Run from main thread */
-static void source_set_volume_cb(pa_source *s) {
-    uint16_t gain;
-    pa_volume_t volume;
-    struct userdata *u;
-    char *k;
-
-    pa_assert(s);
-    pa_assert(s->core);
-
-    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 == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
-    pa_assert(u->transport);
-
-    gain = (dbus_uint16_t) round((double) pa_cvolume_max(&s->real_volume) * HSP_MAX_GAIN / PA_VOLUME_NORM);
-    volume = (pa_volume_t) round((double) gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
-
-    pa_cvolume_set(&s->real_volume, u->sample_spec.channels, volume);
-
-    pa_bluez4_transport_set_microphone_gain(u->transport, gain);
-}
-
-/* Run from main thread */
-static char *get_name(const char *type, pa_modargs *ma, const char *device_id, const char *profile, bool *namereg_fail) {
-    char *t;
-    const char *n;
-
-    pa_assert(type);
-    pa_assert(ma);
-    pa_assert(device_id);
-    pa_assert(namereg_fail);
-
-    t = pa_sprintf_malloc("%s_name", type);
-    n = pa_modargs_get_value(ma, t, NULL);
-    pa_xfree(t);
-
-    if (n) {
-        *namereg_fail = true;
-        return pa_xstrdup(n);
-    }
-
-    if ((n = pa_modargs_get_value(ma, "name", NULL)))
-        *namereg_fail = true;
-    else {
-        n = device_id;
-        *namereg_fail = false;
-    }
-
-    if (profile)
-        return pa_sprintf_malloc("bluez_%s.%s.%s", type, n, profile);
-    else
-        return pa_sprintf_malloc("bluez_%s.%s", type, n);
-}
-
-static int sco_over_pcm_state_update(struct userdata *u, bool changed) {
-    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->stream_fd >= 0)
-            return 0;
-
-        pa_log_debug("Resuming SCO over PCM");
-        if (init_profile(u) < 0) {
-            pa_log("Can't resume SCO over PCM");
-            return -1;
-        }
-
-        if (bt_transport_acquire(u, false) < 0)
-            return -1;
-
-        setup_stream(u);
-
-        return 0;
-    }
-
-    if (changed) {
-        if (u->stream_fd < 0)
-            return 0;
-
-        pa_log_debug("Closing SCO over PCM");
-
-        bt_transport_release(u);
-    }
-
-    return 0;
-}
-
-static pa_hook_result_t sink_state_changed_cb(pa_core *c, pa_sink *s, struct userdata *u) {
-    pa_assert(c);
-    pa_sink_assert_ref(s);
-    pa_assert(u);
-
-    if (!USE_SCO_OVER_PCM(u) || s != u->hsp.sco_sink)
-        return PA_HOOK_OK;
-
-    sco_over_pcm_state_update(u, true);
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct userdata *u) {
-    pa_assert(c);
-    pa_source_assert_ref(s);
-    pa_assert(u);
-
-    if (!USE_SCO_OVER_PCM(u) || s != u->hsp.sco_source)
-        return PA_HOOK_OK;
-
-    sco_over_pcm_state_update(u, true);
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t transport_nrec_changed_cb(pa_bluez4_discovery *y, pa_bluez4_transport *t, struct userdata *u) {
-    pa_proplist *p;
-
-    pa_assert(t);
-    pa_assert(u);
-
-    if (t != u->transport)
-        return PA_HOOK_OK;
-
-    p = pa_proplist_new();
-    pa_proplist_sets(p, "bluetooth.nrec", t->nrec ? "1" : "0");
-    pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, p);
-    pa_proplist_free(p);
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluez4_discovery *y, pa_bluez4_transport *t,
-                                                             struct userdata *u) {
-    pa_cvolume v;
-
-    pa_assert(t);
-    pa_assert(u);
-
-    if (t != u->transport)
-        return PA_HOOK_OK;
-
-    pa_assert(u->source);
-
-    pa_cvolume_set(&v, u->sample_spec.channels,
-                   (pa_volume_t) round((double) t->microphone_gain * PA_VOLUME_NORM / HSP_MAX_GAIN));
-    pa_source_volume_changed(u->source, &v);
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t transport_speaker_gain_changed_cb(pa_bluez4_discovery *y, pa_bluez4_transport *t,
-                                                          struct userdata *u) {
-    pa_cvolume v;
-
-    pa_assert(t);
-    pa_assert(u);
-
-    if (t != u->transport)
-        return PA_HOOK_OK;
-
-    pa_assert(u->sink);
-
-    pa_cvolume_set(&v, u->sample_spec.channels, (pa_volume_t) round((double) t->speaker_gain * PA_VOLUME_NORM / HSP_MAX_GAIN));
-    pa_sink_volume_changed(u->sink, &v);
-
-    return PA_HOOK_OK;
-}
-
-static void connect_ports(struct userdata *u, void *sink_or_source_new_data, pa_direction_t direction) {
-    pa_device_port *port;
-
-    if (direction == PA_DIRECTION_OUTPUT) {
-        pa_sink_new_data *sink_new_data = sink_or_source_new_data;
-
-        pa_assert_se(port = pa_hashmap_get(u->card->ports, u->output_port_name));
-        pa_assert_se(pa_hashmap_put(sink_new_data->ports, port->name, port) >= 0);
-        pa_device_port_ref(port);
-    } else {
-        pa_source_new_data *source_new_data = sink_or_source_new_data;
-
-        pa_assert_se(port = pa_hashmap_get(u->card->ports, u->input_port_name));
-        pa_assert_se(pa_hashmap_put(source_new_data->ports, port->name, port) >= 0);
-        pa_device_port_ref(port);
-    }
-}
-
-static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
-    return 0;
-}
-
-static int source_set_port_cb(pa_source *s, pa_device_port *p) {
-    return 0;
-}
-
-/* Run from main thread */
-static int add_sink(struct userdata *u) {
-    char *k;
-
-    pa_assert(u->transport);
-
-    if (USE_SCO_OVER_PCM(u)) {
-        pa_proplist *p;
-
-        u->sink = u->hsp.sco_sink;
-        p = pa_proplist_new();
-        pa_proplist_sets(p, "bluetooth.protocol", pa_bluez4_profile_to_string(u->profile));
-        pa_proplist_update(u->sink->proplist, PA_UPDATE_MERGE, p);
-        pa_proplist_free(p);
-    } else {
-        pa_sink_new_data data;
-        bool b;
-
-        pa_sink_new_data_init(&data);
-        data.driver = __FILE__;
-        data.module = u->module;
-        pa_sink_new_data_set_sample_spec(&data, &u->sample_spec);
-        pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluez4_profile_to_string(u->profile));
-        if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT)
-            pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
-        data.card = u->card;
-        data.name = get_name("sink", u->modargs, u->address, pa_bluez4_profile_to_string(u->profile), &b);
-        data.namereg_fail = b;
-
-        if (pa_modargs_get_proplist(u->modargs, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
-            pa_log("Invalid properties");
-            pa_sink_new_data_done(&data);
-            return -1;
-        }
-        connect_ports(u, &data, PA_DIRECTION_OUTPUT);
-
-        if (!u->transport_acquired)
-            switch (u->profile) {
-                case PA_BLUEZ4_PROFILE_A2DP_SINK:
-                case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
-                    pa_assert_not_reached(); /* Profile switch should have failed */
-                    break;
-                case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
-                    data.suspend_cause = PA_SUSPEND_USER;
-                    break;
-                case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
-                case PA_BLUEZ4_PROFILE_OFF:
-                    pa_assert_not_reached();
-            }
-
-        u->sink = pa_sink_new(u->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
-        pa_sink_new_data_done(&data);
-
-        if (!u->sink) {
-            pa_log_error("Failed to create sink");
-            return -1;
-        }
-
-        u->sink->userdata = u;
-        u->sink->parent.process_msg = sink_process_msg;
-        u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
-        u->sink->set_port = sink_set_port_cb;
-    }
-
-    if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
-        pa_sink_set_set_volume_callback(u->sink, 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;
-}
-
-/* Run from main thread */
-static int add_source(struct userdata *u) {
-    char *k;
-
-    pa_assert(u->transport);
-
-    if (USE_SCO_OVER_PCM(u)) {
-        u->source = u->hsp.sco_source;
-        pa_proplist_sets(u->source->proplist, "bluetooth.protocol", pa_bluez4_profile_to_string(u->profile));
-    } else {
-        pa_source_new_data data;
-        bool b;
-
-        pa_source_new_data_init(&data);
-        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", pa_bluez4_profile_to_string(u->profile));
-        if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT)
-            pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
-
-        data.card = u->card;
-        data.name = get_name("source", u->modargs, u->address, pa_bluez4_profile_to_string(u->profile), &b);
-        data.namereg_fail = b;
-
-        if (pa_modargs_get_proplist(u->modargs, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
-            pa_log("Invalid properties");
-            pa_source_new_data_done(&data);
-            return -1;
-        }
-
-        connect_ports(u, &data, PA_DIRECTION_INPUT);
-
-        if (!u->transport_acquired)
-            switch (u->profile) {
-                case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
-                    pa_assert_not_reached(); /* Profile switch should have failed */
-                    break;
-                case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
-                case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
-                    data.suspend_cause = PA_SUSPEND_USER;
-                    break;
-                case PA_BLUEZ4_PROFILE_A2DP_SINK:
-                case PA_BLUEZ4_PROFILE_OFF:
-                    pa_assert_not_reached();
-            }
-
-        u->source = pa_source_new(u->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
-        pa_source_new_data_done(&data);
-
-        if (!u->source) {
-            pa_log_error("Failed to create source");
-            return -1;
-        }
-
-        u->source->userdata = u;
-        u->source->parent.process_msg = source_process_msg;
-        u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
-        u->source->set_port = source_set_port_cb;
-    }
-
-    if ((u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) || (u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)) {
-        pa_bluez4_transport *t = u->transport;
-        pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
-    }
-
-    if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
-        pa_source_set_set_volume_callback(u->source, 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;
-}
-
-static void bt_transport_config_a2dp(struct userdata *u) {
-    const pa_bluez4_transport *t;
-    struct a2dp_info *a2dp = &u->a2dp;
-    a2dp_sbc_t *config;
-
-    t = u->transport;
-    pa_assert(t);
-
-    config = (a2dp_sbc_t *) t->config;
-
-    u->sample_spec.format = PA_SAMPLE_S16LE;
-
-    if (a2dp->sbc_initialized)
-        sbc_reinit(&a2dp->sbc, 0);
-    else
-        sbc_init(&a2dp->sbc, 0);
-    a2dp->sbc_initialized = true;
-
-    switch (config->frequency) {
-        case SBC_SAMPLING_FREQ_16000:
-            a2dp->sbc.frequency = SBC_FREQ_16000;
-            u->sample_spec.rate = 16000U;
-            break;
-        case SBC_SAMPLING_FREQ_32000:
-            a2dp->sbc.frequency = SBC_FREQ_32000;
-            u->sample_spec.rate = 32000U;
-            break;
-        case SBC_SAMPLING_FREQ_44100:
-            a2dp->sbc.frequency = SBC_FREQ_44100;
-            u->sample_spec.rate = 44100U;
-            break;
-        case SBC_SAMPLING_FREQ_48000:
-            a2dp->sbc.frequency = SBC_FREQ_48000;
-            u->sample_spec.rate = 48000U;
-            break;
-        default:
-            pa_assert_not_reached();
-    }
-
-    switch (config->channel_mode) {
-        case SBC_CHANNEL_MODE_MONO:
-            a2dp->sbc.mode = SBC_MODE_MONO;
-            u->sample_spec.channels = 1;
-            break;
-        case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-            a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
-            u->sample_spec.channels = 2;
-            break;
-        case SBC_CHANNEL_MODE_STEREO:
-            a2dp->sbc.mode = SBC_MODE_STEREO;
-            u->sample_spec.channels = 2;
-            break;
-        case SBC_CHANNEL_MODE_JOINT_STEREO:
-            a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
-            u->sample_spec.channels = 2;
-            break;
-        default:
-            pa_assert_not_reached();
-    }
-
-    switch (config->allocation_method) {
-        case SBC_ALLOCATION_SNR:
-            a2dp->sbc.allocation = SBC_AM_SNR;
-            break;
-        case SBC_ALLOCATION_LOUDNESS:
-            a2dp->sbc.allocation = SBC_AM_LOUDNESS;
-            break;
-        default:
-            pa_assert_not_reached();
-    }
-
-    switch (config->subbands) {
-        case SBC_SUBBANDS_4:
-            a2dp->sbc.subbands = SBC_SB_4;
-            break;
-        case SBC_SUBBANDS_8:
-            a2dp->sbc.subbands = SBC_SB_8;
-            break;
-        default:
-            pa_assert_not_reached();
-    }
-
-    switch (config->block_length) {
-        case SBC_BLOCK_LENGTH_4:
-            a2dp->sbc.blocks = SBC_BLK_4;
-            break;
-        case SBC_BLOCK_LENGTH_8:
-            a2dp->sbc.blocks = SBC_BLK_8;
-            break;
-        case SBC_BLOCK_LENGTH_12:
-            a2dp->sbc.blocks = SBC_BLK_12;
-            break;
-        case SBC_BLOCK_LENGTH_16:
-            a2dp->sbc.blocks = SBC_BLK_16;
-            break;
-        default:
-            pa_assert_not_reached();
-    }
-
-    a2dp->min_bitpool = config->min_bitpool;
-    a2dp->max_bitpool = config->max_bitpool;
-
-    /* Set minimum bitpool for source to get the maximum possible block_size */
-    a2dp->sbc.bitpool = u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK ? a2dp->max_bitpool : a2dp->min_bitpool;
-    a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
-    a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
-
-    pa_log_info("SBC parameters:\n\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u",
-                a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks, a2dp->sbc.bitpool);
-}
-
-static void bt_transport_config(struct userdata *u) {
-    if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY) {
-        u->sample_spec.format = PA_SAMPLE_S16LE;
-        u->sample_spec.channels = 1;
-        u->sample_spec.rate = 8000;
-    } else
-        bt_transport_config_a2dp(u);
-}
-
-/* Run from main thread */
-static pa_hook_result_t transport_state_changed_cb(pa_bluez4_discovery *y, pa_bluez4_transport *t, struct userdata *u) {
-    pa_assert(t);
-    pa_assert(u);
-
-    if (t == u->transport && t->state == PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED)
-        pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
-
-    if (t->device == u->device)
-        handle_transport_state_change(u, t);
-
-    return PA_HOOK_OK;
-}
-
-/* Run from main thread */
-static int setup_transport(struct userdata *u) {
-    pa_bluez4_transport *t;
-
-    pa_assert(u);
-    pa_assert(!u->transport);
-    pa_assert(u->profile != PA_BLUEZ4_PROFILE_OFF);
-
-    /* check if profile has a transport */
-    t = u->device->transports[u->profile];
-    if (!t || t->state == PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED) {
-        pa_log_warn("Profile has no transport");
-        return -1;
-    }
-
-    u->transport = t;
-
-    if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
-        bt_transport_acquire(u, true); /* In case of error, the sink/sources will be created suspended */
-    else if (bt_transport_acquire(u, false) < 0)
-        return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
-
-    bt_transport_config(u);
-
-    return 0;
-}
-
-/* Run from main thread */
-static int init_profile(struct userdata *u) {
-    int r = 0;
-    pa_assert(u);
-    pa_assert(u->profile != PA_BLUEZ4_PROFILE_OFF);
-
-    if (setup_transport(u) < 0)
-        return -1;
-
-    pa_assert(u->transport);
-
-    if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK ||
-        u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT ||
-        u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
-        if (add_sink(u) < 0)
-            r = -1;
-
-    if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT ||
-        u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE ||
-        u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
-        if (add_source(u) < 0)
-            r = -1;
-
-    return r;
-}
-
-/* Run from main thread */
-static void stop_thread(struct userdata *u) {
-    char *k;
-
-    pa_assert(u);
-
-    if (u->sink && !USE_SCO_OVER_PCM(u))
-        pa_sink_unlink(u->sink);
-
-    if (u->source && !USE_SCO_OVER_PCM(u))
-        pa_source_unlink(u->source);
-
-    if (u->thread) {
-        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
-        pa_thread_free(u->thread);
-        u->thread = NULL;
-    }
-
-    if (u->rtpoll_item) {
-        pa_rtpoll_item_free(u->rtpoll_item);
-        u->rtpoll_item = NULL;
-    }
-
-    if (u->rtpoll) {
-        pa_thread_mq_done(&u->thread_mq);
-
-        pa_rtpoll_free(u->rtpoll);
-        u->rtpoll = NULL;
-    }
-
-    if (u->transport) {
-        bt_transport_release(u);
-        u->transport = NULL;
-    }
-
-    if (u->sink) {
-        if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
-            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 == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
-            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;
-    }
-
-    if (u->read_smoother) {
-        pa_smoother_free(u->read_smoother);
-        u->read_smoother = NULL;
-    }
-}
-
-/* Run from main thread */
-static int start_thread(struct userdata *u) {
-    pa_assert(u);
-    pa_assert(!u->thread);
-    pa_assert(!u->rtpoll);
-    pa_assert(!u->rtpoll_item);
-
-    u->rtpoll = pa_rtpoll_new();
-
-    if (pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll) < 0) {
-        pa_log("pa_thread_mq_init() failed.");
-        return -1;
-    }
-
-    if (USE_SCO_OVER_PCM(u)) {
-        if (sco_over_pcm_state_update(u, false) < 0) {
-            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;
-        }
-
-        pa_sink_ref(u->sink);
-        pa_source_ref(u->source);
-        /* FIXME: monitor stream_fd error */
-        return 0;
-    }
-
-    if (!(u->thread = pa_thread_new("bluetooth", thread_func, u))) {
-        pa_log_error("Failed to create IO thread");
-        return -1;
-    }
-
-    if (u->sink) {
-        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
-        pa_sink_set_rtpoll(u->sink, u->rtpoll);
-        pa_sink_put(u->sink);
-
-        if (u->sink->set_volume)
-            u->sink->set_volume(u->sink);
-    }
-
-    if (u->source) {
-        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
-        pa_source_set_rtpoll(u->source, u->rtpoll);
-        pa_source_put(u->source);
-
-        if (u->source->set_volume)
-            u->source->set_volume(u->source);
-    }
-
-    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));
-
-    pa_sink_set_set_volume_callback(u->hsp.sco_sink, u->hsp.sco_sink_set_volume);
-    pa_source_set_set_volume_callback(u->hsp.sco_source, 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;
-    pa_bluez4_profile_t *d;
-
-    pa_assert(c);
-    pa_assert(new_profile);
-    pa_assert_se(u = c->userdata);
-
-    d = PA_CARD_PROFILE_DATA(new_profile);
-
-    if (*d != PA_BLUEZ4_PROFILE_OFF) {
-        const pa_bluez4_device *device = u->device;
-
-        if (!device->transports[*d] || device->transports[*d]->state == PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED) {
-            pa_log_warn("Profile not connected, refused to switch profile to %s", new_profile->name);
-            return -PA_ERR_IO;
-        }
-    }
-
-    stop_thread(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);
-
-    if (u->profile != PA_BLUEZ4_PROFILE_OFF)
-        if (init_profile(u) < 0)
-            goto off;
-
-    if (u->sink || u->source)
-        if (start_thread(u) < 0)
-            goto off;
-
-    return 0;
-
-off:
-    stop_thread(u);
-
-    pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
-
-    return -PA_ERR_IO;
-}
-
-/* Run from main thread */
-static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
-    pa_device_port *port;
-    pa_device_port_new_data port_data;
-
-    const char *name_prefix = NULL;
-    const char *input_description = NULL;
-    const char *output_description = NULL;
-
-    pa_assert(u);
-    pa_assert(ports);
-    pa_assert(u->device);
-
-    switch (pa_bluez4_get_form_factor(u->device->class)) {
-        case PA_BLUEZ4_FORM_FACTOR_UNKNOWN:
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_HEADSET:
-            name_prefix = "headset";
-            input_description = output_description = _("Headset");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_HANDSFREE:
-            name_prefix = "handsfree";
-            input_description = output_description = _("Handsfree");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_MICROPHONE:
-            name_prefix = "microphone";
-            input_description = _("Microphone");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_SPEAKER:
-            name_prefix = "speaker";
-            output_description = _("Speaker");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_HEADPHONE:
-            name_prefix = "headphone";
-            output_description = _("Headphone");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_PORTABLE:
-            name_prefix = "portable";
-            input_description = output_description = _("Portable");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_CAR:
-            name_prefix = "car";
-            input_description = output_description = _("Car");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_HIFI:
-            name_prefix = "hifi";
-            input_description = output_description = _("HiFi");
-            break;
-
-        case PA_BLUEZ4_FORM_FACTOR_PHONE:
-            name_prefix = "phone";
-            input_description = output_description = _("Phone");
-            break;
-    }
-
-    if (!name_prefix)
-        name_prefix = "unknown";
-
-    if (!output_description)
-        output_description = _("Bluetooth Output");
-
-    if (!input_description)
-        input_description = _("Bluetooth Input");
-
-    u->output_port_name = pa_sprintf_malloc("%s-output", name_prefix);
-    u->input_port_name = pa_sprintf_malloc("%s-input", name_prefix);
-
-    pa_device_port_new_data_init(&port_data);
-    pa_device_port_new_data_set_name(&port_data, u->output_port_name);
-    pa_device_port_new_data_set_description(&port_data, output_description);
-    pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_OUTPUT);
-    pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_OUTPUT));
-    pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
-    pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-    pa_device_port_new_data_done(&port_data);
-
-    pa_device_port_new_data_init(&port_data);
-    pa_device_port_new_data_set_name(&port_data, u->input_port_name);
-    pa_device_port_new_data_set_description(&port_data, input_description);
-    pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_INPUT);
-    pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_INPUT));
-    pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
-    pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-    pa_device_port_new_data_done(&port_data);
-}
-
-/* Run from main thread */
-static pa_card_profile *create_card_profile(struct userdata *u, pa_bluez4_profile_t profile, pa_hashmap *ports) {
-    pa_device_port *input_port, *output_port;
-    const char *name;
-    pa_card_profile *p = NULL;
-    pa_bluez4_profile_t *d = NULL;
-    pa_bluez4_transport *t;
-
-    pa_assert(u->input_port_name);
-    pa_assert(u->output_port_name);
-    pa_assert_se(input_port = pa_hashmap_get(ports, u->input_port_name));
-    pa_assert_se(output_port = pa_hashmap_get(ports, u->output_port_name));
-
-    name = pa_bluez4_profile_to_string(profile);
-
-    switch (profile) {
-    case PA_BLUEZ4_PROFILE_A2DP_SINK:
-        p = pa_card_profile_new(name, _("High Fidelity Playback (A2DP)"), sizeof(pa_bluez4_profile_t));
-        p->priority = 10;
-        p->n_sinks = 1;
-        p->n_sources = 0;
-        p->max_sink_channels = 2;
-        p->max_source_channels = 0;
-        pa_hashmap_put(output_port->profiles, p->name, p);
-
-        d = PA_CARD_PROFILE_DATA(p);
-        break;
-
-    case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
-        p = pa_card_profile_new(name, _("High Fidelity Capture (A2DP)"), sizeof(pa_bluez4_profile_t));
-        p->priority = 10;
-        p->n_sinks = 0;
-        p->n_sources = 1;
-        p->max_sink_channels = 0;
-        p->max_source_channels = 2;
-        pa_hashmap_put(input_port->profiles, p->name, p);
-
-        d = PA_CARD_PROFILE_DATA(p);
-        break;
-
-    case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
-        p = pa_card_profile_new(name, _("Telephony Duplex (HSP/HFP)"), sizeof(pa_bluez4_profile_t));
-        p->priority = 20;
-        p->n_sinks = 1;
-        p->n_sources = 1;
-        p->max_sink_channels = 1;
-        p->max_source_channels = 1;
-        pa_hashmap_put(input_port->profiles, p->name, p);
-        pa_hashmap_put(output_port->profiles, p->name, p);
-
-        d = PA_CARD_PROFILE_DATA(p);
-        break;
-
-    case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
-        p = pa_card_profile_new(name, _("Handsfree Gateway"), sizeof(pa_bluez4_profile_t));
-        p->priority = 20;
-        p->n_sinks = 1;
-        p->n_sources = 1;
-        p->max_sink_channels = 1;
-        p->max_source_channels = 1;
-        pa_hashmap_put(input_port->profiles, p->name, p);
-        pa_hashmap_put(output_port->profiles, p->name, p);
-
-        d = PA_CARD_PROFILE_DATA(p);
-        break;
-
-    case PA_BLUEZ4_PROFILE_OFF:
-        pa_assert_not_reached();
-    }
-
-    *d = profile;
-
-    if ((t = u->device->transports[*d]))
-        p->available = transport_state_to_availability(t->state);
-
-    return p;
-}
-
-static int uuid_to_profile(const char *uuid, pa_bluez4_profile_t *_r) {
-    if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SINK))
-        *_r = PA_BLUEZ4_PROFILE_A2DP_SINK;
-    else if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SOURCE))
-        *_r = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
-    else if (pa_streq(uuid, PA_BLUEZ4_UUID_HSP_HS) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_HF))
-        *_r = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
-    else if (pa_streq(uuid, PA_BLUEZ4_UUID_HSP_AG) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG))
-        *_r = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
-    else
-        return -PA_ERR_INVALID;
-
-    return 0;
-}
-
-/* Run from main thread */
-static int add_card(struct userdata *u) {
-    pa_card_new_data data;
-    bool b;
-    pa_card_profile *p;
-    pa_bluez4_profile_t *d;
-    pa_bluez4_form_factor_t ff;
-    char *n;
-    const char *profile_str;
-    const pa_bluez4_device *device;
-    const char *uuid;
-    void *state;
-
-    pa_assert(u);
-    pa_assert(u->device);
-
-    device = u->device;
-
-    pa_card_new_data_init(&data);
-    data.driver = __FILE__;
-    data.module = u->module;
-
-    n = pa_utf8_filter(device->alias);
-    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, n);
-    pa_xfree(n);
-    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, device->address);
-    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "bluez");
-    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
-    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "bluetooth");
-
-    if ((ff = pa_bluez4_get_form_factor(device->class)) != PA_BLUEZ4_FORM_FACTOR_UNKNOWN)
-        pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, pa_bluez4_form_factor_to_string(ff));
-
-    pa_proplist_sets(data.proplist, "bluez.path", device->path);
-    pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", (unsigned) device->class);
-    pa_proplist_sets(data.proplist, "bluez.alias", device->alias);
-    data.name = get_name("card", u->modargs, device->address, NULL, &b);
-    data.namereg_fail = b;
-
-    if (pa_modargs_get_proplist(u->modargs, "card_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
-        pa_log("Invalid properties");
-        pa_card_new_data_done(&data);
-        return -1;
-    }
-
-    create_card_ports(u, data.ports);
-
-    PA_HASHMAP_FOREACH(uuid, device->uuids, state) {
-        pa_bluez4_profile_t profile;
-
-        if (uuid_to_profile(uuid, &profile) < 0)
-            continue;
-
-        if (pa_hashmap_get(data.profiles, pa_bluez4_profile_to_string(profile)))
-            continue;
-
-        p = create_card_profile(u, profile, data.ports);
-        pa_hashmap_put(data.profiles, p->name, p);
-    }
-
-    pa_assert(!pa_hashmap_isempty(data.profiles));
-
-    p = pa_card_profile_new("off", _("Off"), sizeof(pa_bluez4_profile_t));
-    p->available = PA_AVAILABLE_YES;
-    d = PA_CARD_PROFILE_DATA(p);
-    *d = PA_BLUEZ4_PROFILE_OFF;
-    pa_hashmap_put(data.profiles, p->name, p);
-
-    u->card = pa_card_new(u->core, &data);
-    pa_card_new_data_done(&data);
-
-    if (!u->card) {
-        pa_log("Failed to allocate card.");
-        return -1;
-    }
-
-    u->card->userdata = u;
-    u->card->set_profile = card_set_profile;
-
-    pa_card_choose_initial_profile(u->card);
-
-    /* If the "profile" modarg is given, we have to override whatever the usual
-     * policy chose in pa_card_choose_initial_profile(). */
-    profile_str = pa_modargs_get_value(u->modargs, "profile", NULL);
-    if (profile_str) {
-        pa_card_profile *profile;
-
-        profile = pa_hashmap_get(u->card->profiles, profile_str);
-        if (!profile) {
-            pa_log("No such profile: %s", profile_str);
-            return -1;
-        }
-
-        pa_card_set_profile(u->card, profile, false);
-    }
-
-    pa_card_put(u->card);
-
-    d = PA_CARD_PROFILE_DATA(u->card->active_profile);
-
-    if (*d != PA_BLUEZ4_PROFILE_OFF && (!device->transports[*d] ||
-                              device->transports[*d]->state == PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED)) {
-        pa_log_warn("Default profile not connected, selecting off profile");
-        u->card->active_profile = pa_hashmap_get(u->card->profiles, "off");
-        u->card->save_profile = false;
-    }
-
-    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;
-}
-
-/* Run from main thread */
-static pa_bluez4_device* find_device(struct userdata *u, const char *address, const char *path) {
-    pa_bluez4_device *d = NULL;
-
-    pa_assert(u);
-
-    if (!address && !path) {
-        pa_log_error("Failed to get device address/path from module arguments.");
-        return NULL;
-    }
-
-    if (path) {
-        if (!(d = pa_bluez4_discovery_get_by_path(u->discovery, path))) {
-            pa_log_error("%s is not a valid BlueZ audio device.", path);
-            return NULL;
-        }
-
-        if (address && !(pa_streq(d->address, address))) {
-            pa_log_error("Passed path %s address %s != %s don't match.", path, d->address, address);
-            return NULL;
-        }
-
-    } else {
-        if (!(d = pa_bluez4_discovery_get_by_address(u->discovery, address))) {
-            pa_log_error("%s is not known.", address);
-            return NULL;
-        }
-    }
-
-    if (d) {
-        u->address = pa_xstrdup(d->address);
-        u->path = pa_xstrdup(d->path);
-    }
-
-    return d;
-}
-
-/* Run from main thread */
-static pa_hook_result_t uuid_added_cb(pa_bluez4_discovery *y, const struct pa_bluez4_hook_uuid_data *data,
-                                      struct userdata *u) {
-    pa_bluez4_profile_t profile;
-    pa_card_profile *p;
-
-    pa_assert(data);
-    pa_assert(data->device);
-    pa_assert(data->uuid);
-    pa_assert(u);
-
-    if (data->device != u->device)
-        return PA_HOOK_OK;
-
-    if (uuid_to_profile(data->uuid, &profile) < 0)
-        return PA_HOOK_OK;
-
-    if (pa_hashmap_get(u->card->profiles, pa_bluez4_profile_to_string(profile)))
-        return PA_HOOK_OK;
-
-    p = create_card_profile(u, profile, u->card->ports);
-    pa_card_add_profile(u->card, p);
-
-    return PA_HOOK_OK;
-}
-
-/* Run from main thread */
-static pa_hook_result_t discovery_hook_cb(pa_bluez4_discovery *y, const pa_bluez4_device *d, struct userdata *u) {
-    pa_assert(u);
-    pa_assert(d);
-
-    if (d != u->device)
-        return PA_HOOK_OK;
-
-    if (d->dead)
-        pa_log_debug("Device %s removed: unloading module", d->path);
-    else if (!pa_bluez4_device_any_audio_connected(d))
-        pa_log_debug("Unloading module, because device %s doesn't have any audio profiles connected anymore.", d->path);
-    else
-        return PA_HOOK_OK;
-
-    pa_module_unload(u->module, true);
-
-    return PA_HOOK_OK;
-}
-
-int pa__init(pa_module *m) {
-    pa_modargs *ma;
-    uint32_t channels;
-    struct userdata *u;
-    const char *address, *path;
-    pa_bluez4_device *device;
-
-    pa_assert(m);
-
-    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log_error("Failed to parse module arguments");
-        goto fail;
-    }
-
-    m->userdata = u = pa_xnew0(struct userdata, 1);
-    u->module = m;
-    u->core = m->core;
-    u->stream_fd = -1;
-    u->sample_spec = m->core->default_sample_spec;
-    u->modargs = ma;
-
-    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");
-        goto fail;
-    }
-
-    if (pa_modargs_get_value(ma, "sco_source", NULL) &&
-        !(u->hsp.sco_source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sco_source", NULL), PA_NAMEREG_SOURCE))) {
-        pa_log("SCO source not found");
-        goto fail;
-    }
-
-    if (pa_modargs_get_sample_rate(ma, &u->sample_spec.rate) < 0) {
-        pa_log_error("Failed to get rate from module arguments");
-        goto fail;
-    }
-
-    channels = u->sample_spec.channels;
-    if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 ||
-        !pa_channels_valid(channels)) {
-        pa_log_error("Failed to get channels from module arguments");
-        goto fail;
-    }
-    u->sample_spec.channels = (uint8_t) channels;
-    u->requested_sample_spec = u->sample_spec;
-
-    address = pa_modargs_get_value(ma, "address", NULL);
-    path = pa_modargs_get_value(ma, "path", NULL);
-
-    if (!(u->discovery = pa_bluez4_discovery_get(m->core)))
-        goto fail;
-
-    if (!(device = find_device(u, address, path)))
-        goto fail;
-
-    u->device = device;
-
-    u->discovery_slot =
-        pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_DEVICE_CONNECTION_CHANGED),
-                        PA_HOOK_NORMAL, (pa_hook_cb_t) discovery_hook_cb, u);
-
-    u->uuid_added_slot =
-        pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_DEVICE_UUID_ADDED),
-                        PA_HOOK_NORMAL, (pa_hook_cb_t) uuid_added_cb, u);
-
-    u->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);
-
-    u->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);
-
-    u->transport_state_changed_slot =
-        pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED),
-                        PA_HOOK_NORMAL, (pa_hook_cb_t) transport_state_changed_cb, u);
-
-    u->transport_nrec_changed_slot =
-        pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_TRANSPORT_NREC_CHANGED),
-                        PA_HOOK_NORMAL, (pa_hook_cb_t) transport_nrec_changed_cb, u);
-
-    u->transport_microphone_changed_slot =
-        pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED),
-                        PA_HOOK_NORMAL, (pa_hook_cb_t) transport_microphone_gain_changed_cb, u);
-
-    u->transport_speaker_changed_slot =
-        pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED),
-                        PA_HOOK_NORMAL, (pa_hook_cb_t) transport_speaker_gain_changed_cb, u);
-
-    /* Add the card structure. This will also initialize the default profile */
-    if (add_card(u) < 0)
-        goto fail;
-
-    if (!(u->msg = pa_msgobject_new(bluetooth_msg)))
-        goto fail;
-
-    u->msg->parent.process_msg = device_process_msg;
-    u->msg->card = u->card;
-
-    if (u->profile != PA_BLUEZ4_PROFILE_OFF)
-        if (init_profile(u) < 0)
-            goto off;
-
-    if (u->sink || u->source)
-        if (start_thread(u) < 0)
-            goto off;
-
-    return 0;
-
-off:
-    stop_thread(u);
-
-    pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
-
-    return 0;
-
-fail:
-
-    pa__done(m);
-
-    return -1;
-}
-
-int pa__get_n_used(pa_module *m) {
-    struct userdata *u;
-
-    pa_assert(m);
-    pa_assert_se(u = m->userdata);
-
-    return
-        (u->sink ? pa_sink_linked_by(u->sink) : 0) +
-        (u->source ? pa_source_linked_by(u->source) : 0);
-}
-
-void pa__done(pa_module *m) {
-    struct userdata *u;
-
-    pa_assert(m);
-
-    if (!(u = m->userdata))
-        return;
-
-    stop_thread(u);
-
-    if (u->discovery_slot)
-        pa_hook_slot_free(u->discovery_slot);
-
-    if (u->uuid_added_slot)
-        pa_hook_slot_free(u->uuid_added_slot);
-
-    if (u->sink_state_changed_slot)
-        pa_hook_slot_free(u->sink_state_changed_slot);
-
-    if (u->source_state_changed_slot)
-        pa_hook_slot_free(u->source_state_changed_slot);
-
-    if (u->transport_state_changed_slot)
-        pa_hook_slot_free(u->transport_state_changed_slot);
-
-    if (u->transport_nrec_changed_slot)
-        pa_hook_slot_free(u->transport_nrec_changed_slot);
-
-    if (u->transport_microphone_changed_slot)
-        pa_hook_slot_free(u->transport_microphone_changed_slot);
-
-    if (u->transport_speaker_changed_slot)
-        pa_hook_slot_free(u->transport_speaker_changed_slot);
-
-    if (USE_SCO_OVER_PCM(u))
-        restore_sco_volume_callbacks(u);
-
-    if (u->msg)
-        pa_xfree(u->msg);
-
-    if (u->card)
-        pa_card_free(u->card);
-
-    if (u->a2dp.buffer)
-        pa_xfree(u->a2dp.buffer);
-
-    sbc_finish(&u->a2dp.sbc);
-
-    if (u->modargs)
-        pa_modargs_free(u->modargs);
-
-    pa_xfree(u->output_port_name);
-    pa_xfree(u->input_port_name);
-
-    pa_xfree(u->address);
-    pa_xfree(u->path);
-
-    if (u->discovery)
-        pa_bluez4_discovery_unref(u->discovery);
-
-    pa_xfree(u);
-}
diff --git a/src/modules/bluetooth/module-bluez4-discover.c b/src/modules/bluetooth/module-bluez4-discover.c
deleted file mode 100644
index 2813cd54..00000000
--- a/src/modules/bluetooth/module-bluez4-discover.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/***
-  This file is part of PulseAudio.
-
-  Copyright 2008-2013 João Paulo Rechi Vita
-
-  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, see <http://www.gnu.org/licenses/>.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <pulse/xmalloc.h>
-#include <pulsecore/module.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/modargs.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/dbus-shared.h>
-
-#include "bluez4-util.h"
-
-PA_MODULE_AUTHOR("João Paulo Rechi Vita");
-PA_MODULE_DESCRIPTION("Detect available BlueZ 4 Bluetooth audio devices and load BlueZ 4 Bluetooth audio drivers");
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_USAGE("sco_sink=<name of sink> "
-                "sco_source=<name of source> ");
-PA_MODULE_LOAD_ONCE(true);
-
-static const char* const valid_modargs[] = {
-    "sco_sink",
-    "sco_source",
-    "async", /* deprecated */
-    NULL
-};
-
-struct userdata {
-    pa_module *module;
-    pa_modargs *modargs;
-    pa_core *core;
-    pa_bluez4_discovery *discovery;
-    pa_hook_slot *slot;
-    pa_hashmap *hashmap;
-};
-
-struct pa_module_info {
-    char *path;
-    uint32_t module;
-};
-
-static pa_hook_result_t load_module_for_device(pa_bluez4_discovery *y, const pa_bluez4_device *d, struct userdata *u) {
-    struct pa_module_info *mi;
-
-    pa_assert(u);
-    pa_assert(d);
-
-    mi = pa_hashmap_get(u->hashmap, d->path);
-
-    if (pa_bluez4_device_any_audio_connected(d)) {
-
-        if (!mi) {
-            pa_module *m = NULL;
-            char *args;
-
-            /* Oh, awesome, a new device has shown up and been connected! */
-
-            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\"", d->address, d->path);
-
-            if (pa_modargs_get_value(u->modargs, "sco_sink", NULL) &&
-                pa_modargs_get_value(u->modargs, "sco_source", NULL)) {
-                char *tmp;
-
-                tmp = pa_sprintf_malloc("%s sco_sink=\"%s\" sco_source=\"%s\"", args,
-                                        pa_modargs_get_value(u->modargs, "sco_sink", NULL),
-                                        pa_modargs_get_value(u->modargs, "sco_source", NULL));
-                pa_xfree(args);
-                args = tmp;
-            }
-
-            pa_log_debug("Loading module-bluez4-device %s", args);
-            pa_module_load(&m, u->module->core, "module-bluez4-device", args);
-            pa_xfree(args);
-
-            if (m) {
-                mi = pa_xnew(struct pa_module_info, 1);
-                mi->module = m->index;
-                mi->path = pa_xstrdup(d->path);
-
-                pa_hashmap_put(u->hashmap, mi->path, mi);
-            } else
-                pa_log_debug("Failed to load module for device %s", d->path);
-        }
-
-    } else {
-
-        if (mi) {
-
-            /* Hmm, disconnection? Then the module unloads itself */
-
-            pa_log_debug("Unregistering module for %s", d->path);
-            pa_hashmap_remove(u->hashmap, mi->path);
-            pa_xfree(mi->path);
-            pa_xfree(mi);
-        }
-    }
-
-    return PA_HOOK_OK;
-}
-
-int pa__init(pa_module* m) {
-    struct userdata *u;
-    pa_modargs *ma;
-
-    pa_assert(m);
-
-    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("Failed to parse module arguments");
-        goto fail;
-    }
-
-    if (pa_modargs_get_value(ma, "async", NULL))
-        pa_log_warn("The 'async' argument is deprecated and does nothing.");
-
-    m->userdata = u = pa_xnew0(struct userdata, 1);
-    u->module = m;
-    u->core = m->core;
-    u->modargs = ma;
-    u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
-    if (!(u->discovery = pa_bluez4_discovery_get(u->core)))
-        goto fail;
-
-    u->slot = pa_hook_connect(pa_bluez4_discovery_hook(u->discovery, PA_BLUEZ4_HOOK_DEVICE_CONNECTION_CHANGED),
-                              PA_HOOK_NORMAL, (pa_hook_cb_t) load_module_for_device, u);
-
-    return 0;
-
-fail:
-    pa__done(m);
-
-    return -1;
-}
-
-void pa__done(pa_module* m) {
-    struct userdata *u;
-
-    pa_assert(m);
-
-    if (!(u = m->userdata))
-        return;
-
-    if (u->slot)
-        pa_hook_slot_free(u->slot);
-
-    if (u->discovery)
-        pa_bluez4_discovery_unref(u->discovery);
-
-    if (u->hashmap) {
-        struct pa_module_info *mi;
-
-        while ((mi = pa_hashmap_steal_first(u->hashmap))) {
-            pa_xfree(mi->path);
-            pa_xfree(mi);
-        }
-
-        pa_hashmap_free(u->hashmap);
-    }
-
-    if (u->modargs)
-        pa_modargs_free(u->modargs);
-
-    pa_xfree(u);
-}

commit fb600395e1e13ef68e36153faf02bda287927ae2
Author: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Date:   Thu Mar 22 14:56:00 2018 +0200

    bluetooth: ofono: Use Acquire method if available
    
    Attempt to use Acquire method if available since it directly returns
    the fd in the reply or an error if that the connection could not be
    created while Connect offer neither of these and depend on
    NewConnection to deliver the fd.

diff --git a/src/modules/bluetooth/backend-ofono.c b/src/modules/bluetooth/backend-ofono.c
index 2c51497f..5f427043 100644
--- a/src/modules/bluetooth/backend-ofono.c
+++ b/src/modules/bluetooth/backend-ofono.c
@@ -67,7 +67,7 @@ struct hf_audio_card {
 
     bool connecting;
     int fd;
-    uint8_t codec;
+    int (*acquire)(struct hf_audio_card *card);
 
     pa_bluetooth_transport *transport;
 };
@@ -99,12 +99,95 @@ static pa_dbus_pending* hf_dbus_send_and_add_to_pending(pa_bluetooth_backend *ba
     return p;
 }
 
+static DBusMessage *card_send(struct hf_audio_card *card, const char *method, DBusError *err)
+{
+    pa_bluetooth_transport *t = card->transport;
+    DBusMessage *m, *r;
+
+    pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", method));
+    r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(card->backend->connection), m, -1, err);
+    dbus_message_unref(m);
+
+    return r;
+}
+
+static int card_connect(struct hf_audio_card *card) {
+    DBusMessage *r;
+    DBusError err;
+
+    if (card->connecting)
+        return -EAGAIN;
+
+    card->connecting = true;
+
+    dbus_error_init(&err);
+    r = card_send(card, "Connect", &err);
+
+    if (!r) {
+        pa_log_error("Failed to connect %s: %s", err.name, err.message);
+        card->connecting = false;
+        dbus_error_free(&err);
+        return -1;
+    }
+
+    dbus_message_unref(r);
+
+    if (card->connecting)
+        return -EAGAIN;
+
+    return 0;
+}
+
+static int card_acquire(struct hf_audio_card *card) {
+    int fd;
+    uint8_t codec;
+    DBusMessage *r;
+    DBusError err;
+
+    /* Try acquiring the stream first which was introduced in 1.21 */
+    dbus_error_init(&err);
+    r = card_send(card, "Acquire", &err);
+
+    if (!r) {
+        if (!pa_streq(err.name, DBUS_ERROR_UNKNOWN_METHOD)) {
+            pa_log_error("Failed to acquire %s: %s", err.name, err.message);
+            dbus_error_free(&err);
+            return -1;
+        }
+        dbus_error_free(&err);
+        /* Fallback to Connect as this might be an old version of ofono */
+        card->acquire = card_connect;
+        return card_connect(card);
+    }
+
+    if ((dbus_message_get_args(r, NULL, DBUS_TYPE_UNIX_FD, &fd,
+                                      DBUS_TYPE_BYTE, &codec,
+                                      DBUS_TYPE_INVALID) == true)) {
+        dbus_message_unref(r);
+        if (codec != HFP_AUDIO_CODEC_CVSD) {
+            pa_log_error("Invalid codec: %u", codec);
+            /* shutdown to make sure connection is dropped immediately */
+            shutdown(fd, SHUT_RDWR);
+            close(fd);
+            return -1;
+        }
+        card->transport->codec = codec;
+        card->fd = fd;
+        return 0;
+    }
+
+    pa_log_error("Unable to acquire");
+    dbus_message_unref(r);
+    return -1;
+}
+
 static struct hf_audio_card *hf_audio_card_new(pa_bluetooth_backend *backend, const char *path) {
     struct hf_audio_card *card = pa_xnew0(struct hf_audio_card, 1);
 
     card->path = pa_xstrdup(path);
     card->backend = backend;
     card->fd = -1;
+    card->acquire = card_acquire;
 
     return card;
 }
@@ -157,28 +240,9 @@ static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool opti
     pa_assert(card);
 
     if (!optional && card->fd < 0) {
-        DBusMessage *m, *r;
-        DBusError derr;
-
-        if (card->connecting)
-            return -EAGAIN;
-
-        card->connecting = true;
-
-        dbus_error_init(&derr);
-        pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", "Connect"));
-        r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(card->backend->connection), m, -1, &derr);
-        dbus_message_unref(m);
-        m = NULL;
-
-        if (!r)
-            return -1;
-
-        dbus_message_unref(r);
-        r = NULL;
-
-        if (card->connecting)
-            return -EAGAIN;
+        err = card->acquire(card);
+        if (err < 0)
+            return err;
     }
 
     /* The correct block size should take into account the SCO MTU from
@@ -191,8 +255,6 @@ static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool opti
     if (omtu)
         *omtu = 48;
 
-    t->codec = card->codec;
-
     err = socket_accept(card->fd);
     if (err < 0) {
         pa_log_error("Deferred setup failed on fd %d: %s", card->fd, pa_cstrerror(-err));

commit 556cdfa1902d9b2b4022f5a6d51813bdf567b17d
Author: Raman Shyshniou <rommer at ibuffed.com>
Date:   Tue Mar 20 16:26:20 2018 +0300

    optimize set_state_in_io_thread() callbacks
    
    Source and sink are passed in arguments to set_state_in_io_thread()
    callbacks. There is optimal to access them directly.

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 4568a19c..51d2d465 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1291,7 +1291,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
     switch (new_state) {
 
         case PA_SINK_SUSPENDED: {
-            pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
+            pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
 
             suspend(u);
 
@@ -1302,7 +1302,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
         case PA_SINK_RUNNING: {
             int r;
 
-            if (u->sink->thread_info.state == PA_SINK_INIT) {
+            if (s->thread_info.state == PA_SINK_INIT) {
                 if (build_pollfd(u) < 0)
                     /* FIXME: This will cause an assertion failure, because
                      * with the current design pa_sink_put() is not allowed
@@ -1312,7 +1312,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
                     return -PA_ERR_IO;
             }
 
-            if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
+            if (s->thread_info.state == PA_SINK_SUSPENDED) {
                 if ((r = unsuspend(u)) < 0)
                     return r;
             }
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 8014bc03..54a32efb 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1146,7 +1146,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
     switch (new_state) {
 
         case PA_SOURCE_SUSPENDED: {
-            pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
+            pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state));
 
             suspend(u);
 
@@ -1157,7 +1157,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
         case PA_SOURCE_RUNNING: {
             int r;
 
-            if (u->source->thread_info.state == PA_SOURCE_INIT) {
+            if (s->thread_info.state == PA_SOURCE_INIT) {
                 if (build_pollfd(u) < 0)
                     /* FIXME: This will cause an assertion failure, because
                      * with the current design pa_source_put() is not allowed
@@ -1167,7 +1167,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
                     return -PA_ERR_IO;
             }
 
-            if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
+            if (s->thread_info.state == PA_SOURCE_SUSPENDED) {
                 if ((r = unsuspend(u)) < 0)
                     return r;
             }
diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
index 79d75c11..87592834 100644
--- a/src/modules/bluetooth/module-bluez4-device.c
+++ b/src/modules/bluetooth/module-bluez4-device.c
@@ -423,7 +423,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
         case PA_SINK_SUSPENDED:
             /* Ignore if transition is PA_SINK_INIT->PA_SINK_SUSPENDED */
-            if (!PA_SINK_IS_OPENED(u->sink->thread_info.state))
+            if (!PA_SINK_IS_OPENED(s->thread_info.state))
                 break;
 
             /* Stop the device if the source is suspended as well */
@@ -437,7 +437,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
         case PA_SINK_IDLE:
         case PA_SINK_RUNNING:
-            if (u->sink->thread_info.state != PA_SINK_SUSPENDED)
+            if (s->thread_info.state != PA_SINK_SUSPENDED)
                 break;
 
             /* Resume the device if the source was suspended as well */
@@ -497,7 +497,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
 
         case PA_SOURCE_SUSPENDED:
             /* Ignore if transition is PA_SOURCE_INIT->PA_SOURCE_SUSPENDED */
-            if (!PA_SOURCE_IS_OPENED(u->source->thread_info.state))
+            if (!PA_SOURCE_IS_OPENED(s->thread_info.state))
                 break;
 
             /* Stop the device if the sink is suspended as well */
@@ -510,7 +510,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
 
         case PA_SOURCE_IDLE:
         case PA_SOURCE_RUNNING:
-            if (u->source->thread_info.state != PA_SOURCE_SUSPENDED)
+            if (s->thread_info.state != PA_SOURCE_SUSPENDED)
                 break;
 
             /* Resume the device if the sink was suspended as well */
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 2a36adfd..351ad127 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -980,7 +980,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
 
         case PA_SOURCE_SUSPENDED:
             /* Ignore if transition is PA_SOURCE_INIT->PA_SOURCE_SUSPENDED */
-            if (!PA_SOURCE_IS_OPENED(u->source->thread_info.state))
+            if (!PA_SOURCE_IS_OPENED(s->thread_info.state))
                 break;
 
             /* Stop the device if the sink is suspended as well */
@@ -994,7 +994,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
 
         case PA_SOURCE_IDLE:
         case PA_SOURCE_RUNNING:
-            if (u->source->thread_info.state != PA_SOURCE_SUSPENDED)
+            if (s->thread_info.state != PA_SOURCE_SUSPENDED)
                 break;
 
             /* Resume the device if the sink was suspended as well */
@@ -1157,7 +1157,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
         case PA_SINK_SUSPENDED:
             /* Ignore if transition is PA_SINK_INIT->PA_SINK_SUSPENDED */
-            if (!PA_SINK_IS_OPENED(u->sink->thread_info.state))
+            if (!PA_SINK_IS_OPENED(s->thread_info.state))
                 break;
 
             /* Stop the device if the source is suspended as well */
@@ -1171,7 +1171,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
         case PA_SINK_IDLE:
         case PA_SINK_RUNNING:
-            if (u->sink->thread_info.state != PA_SINK_SUSPENDED)
+            if (s->thread_info.state != PA_SINK_SUSPENDED)
                 break;
 
             /* Resume the device if the source was suspended as well */
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index c8065d82..0f4af441 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -522,7 +522,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
     /* When set to running or idle for the first time, request a rewind
      * of the master sink to make sure we are heard immediately */
-    if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) {
+    if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
     }
diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c
index 43375999..681f44d2 100644
--- a/src/modules/module-equalizer-sink.c
+++ b/src/modules/module-equalizer-sink.c
@@ -296,7 +296,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
     /* When set to running or idle for the first time, request a rewind
      * of the master sink to make sure we are heard immediately */
-    if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) {
+    if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
     }
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index 3f6b8116..5ff04516 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -183,7 +183,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
     switch (new_state) {
 
         case PA_SINK_SUSPENDED:
-            pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
+            pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
 
             pa_smoother_pause(u->smoother, pa_rtclock_now());
             break;
@@ -191,7 +191,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
         case PA_SINK_IDLE:
         case PA_SINK_RUNNING:
 
-            if (u->sink->thread_info.state == PA_SINK_SUSPENDED)
+            if (s->thread_info.state == PA_SINK_SUSPENDED)
                 pa_smoother_resume(u->smoother, pa_rtclock_now(), true);
 
             break;
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index c365b310..a09d8b24 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -403,7 +403,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
     /* When set to running or idle for the first time, request a rewind
      * of the master sink to make sure we are heard immediately */
-    if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) {
+    if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
     }
diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index baaf0647..6cbe588d 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -109,7 +109,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
     pa_assert(s);
     pa_assert_se(u = s->userdata);
 
-    if (u->sink->thread_info.state == PA_SINK_SUSPENDED || u->sink->thread_info.state == PA_SINK_INIT) {
+    if (s->thread_info.state == PA_SINK_SUSPENDED || s->thread_info.state == PA_SINK_INIT) {
         if (PA_SINK_IS_OPENED(new_state))
             u->timestamp = pa_rtclock_now();
     }
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index fc01206b..765e7519 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -142,10 +142,10 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
     pa_assert(s);
     pa_assert_se(u = s->userdata);
 
-    if (u->sink->thread_info.state == PA_SINK_SUSPENDED || u->sink->thread_info.state == PA_SINK_INIT) {
+    if (s->thread_info.state == PA_SINK_SUSPENDED || s->thread_info.state == PA_SINK_INIT) {
         if (PA_SINK_IS_OPENED(new_state))
             u->timestamp = pa_rtclock_now();
-    } else if (u->sink->thread_info.state == PA_SINK_RUNNING || u->sink->thread_info.state == PA_SINK_IDLE) {
+    } else if (PA_SINK_IS_OPENED(s->thread_info.state)) {
         if (new_state == PA_SINK_SUSPENDED) {
             /* Clear potential FIFO error flag */
             u->fifo_error = false;
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index f53b6b15..503fcf5c 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -123,7 +123,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
     /* When set to running or idle for the first time, request a rewind
      * of the master sink to make sure we are heard immediately */
-    if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) {
+    if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
     }
diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
index ef42b3d9..240ed855 100644
--- a/src/modules/module-solaris.c
+++ b/src/modules/module-solaris.c
@@ -411,7 +411,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
         case PA_SINK_SUSPENDED:
 
-            pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
+            pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
 
             pa_smoother_pause(u->smoother, pa_rtclock_now());
 
@@ -424,16 +424,16 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
         case PA_SINK_IDLE:
         case PA_SINK_RUNNING:
 
-            if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
+            if (s->thread_info.state == PA_SINK_SUSPENDED) {
                 pa_smoother_resume(u->smoother, pa_rtclock_now(), true);
 
                 if (!u->source || u->source_suspended) {
                     bool mute;
                     if (unsuspend(u) < 0)
                         return -1;
-                    u->sink->get_volume(u->sink);
-                    if (u->sink->get_mute(u->sink, &mute) >= 0)
-                        pa_sink_set_mute(u->sink, mute, false);
+                    s->get_volume(s);
+                    if (s->get_mute(s, &mute) >= 0)
+                        pa_sink_set_mute(s, mute, false);
                 }
                 u->sink_suspended = false;
             }
@@ -477,7 +477,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
 
         case PA_SOURCE_SUSPENDED:
 
-            pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
+            pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state));
 
             if (!u->sink || u->sink_suspended)
                 suspend(u);
@@ -488,11 +488,11 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
         case PA_SOURCE_IDLE:
         case PA_SOURCE_RUNNING:
 
-            if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
+            if (s->thread_info.state == PA_SOURCE_SUSPENDED) {
                 if (!u->sink || u->sink_suspended) {
                     if (unsuspend(u) < 0)
                         return -1;
-                    u->source->get_volume(u->source);
+                    s->get_volume(s);
                 }
                 u->source_suspended = false;
             }
diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index e1345523..3a818225 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -135,7 +135,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
     /* When set to running or idle for the first time, request a rewind
      * of the master sink to make sure we are heard immediately */
-    if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) {
+    if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
     }
diff --git a/src/modules/module-virtual-surround-sink.c b/src/modules/module-virtual-surround-sink.c
index 2c3d54ba..f14f137f 100644
--- a/src/modules/module-virtual-surround-sink.c
+++ b/src/modules/module-virtual-surround-sink.c
@@ -163,7 +163,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
     /* When set to running or idle for the first time, request a rewind
      * of the master sink to make sure we are heard immediately */
-    if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) {
+    if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
     }
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index 42a6e3b0..6a70f9af 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -682,7 +682,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
     switch (new_state) {
 
         case PA_SINK_SUSPENDED:
-            pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
+            pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
 
             if (!u->source || u->source_suspended)
                 suspend(u);
@@ -695,12 +695,12 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
         case PA_SINK_IDLE:
         case PA_SINK_RUNNING:
 
-            if (u->sink->thread_info.state == PA_SINK_INIT) {
+            if (s->thread_info.state == PA_SINK_INIT) {
                 do_trigger = true;
                 quick = u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state);
             }
 
-            if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
+            if (s->thread_info.state == PA_SINK_SUSPENDED) {
 
                 if (!u->source || u->source_suspended) {
                     if (unsuspend(u) < 0)
@@ -770,7 +770,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
     switch (new_state) {
 
         case PA_SOURCE_SUSPENDED:
-            pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
+            pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state));
 
             if (!u->sink || u->sink_suspended)
                 suspend(u);
@@ -783,12 +783,12 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
         case PA_SOURCE_IDLE:
         case PA_SOURCE_RUNNING:
 
-            if (u->source->thread_info.state == PA_SOURCE_INIT) {
+            if (s->thread_info.state == PA_SOURCE_INIT) {
                 do_trigger = true;
                 quick = u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state);
             }
 
-            if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
+            if (s->thread_info.state == PA_SOURCE_SUSPENDED) {
 
                 if (!u->sink || u->sink_suspended) {
                     if (unsuspend(u) < 0)
diff --git a/src/modules/raop/raop-sink.c b/src/modules/raop/raop-sink.c
index 818cdfe0..ec6f8262 100644
--- a/src/modules/raop/raop-sink.c
+++ b/src/modules/raop/raop-sink.c
@@ -236,7 +236,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
         case PA_SINK_SUSPENDED:
             pa_log_debug("RAOP: SUSPENDED");
 
-            pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
+            pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
 
             /* Issue a TEARDOWN if we are still connected */
             if (pa_raop_client_is_alive(u->raop)) {
@@ -249,7 +249,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
             pa_log_debug("RAOP: IDLE");
 
             /* Issue a FLUSH if we're comming from running state */
-            if (u->sink->thread_info.state == PA_SINK_RUNNING) {
+            if (s->thread_info.state == PA_SINK_RUNNING) {
                 pa_rtpoll_set_timer_disabled(u->rtpoll);
                 pa_raop_client_flush(u->raop);
             }

commit de705a0eeaa27a8ac1abdc2625e639340323595a
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Tue Mar 6 15:09:06 2018 +0200

    set exit_idle_time to 0 when we detect a session
    
    As the comments explain, this fixes relogin problems on some systems
    that remove our sockets on logout without terminating the daemon.

diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index f0550f3b..f49fa9b0 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -292,9 +292,18 @@ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
     <option>
       <p><opt>exit-idle-time=</opt> Terminate the daemon after the
       last client quit and this time in seconds passed. Use a negative value to
-      disable this feature. Defaults to 20. The
-      <opt>--exit-idle-time</opt> command line option takes
-      precedence.</p>
+      disable this feature. Defaults to 20. The <opt>--exit-idle-time</opt>
+      command line option takes precedence.</p>
+
+      <p>When PulseAudio runs in the per-user mode and detects a login
+      session, then any positive value will be reset to 0 so that PulseAudio
+      will terminate immediately on logout. A positive value therefore has
+      effect only in environments where there's no support for login session
+      tracking. A negative value can still be used to disable any automatic
+      exit.</p>
+
+      <p>When PulseAudio runs in the system mode, automatic exit is always
+      disabled, so this option does nothing.</p>
     </option>
 
     <option>
diff --git a/man/pulseaudio.1.xml.in b/man/pulseaudio.1.xml.in
index f732b8ae..824eddb4 100644
--- a/man/pulseaudio.1.xml.in
+++ b/man/pulseaudio.1.xml.in
@@ -189,8 +189,21 @@ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
     <option>
       <p><opt>--exit-idle-time</opt><arg>=SECS</arg></p>
 
-      <optdesc><p>Terminate the daemon when idle and the specified
-      number of seconds passed.</p></optdesc>
+      <optdesc>
+        <p>Terminate the daemon after the last client quit and this time in
+        seconds passed. Use a negative value to disable this feature. Defaults
+        to 20.</p>
+
+        <p>When PulseAudio runs in the per-user mode and detects a login
+        session, then any positive value will be reset to 0 so that PulseAudio
+        will terminate immediately on logout. A positive value therefore has
+        effect only in environments where there's no support for login session
+        tracking. A negative value can still be used to disable any automatic
+        exit.</p>
+
+        <p>When PulseAudio runs in the system mode, automatic exit is always
+        disabled, so this option does nothing.</p>
+      </optdesc>
     </option>
 
     <option>
diff --git a/src/modules/module-console-kit.c b/src/modules/module-console-kit.c
index c7938849..c8fe2ed2 100644
--- a/src/modules/module-console-kit.c
+++ b/src/modules/module-console-kit.c
@@ -118,6 +118,19 @@ static void add_session(struct userdata *u, const char *id) {
 
     pa_log_debug("Added new session %s", id);
 
+    /* Positive exit_idle_time is only useful when we have no session tracking
+     * capability, so we can set it to 0 now that we have detected a session.
+     * The benefit of setting exit_idle_time to 0 is that pulseaudio will exit
+     * immediately when the session ends. That in turn is useful, because some
+     * systems (those that use pam_systemd but don't use systemd for managing
+     * pulseaudio) clean $XDG_RUNTIME_DIR on logout, but fail to terminate all
+     * services that depend on the files in $XDG_RUNTIME_DIR. The directory
+     * contains our sockets, and if the sockets are removed without terminating
+     * pulseaudio, a quick relogin will likely cause trouble, because a new
+     * instance will be spawned while the old instance is still running. */
+    if (u->core->exit_idle_time > 0)
+        pa_core_set_exit_idle_time(u->core, 0);
+
 fail:
 
     if (m)
diff --git a/src/modules/module-systemd-login.c b/src/modules/module-systemd-login.c
index 87981592..51401575 100644
--- a/src/modules/module-systemd-login.c
+++ b/src/modules/module-systemd-login.c
@@ -84,6 +84,20 @@ static int add_session(struct userdata *u, const char *id) {
     pa_hashmap_put(u->sessions, session->id, session);
 
     pa_log_debug("Added new session %s", id);
+
+    /* Positive exit_idle_time is only useful when we have no session tracking
+     * capability, so we can set it to 0 now that we have detected a session.
+     * The benefit of setting exit_idle_time to 0 is that pulseaudio will exit
+     * immediately when the session ends. That in turn is useful, because some
+     * systems (those that use pam_systemd but don't use systemd for managing
+     * pulseaudio) clean $XDG_RUNTIME_DIR on logout, but fail to terminate all
+     * services that depend on the files in $XDG_RUNTIME_DIR. The directory
+     * contains our sockets, and if the sockets are removed without terminating
+     * pulseaudio, a quick relogin will likely cause trouble, because a new
+     * instance will be spawned while the old instance is still running. */
+    if (u->core->exit_idle_time > 0)
+        pa_core_set_exit_idle_time(u->core, 0);
+
     return 0;
 }
 
diff --git a/src/modules/x11/module-x11-xsmp.c b/src/modules/x11/module-x11-xsmp.c
index 0238e516..6f801237 100644
--- a/src/modules/x11/module-x11-xsmp.c
+++ b/src/modules/x11/module-x11-xsmp.c
@@ -206,6 +206,19 @@ int pa__init(pa_module*m) {
     if (!u->client)
         goto fail;
 
+    /* Positive exit_idle_time is only useful when we have no session tracking
+     * capability, so we can set it to 0 now that we have detected a session.
+     * The benefit of setting exit_idle_time to 0 is that pulseaudio will exit
+     * immediately when the session ends. That in turn is useful, because some
+     * systems (those that use pam_systemd but don't use systemd for managing
+     * pulseaudio) clean $XDG_RUNTIME_DIR on logout, but fail to terminate all
+     * services that depend on the files in $XDG_RUNTIME_DIR. The directory
+     * contains our sockets, and if the sockets are removed without terminating
+     * pulseaudio, a quick relogin will likely cause trouble, because a new
+     * instance will be spawned while the old instance is still running. */
+    if (u->core->exit_idle_time > 0)
+        pa_core_set_exit_idle_time(u->core, 0);
+
     pa_modargs_free(ma);
 
     return 0;
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 79abbc04..da42a13e 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -426,6 +426,16 @@ void pa_core_update_default_source(pa_core *core) {
     pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED], core->default_source);
 }
 
+void pa_core_set_exit_idle_time(pa_core *core, int time) {
+    pa_assert(core);
+
+    if (time == core->exit_idle_time)
+        return;
+
+    pa_log_info("exit_idle_time: %i -> %i", core->exit_idle_time, time);
+    core->exit_idle_time = time;
+}
+
 static void exit_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
     pa_core *c = userdata;
     pa_assert(c->exit_event == e);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 213964ce..38622f61 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -258,6 +258,8 @@ void pa_core_set_configured_default_source(pa_core *core, const char *source);
 void pa_core_update_default_sink(pa_core *core);
 void pa_core_update_default_source(pa_core *core);
 
+void pa_core_set_exit_idle_time(pa_core *core, int time);
+
 /* Check whether no one is connected to this core */
 void pa_core_check_idle(pa_core *c);
 

commit 83675b3745c64bd738400eae44eb4daa195ed88a
Author: Bert Hekman <demontpx at gmail.com>
Date:   Tue Feb 13 20:06:12 2018 +0100

    alsa-mixer: add support for SteelSeries Arctis 5 and renamed Arctis 7 files appropriately

diff --git a/src/Makefile.am b/src/Makefile.am
index f4464d25..6fbd7050 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1320,7 +1320,8 @@ dist_alsaprofilesets_DATA = \
 		modules/alsa/mixer/profile-sets/native-instruments-korecontroller.conf \
 		modules/alsa/mixer/profile-sets/kinect-audio.conf \
 		modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf \
-		modules/alsa/mixer/profile-sets/steelseries-arctis-usb-audio.conf \
+		modules/alsa/mixer/profile-sets/steelseries-arctis-5-usb-audio.conf \
+		modules/alsa/mixer/profile-sets/steelseries-arctis-7-usb-audio.conf \
 		modules/alsa/mixer/profile-sets/dell-dock-tb16-usb-audio.conf
 
 if HAVE_UDEV
@@ -1364,9 +1365,11 @@ dist_alsapaths_DATA = \
 		modules/alsa/mixer/paths/hdmi-output-5.conf \
 		modules/alsa/mixer/paths/hdmi-output-6.conf \
 		modules/alsa/mixer/paths/hdmi-output-7.conf \
-		modules/alsa/mixer/paths/steelseries-arctis-input.conf \
-		modules/alsa/mixer/paths/steelseries-arctis-output-mono.conf \
-		modules/alsa/mixer/paths/steelseries-arctis-output-stereo.conf
+		modules/alsa/mixer/paths/steelseries-arctis-5-output-chat.conf \
+		modules/alsa/mixer/paths/steelseries-arctis-5-output-game.conf \
+		modules/alsa/mixer/paths/steelseries-arctis-7-input.conf \
+		modules/alsa/mixer/paths/steelseries-arctis-7-output-mono.conf \
+		modules/alsa/mixer/paths/steelseries-arctis-7-output-stereo.conf
 
 endif
 
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index a524d6d6..a07c4351 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -2545,6 +2545,8 @@ static int path_verify(pa_alsa_path *p) {
         { "iec958-passthrough-output",  N_("Digital Passthrough (S/PDIF)") },
         { "multichannel-input",         N_("Multichannel Input") },
         { "multichannel-output",        N_("Multichannel Output") },
+        { "steelseries-arctis-5-output-game", N_("Game Output") },
+        { "steelseries-arctis-5-output-chat", N_("Chat Output") },
     };
 
     pa_alsa_element *e;
diff --git a/src/modules/alsa/mixer/paths/steelseries-arctis-5-output-chat.conf b/src/modules/alsa/mixer/paths/steelseries-arctis-5-output-chat.conf
new file mode 100644
index 00000000..5842bfe8
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/steelseries-arctis-5-output-chat.conf
@@ -0,0 +1,27 @@
+# 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, see <http://www.gnu.org/licenses/>.
+
+; Steelseries Arctis 5 USB headset stereo chat path. The headset has two
+; output devices. The first one is meant for voice audio, and the second
+; one meant for everything else. The purpose of this unusual design is to
+; provide separate volume controls for voice and other audio, which can be
+; useful in gaming.
+
+[General]
+priority = 50
+
+[Element Com Speaker]
+switch = mute
+volume = merge
diff --git a/src/modules/alsa/mixer/paths/steelseries-arctis-5-output-game.conf b/src/modules/alsa/mixer/paths/steelseries-arctis-5-output-game.conf
new file mode 100644
index 00000000..b758a6fe
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/steelseries-arctis-5-output-game.conf
@@ -0,0 +1,27 @@
+# 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, see <http://www.gnu.org/licenses/>.
+
+; Steelseries Arctis 5 USB headset stereo game path. The headset has two
+; output devices. The first one is meant for voice audio, and the second
+; one meant for everything else. The purpose of this unusual design is to
+; provide separate volume controls for voice and other audio, which can be
+; useful in gaming.
+
+[General]
+priority = 99
+
+[Element PCM]
+switch = mute
+volume = merge
diff --git a/src/modules/alsa/mixer/paths/steelseries-arctis-input.conf b/src/modules/alsa/mixer/paths/steelseries-arctis-7-input.conf
similarity index 100%
rename from src/modules/alsa/mixer/paths/steelseries-arctis-input.conf
rename to src/modules/alsa/mixer/paths/steelseries-arctis-7-input.conf
diff --git a/src/modules/alsa/mixer/paths/steelseries-arctis-output-mono.conf b/src/modules/alsa/mixer/paths/steelseries-arctis-7-output-mono.conf
similarity index 100%
rename from src/modules/alsa/mixer/paths/steelseries-arctis-output-mono.conf
rename to src/modules/alsa/mixer/paths/steelseries-arctis-7-output-mono.conf
diff --git a/src/modules/alsa/mixer/paths/steelseries-arctis-output-stereo.conf b/src/modules/alsa/mixer/paths/steelseries-arctis-7-output-stereo.conf
similarity index 100%
rename from src/modules/alsa/mixer/paths/steelseries-arctis-output-stereo.conf
rename to src/modules/alsa/mixer/paths/steelseries-arctis-7-output-stereo.conf
diff --git a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
index 4dacb62b..ceb61d9e 100644
--- a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
+++ b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
@@ -105,7 +105,8 @@ ATTRS{idVendor}=="0763", ATTRS{idProduct}=="2012", ENV{PULSE_PROFILE_SET}="maudi
 ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02bb", ENV{PULSE_PROFILE_SET}="kinect-audio.conf"
 ATTRS{idVendor}=="041e", ATTRS{idProduct}=="322c", ENV{PULSE_PROFILE_SET}="sb-omni-surround-5.1.conf"
 ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4014", ENV{PULSE_PROFILE_SET}="dell-dock-tb16-usb-audio.conf"
-ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1260", ENV{PULSE_PROFILE_SET}="steelseries-arctis-usb-audio.conf"
+ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1250", ENV{PULSE_PROFILE_SET}="steelseries-arctis-5-usb-audio.conf"
+ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1260", ENV{PULSE_PROFILE_SET}="steelseries-arctis-7-usb-audio.conf"
 ATTRS{idVendor}=="147a", ATTRS{idProduct}=="e055", ENV{PULSE_PROFILE_SET}="cmedia-high-speed-true-hdaudio.conf"
 
 LABEL="pulseaudio_end"
diff --git a/src/modules/alsa/mixer/profile-sets/steelseries-arctis-5-usb-audio.conf b/src/modules/alsa/mixer/profile-sets/steelseries-arctis-5-usb-audio.conf
new file mode 100644
index 00000000..fe353c38
--- /dev/null
+++ b/src/modules/alsa/mixer/profile-sets/steelseries-arctis-5-usb-audio.conf
@@ -0,0 +1,22 @@
+[General]
+auto-profiles = yes
+
+[Mapping analog-chat]
+description = Chat
+device-strings = hw:%f,0,0
+channel-map = left,right
+paths-input = analog-input-mic
+paths-output = steelseries-arctis-5-output-chat
+
+[Mapping analog-game]
+description = Game
+device-strings = hw:%f,1,0
+channel-map = left,right
+paths-output = steelseries-arctis-5-output-game
+direction = output
+
+[Profile output:analog-chat+output:analog-game+input:analog-chat]
+output-mappings = analog-chat analog-game
+input-mappings = analog-chat
+priority = 5100
+skip-probe = yes
diff --git a/src/modules/alsa/mixer/profile-sets/steelseries-arctis-usb-audio.conf b/src/modules/alsa/mixer/profile-sets/steelseries-arctis-7-usb-audio.conf
similarity index 91%
rename from src/modules/alsa/mixer/profile-sets/steelseries-arctis-usb-audio.conf
rename to src/modules/alsa/mixer/profile-sets/steelseries-arctis-7-usb-audio.conf
index d3563a16..8c061e1a 100644
--- a/src/modules/alsa/mixer/profile-sets/steelseries-arctis-usb-audio.conf
+++ b/src/modules/alsa/mixer/profile-sets/steelseries-arctis-7-usb-audio.conf
@@ -27,13 +27,13 @@ auto-profiles = yes
 [Mapping analog-mono]
 device-strings = hw:%f,0,0
 channel-map = mono
-paths-output = steelseries-arctis-output-mono
-paths-input = steelseries-arctis-input
+paths-output = steelseries-arctis-7-output-mono
+paths-input = steelseries-arctis-7-input
 
 [Mapping analog-stereo]
 device-strings = hw:%f,1,0
 channel-map = left,right
-paths-output = steelseries-arctis-output-stereo
+paths-output = steelseries-arctis-7-output-stereo
 direction = output
 
 [Profile output:analog-mono+output:analog-stereo+input:analog-mono]

commit 0d50e787f86b385bf33aeb53b16ca40543f1db63
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Tue Feb 20 11:55:14 2018 +0200

    alsa-card: improve the profile availability logic
    
    When a new card shows up (during pulseaudio startup or hotplugged),
    pulseaudio needs to pick the initial profile for the card. Unavailable
    profiles shouldn't be picked, but module-alsa-card sometimes marked
    unavailable profiles as available, causing bad initial profile choices.
    
    This patch changes module-alsa-card so that it marks all profiles
    unavailable whose all output ports or all input ports are unavailable.
    Previously only those profiles were marked as unavailable whose all
    ports were unavailable. For example, if a profile contains one sink and
    one source, and the sink is unavailable and the source is available,
    previously such profile was marked as available, but now it's marked as
    unavailable.
    
    BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=102902

diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 1f78f18d..ab81ef9c 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -442,29 +442,54 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
         }
     }
 
-    /* Update profile availabilities. The logic could be improved; for now we
-     * only set obviously unavailable profiles (those that contain only
-     * unavailable ports) to PA_AVAILABLE_NO and all others to
-     * PA_AVAILABLE_UNKNOWN. */
+    /* Update profile availabilities. Ideally we would mark all profiles
+     * unavailable that contain unavailable devices. We can't currently do that
+     * in all cases, because if there are multiple sinks in a profile, and the
+     * profile contains a mix of available and unavailable ports, we don't know
+     * how the ports are distributed between the different sinks. It's possible
+     * that some sinks contain only unavailable ports, in which case we should
+     * mark the profile as unavailable, but it's also possible that all sinks
+     * contain at least one available port, in which case we should mark the
+     * profile as available. Until the data structures are improved so that we
+     * can distinguish between these two cases, we mark the problematic cases
+     * as available (well, "unknown" to be precise, but there's little
+     * practical difference).
+     *
+     * When all output ports are unavailable, we know that all sinks are
+     * unavailable, and therefore the profile is marked unavailable as well.
+     * The same applies to input ports as well, of course.
+     *
+     * If there are no output ports at all, but the profile contains at least
+     * one sink, then the output is considered to be available. */
     PA_HASHMAP_FOREACH(profile, u->card->profiles, state) {
         pa_device_port *port;
         void *state2;
-        pa_available_t available = PA_AVAILABLE_NO;
-
-        /* Don't touch the "off" profile. */
-        if (profile->n_sources == 0 && profile->n_sinks == 0)
-            continue;
+        bool has_input_port = false;
+        bool has_output_port = false;
+        bool found_available_input_port = false;
+        bool found_available_output_port = false;
+        pa_available_t available = PA_AVAILABLE_UNKNOWN;
 
         PA_HASHMAP_FOREACH(port, u->card->ports, state2) {
             if (!pa_hashmap_get(port->profiles, profile->name))
                 continue;
 
-            if (port->available != PA_AVAILABLE_NO) {
-                available = PA_AVAILABLE_UNKNOWN;
-                break;
+            if (port->direction == PA_DIRECTION_INPUT) {
+                has_input_port = true;
+
+                if (port->available != PA_AVAILABLE_NO)
+                    found_available_input_port = true;
+            } else {
+                has_output_port = true;
+
+                if (port->available != PA_AVAILABLE_NO)
+                    found_available_output_port = true;
             }
         }
 
+        if ((has_input_port && !found_available_input_port) || (has_output_port && !found_available_output_port))
+            available = PA_AVAILABLE_NO;
+
         pa_card_profile_set_available(profile, available);
     }
 

commit 4895e52da95c9d0ae0719fa2b2230cffe433e0cd
Author: Raman Shyshniou <rommer at ibuffed.com>
Date:   Tue Feb 20 21:32:57 2018 +0100

    loopback: use source sample spec and channel map by default
    
    Currently the loopback module uses sample spec and channel map of the
    sink by default. It leads to double resample if source and sink sample
    specs are different and no rate/format specified in arguments. This
    patch causes the source sample spec and channel map to be used by
    default.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 19005e8e..31702e32 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -1300,15 +1300,15 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
-    if (sink) {
-        ss = sink->sample_spec;
-        map = sink->channel_map;
+    if (source) {
+        ss = source->sample_spec;
+        map = source->channel_map;
         format_set = true;
         rate_set = true;
         channels_set = true;
-    } else if (source) {
-        ss = source->sample_spec;
-        map = source->channel_map;
+    } else if (sink) {
+        ss = sink->sample_spec;
+        map = sink->channel_map;
         format_set = true;
         rate_set = true;
         channels_set = true;
@@ -1389,6 +1389,70 @@ int pa__init(pa_module *m) {
 
     u->real_adjust_time = u->adjust_time;
 
+    pa_source_output_new_data_init(&source_output_data);
+    source_output_data.driver = __FILE__;
+    source_output_data.module = m;
+    if (source)
+        pa_source_output_new_data_set_source(&source_output_data, source, false, true);
+
+    if (pa_modargs_get_proplist(ma, "source_output_properties", source_output_data.proplist, PA_UPDATE_REPLACE) < 0) {
+        pa_log("Failed to parse the source_output_properties value.");
+        pa_source_output_new_data_done(&source_output_data);
+        goto fail;
+    }
+
+    if (!pa_proplist_contains(source_output_data.proplist, PA_PROP_MEDIA_ROLE))
+        pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
+
+    pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
+    pa_source_output_new_data_set_channel_map(&source_output_data, &map);
+    source_output_data.flags = PA_SOURCE_OUTPUT_START_CORKED;
+
+    if (!remix)
+        source_output_data.flags |= PA_SOURCE_OUTPUT_NO_REMIX;
+
+    if (!format_set)
+        source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_FORMAT;
+
+    if (!rate_set)
+        source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_RATE;
+
+    if (!channels_set)
+        source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_CHANNELS;
+
+    source_dont_move = false;
+    if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) {
+        pa_log("source_dont_move= expects a boolean argument.");
+        goto fail;
+    }
+
+    if (source_dont_move)
+        source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;
+
+    pa_source_output_new(&u->source_output, m->core, &source_output_data);
+    pa_source_output_new_data_done(&source_output_data);
+
+    if (!u->source_output)
+        goto fail;
+
+    u->source_output->parent.process_msg = source_output_process_msg_cb;
+    u->source_output->push = source_output_push_cb;
+    u->source_output->process_rewind = source_output_process_rewind_cb;
+    u->source_output->kill = source_output_kill_cb;
+    u->source_output->attach = source_output_attach_cb;
+    u->source_output->detach = source_output_detach_cb;
+    u->source_output->may_move_to = source_output_may_move_to_cb;
+    u->source_output->moving = source_output_moving_cb;
+    u->source_output->suspend = source_output_suspend_cb;
+    u->source_output->update_source_latency_range = update_source_latency_range_cb;
+    u->source_output->update_source_fixed_latency = update_source_latency_range_cb;
+    u->source_output->userdata = u;
+
+    /* If format, rate or channels were originally unset, they are set now
+     * after the pa_source_output_new() call. */
+    ss = u->source_output->sample_spec;
+    map = u->source_output->channel_map;
+
     pa_sink_input_new_data_init(&sink_input_data);
     sink_input_data.driver = __FILE__;
     sink_input_data.module = m;
@@ -1412,15 +1476,6 @@ int pa__init(pa_module *m) {
     if (!remix)
         sink_input_data.flags |= PA_SINK_INPUT_NO_REMIX;
 
-    if (!format_set)
-        sink_input_data.flags |= PA_SINK_INPUT_FIX_FORMAT;
-
-    if (!rate_set)
-        sink_input_data.flags |= PA_SINK_INPUT_FIX_RATE;
-
-    if (!channels_set)
-        sink_input_data.flags |= PA_SINK_INPUT_FIX_CHANNELS;
-
     sink_dont_move = false;
     if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) {
         pa_log("sink_dont_move= expects a boolean argument.");
@@ -1436,11 +1491,6 @@ int pa__init(pa_module *m) {
     if (!u->sink_input)
         goto fail;
 
-    /* If format, rate or channels were originally unset, they are set now
-     * after the pa_sink_input_new() call. */
-    ss = u->sink_input->sample_spec;
-    map = u->sink_input->channel_map;
-
     u->sink_input->parent.process_msg = sink_input_process_msg_cb;
     u->sink_input->pop = sink_input_pop_cb;
     u->sink_input->process_rewind = sink_input_process_rewind_cb;
@@ -1457,56 +1507,6 @@ int pa__init(pa_module *m) {
     u->sink_input->update_sink_fixed_latency = update_sink_latency_range_cb;
     u->sink_input->userdata = u;
 
-    pa_source_output_new_data_init(&source_output_data);
-    source_output_data.driver = __FILE__;
-    source_output_data.module = m;
-    if (source)
-        pa_source_output_new_data_set_source(&source_output_data, source, false, true);
-
-    if (pa_modargs_get_proplist(ma, "source_output_properties", source_output_data.proplist, PA_UPDATE_REPLACE) < 0) {
-        pa_log("Failed to parse the source_output_properties value.");
-        pa_source_output_new_data_done(&source_output_data);
-        goto fail;
-    }
-
-    if (!pa_proplist_contains(source_output_data.proplist, PA_PROP_MEDIA_ROLE))
-        pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
-
-    pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
-    pa_source_output_new_data_set_channel_map(&source_output_data, &map);
-    source_output_data.flags = PA_SOURCE_OUTPUT_START_CORKED;
-
-    if (!remix)
-        source_output_data.flags |= PA_SOURCE_OUTPUT_NO_REMIX;
-
-    source_dont_move = false;
-    if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) {
-        pa_log("source_dont_move= expects a boolean argument.");
-        goto fail;
-    }
-
-    if (source_dont_move)
-        source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;
-
-    pa_source_output_new(&u->source_output, m->core, &source_output_data);
-    pa_source_output_new_data_done(&source_output_data);
-
-    if (!u->source_output)
-        goto fail;
-
-    u->source_output->parent.process_msg = source_output_process_msg_cb;
-    u->source_output->push = source_output_push_cb;
-    u->source_output->process_rewind = source_output_process_rewind_cb;
-    u->source_output->kill = source_output_kill_cb;
-    u->source_output->attach = source_output_attach_cb;
-    u->source_output->detach = source_output_detach_cb;
-    u->source_output->may_move_to = source_output_may_move_to_cb;
-    u->source_output->moving = source_output_moving_cb;
-    u->source_output->suspend = source_output_suspend_cb;
-    u->source_output->update_source_latency_range = update_source_latency_range_cb;
-    u->source_output->update_source_fixed_latency = update_source_latency_range_cb;
-    u->source_output->userdata = u;
-
     update_latency_boundaries(u, u->source_output->source, u->sink_input->sink);
     set_sink_input_latency(u, u->sink_input->sink);
     set_source_output_latency(u, u->source_output->source);

commit 5864c4f9763c5c2113488fe1153e84fe0028f941
Author: Raman Shyshniou <rommer at ibuffed.com>
Date:   Tue Feb 20 21:29:16 2018 +0100

    loopback: add max_latency_msec argument
    
    Currently loopback module indefinitely increases latency if underruns
    occur. This patch allows to set up the upper limit of latency.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index aecac0ab..19005e8e 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -45,6 +45,7 @@ PA_MODULE_USAGE(
         "sink=<sink to connect to> "
         "adjust_time=<how often to readjust rates in s> "
         "latency_msec=<latency in ms> "
+        "max_latency_msec=<maximum latency in ms> "
         "format=<sample format> "
         "rate=<sample rate> "
         "channels=<number of channels> "
@@ -89,6 +90,7 @@ struct userdata {
 
     /* Values from command line configuration */
     pa_usec_t latency;
+    pa_usec_t max_latency;
     pa_usec_t adjust_time;
 
     /* Latency boundaries and current values */
@@ -158,6 +160,7 @@ static const char* const valid_modargs[] = {
     "sink",
     "adjust_time",
     "latency_msec",
+    "max_latency_msec",
     "format",
     "rate",
     "channels",
@@ -325,10 +328,20 @@ static void adjust_rates(struct userdata *u) {
 
     /* If we are seeing underruns then the latency is too small */
     if (u->underrun_counter > 2) {
-        u->underrun_latency_limit = PA_MAX(u->latency, u->minimum_latency) + 5 * PA_USEC_PER_MSEC;
-        u->underrun_latency_limit = PA_CLIP_SUB((int64_t)u->underrun_latency_limit, u->sink_latency_offset + u->source_latency_offset);
+        pa_usec_t target_latency;
+
+        target_latency = PA_MAX(u->latency, u->minimum_latency) + 5 * PA_USEC_PER_MSEC;
+
+        if (u->max_latency == 0 || target_latency < u->max_latency) {
+            u->underrun_latency_limit = PA_CLIP_SUB((int64_t)target_latency, u->sink_latency_offset + u->source_latency_offset);
+            pa_log_warn("Too many underruns, increasing latency to %0.2f ms", (double)target_latency / PA_USEC_PER_MSEC);
+        } else {
+            u->underrun_latency_limit = PA_CLIP_SUB((int64_t)u->max_latency, u->sink_latency_offset + u->source_latency_offset);
+            pa_log_warn("Too many underruns, configured maximum latency of %0.2f ms is reached", (double)u->max_latency / PA_USEC_PER_MSEC);
+            pa_log_warn("Consider increasing the max_latency_msec");
+        }
+
         update_minimum_latency(u, u->sink_input->sink, false);
-        pa_log_warn("Too many underruns, increasing latency to %0.2f ms", (double)u->minimum_latency / PA_USEC_PER_MSEC);
         u->underrun_counter = 0;
     }
 
@@ -347,7 +360,7 @@ static void adjust_rates(struct userdata *u) {
     }
     u->adjust_time_stamp = now;
 
-    /* Rates and latencies*/
+    /* Rates and latencies */
     old_rate = u->sink_input->sample_spec.rate;
     base_rate = u->source_output->sample_spec.rate;
 
@@ -1252,6 +1265,7 @@ int pa__init(pa_module *m) {
     pa_source_output_new_data source_output_data;
     bool source_dont_move;
     uint32_t latency_msec;
+    uint32_t max_latency_msec;
     pa_sample_spec ss;
     pa_channel_map map;
     bool format_set = false;
@@ -1336,10 +1350,22 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
+    max_latency_msec = 0;
+    if (pa_modargs_get_value_u32(ma, "max_latency_msec", &max_latency_msec) < 0) {
+        pa_log("Invalid maximum latency specification");
+        goto fail;
+    }
+
+    if (max_latency_msec > 0 && max_latency_msec < latency_msec) {
+        pa_log_warn("Configured maximum latency is smaller than latency, using latency instead");
+        max_latency_msec = latency_msec;
+    }
+
     m->userdata = u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
     u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;
+    u->max_latency = (pa_usec_t) max_latency_msec * PA_USEC_PER_MSEC;
     u->output_thread_info.pop_called = false;
     u->output_thread_info.pop_adjust = false;
     u->output_thread_info.push_called = false;

commit 4762aa45d9ea2f5146a135eda6b840bf3964b317
Author: Georg Chini <georg at chini.tk>
Date:   Tue Feb 13 18:17:08 2018 +0100

    core-util: correct error in set_nonblock()
    
    set_nonblock() will always set the file descriptor to non-blocking,
    regardless of the nonblock argument.
    
    This patch fixes the issue by passing the correct argument to the
    fcntl() call. The bug had no impact because there is only one caller
    of pa_make_fd_block() in poll-win32.c

diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 64e9f217..7f627539 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -202,7 +202,7 @@ static void set_nonblock(int fd, bool nonblock) {
         nv = v & ~O_NONBLOCK;
 
     if (v != nv)
-        pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
+        pa_assert_se(fcntl(fd, F_SETFL, nv) >= 0);
 
 #elif defined(OS_IS_WIN32)
     u_long arg;

commit 114cdfbdde88a3454c4f8bde2c419f2b2e0f070d
Author: Arun Raghavan <arun at arunraghavan.net>
Date:   Mon Jul 31 12:37:36 2017 +0100

    build-sys: First pass at a meson-ified build system
    
    This is a working implementation of a build with meson. The server,
    utils, and most modules build with this, and it is possible to run from
    a build tree and play/capture audio on ALSA devices.
    
    There are a number of FIXMEs, of course, and a number of features that
    need to be enabled (modules, dependencies, installation, etc.), but this
    should provide everything we need to get there relatively quickly.
    
    To use this, install meson (distro package, or mesonbuild.com) and run:
    
      $ cd <pulseaudio src dir>
      $ meson <builddir>
      $ ninja -C <builddir>

diff --git a/meson.build b/meson.build
new file mode 100644
index 00000000..f215ce36
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,220 @@
+project('pulseaudio', 'c', 'cpp',
+        version : '10.99.1',
+        meson_version : '>= 0.31.0',
+        default_options : [ 'c_std=gnu11', 'cpp_std=c++11' ]
+        )
+
+pa_version = meson.project_version()
+version_split = pa_version.split('.')
+pa_version_major = version_split[0]
+pa_version_minor = version_split[1]
+pa_version_micro = version_split[2]
+pa_version_major_minor = pa_version_major + '.' + pa_version_minor
+
+pa_api_version = 12
+pa_protocol_version = 31
+
+apiversion = '1.0'
+soversion = 0
+# FIXME: this doesn't actually do what we want it to
+# maintaining compatibility with the previous libtool versioning
+# current = minor * 100 + micro
+libversion = '@0 at .@1 at .0'.format(soversion, pa_version_minor.to_int() * 100 + pa_version_micro.to_int())
+
+prefix = get_option('prefix')
+datadir = join_paths(prefix, get_option('datadir'))
+localstatedir = join_paths(prefix, get_option('localstatedir'))
+sysconfdir = join_paths(prefix, get_option('sysconfdir'))
+
+cc = meson.get_compiler('c')
+
+cdata = configuration_data()
+cdata.set_quoted('PACKAGE', 'pulseaudio')
+cdata.set_quoted('PACKAGE_NAME', 'pulseaudio')
+cdata.set_quoted('PACKAGE_VERSION', pa_version)
+cdata.set_quoted('CANONICAL_HOST', host_machine.cpu())
+cdata.set_quoted('PA_MACHINE_ID', join_paths(sysconfdir, 'machine-id'))
+cdata.set_quoted('PA_MACHINE_ID_FALLBACK', join_paths(localstatedir, 'lib', 'dbus', 'machine-id'))
+cdata.set_quoted('PA_SRCDIR', join_paths(meson.current_source_dir(), 'src'))
+cdata.set_quoted('PA_BUILDDIR', meson.current_build_dir())
+cdata.set_quoted('PA_SOEXT', '.so')
+cdata.set_quoted('PA_DEFAULT_CONFIG_DIR', join_paths(sysconfdir, 'pulse'))
+cdata.set_quoted('PA_BINARY', join_paths(prefix, get_option('bindir'), 'pulseaudio'))
+cdata.set_quoted('PA_SYSTEM_RUNTIME_PATH', join_paths(localstatedir, 'run', 'pulse'))
+cdata.set_quoted('PA_SYSTEM_CONFIG_PATH', join_paths(localstatedir, 'lib', 'pulse'))
+cdata.set_quoted('PA_SYSTEM_STATE_PATH', join_paths(localstatedir, 'lib', 'pulse'))
+cdata.set_quoted('PA_DLSEARCHPATH', join_paths(prefix, get_option('libdir'), 'pulse-' + pa_version_major_minor, 'modules'))
+cdata.set_quoted('PA_SYSTEM_USER', get_option('system_user'))
+cdata.set_quoted('PA_SYSTEM_GROUP', get_option('system_group'))
+cdata.set_quoted('PA_ACCESS_GROUP', get_option('access_group'))
+cdata.set_quoted('PA_CFLAGS', 'Not yet supported on meson')
+cdata.set_quoted('PA_ALSA_PATHS_DIR', join_paths(datadir, 'pulseaudio', 'alsa-mixer', 'paths'))
+cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', join_paths(datadir, 'pulseaudio', 'alsa-mixer', 'profile-sets'))
+cdata.set_quoted('DESKTOPFILEDIR', join_paths(datadir, 'applications'))
+
+# Headers
+
+check_headers = [
+  'arpa/inet.h',
+  'cpuid.h',
+  'grp.h',
+  'langinfo.h',
+  'locale.h',
+  'netdb.h',
+  'netinet/in.h',
+  'netinet/in_systm.h',
+  'netinet/ip.h',
+  'netinet/tcp.h',
+  'pcreposix.h',
+  'poll.h',
+  'pwd.h',
+  'regex.h',
+  'sched.h',
+  'sys/capability.h',
+  'sys/ioctl.h',
+  'sys/mman.h',
+  'sys/prctl.h',
+  'sys/resource.h',
+  'sys/select.h',
+  'sys/socket.h',
+  'sys/un.h',
+  'valgrind/memcheck.h',
+  'xlocale.h',
+]
+
+foreach h : check_headers
+  if cc.has_header(h)
+    define = 'HAVE_' + h.underscorify().to_upper()
+    cdata.set(define, 1)
+  endif
+endforeach
+
+# FIXME: move this to the above set
+if cc.has_header('pthread.h')
+  cdata.set('HAVE_PTHREAD', 1)
+endif
+
+# Functions
+
+check_functions = [
+  'accept4',
+  'clock_gettime',
+  'fchmod',
+  'fchown',
+  'fork',
+  'fstat',
+  'getaddrinfo',
+  'gettimeofday',
+  'getuid',
+  'lstat',
+  'memfd_create',
+  'mlock',
+  'nanosleep',
+  'paccept',
+  'pipe',
+  'pipe2',
+  'posix_madvise',
+  'readlink',
+  'setegid',
+  'seteuid',
+  'setregid',
+  'setreuid',
+  'setresgid',
+  'setresuid',
+  'setsid',
+  'sig2str',
+  'sigaction',
+  'strtod_l',
+  'symlink',
+  'sysconf',
+  'uname',
+]
+
+foreach f : check_functions
+  if cc.has_function(f)
+    define = 'HAVE_' + f.underscorify().to_upper()
+    cdata.set(define, 1)
+  endif
+endforeach
+
+shm_dep = cc.find_library('rt', required : false)
+if shm_dep.found()
+  cdata.set('HAVE_SHM_OPEN', 1)
+endif
+
+if cc.has_function('SYS_memfd_create', prefix : '#include <sys/syscall.h>')
+  cdata.set('HAVE_MEMFD', 1)
+endif
+
+# Types
+
+# FIXME: do we ever care about gid_t not being defined / smaller than an int?
+cdata.set('GETGROUPS_T', 'gid_t')
+
+# Include paths
+
+configinc = include_directories('.')
+topinc = include_directories('src')
+
+# CFLAGS
+
+pa_c_args = ['-DHAVE_CONFIG_H', '-D_GNU_SOURCE']
+server_c_args = ['-D__INCLUDED_FROM_PULSE_AUDIO']
+cdata.set('MESON_BUILD', 1)
+
+# Core Dependencies
+
+libm_dep = cc.find_library('m', required : true)
+thread_dep = dependency('threads')
+cap_dep = cc.find_library('cap', required : false)
+
+if get_option('database') == 'tdb'
+  database_dep = dependency('tdb')
+elif get_option('database') == 'gdbm'
+  database_dep = cc.find_library('gdbm', required : true)
+endif
+
+atomictest = '''void func() {
+  volatile int atomic = 2;
+  __sync_bool_compare_and_swap (&atomic, 2, 3);
+}
+'''
+if cc.compiles(atomictest)
+  cdata.set('HAVE_ATOMIC_BUILTINS', true)
+else
+  # FIXME: check if we need libatomic_ops
+endif
+
+# FIXME: make sure it's >= 2.2
+ltdl_dep = cc.find_library('ltdl', required : true)
+# FIXME: can meson support libtool -dlopen/-dlpreopen things?
+#        and do we still want to support this at all?
+cdata.set('DISABLE_LIBTOOL_PRELOAD', 1)
+
+sndfile_dep = dependency('sndfile', version : '>= 1.0.20')
+
+dbus_dep = dependency('dbus-1', version : '>= 1.4.12', required : false)
+if dbus_dep.found()
+  cdata.set('HAVE_DBUS', 1)
+endif
+
+x11_dep = dependency('x11-xcb', required : false)
+if x11_dep.found()
+  cdata.set('HAVE_X11', 1)
+endif
+
+alsa_dep = dependency('alsa', version : '>= 1.0.24', required : false)
+if alsa_dep.found()
+  cdata.set('HAVE_ALSA_UCM', 1)
+endif
+
+# FIXME: support ORC
+cdata.set('DISABLE_ORC', 1)
+
+# Module dependencies
+udev_dep = dependency('libudev', version : '>= 143', required : false)
+
+# Now generate config.h from everything above
+configure_file(output : 'config.h', configuration : cdata)
+
+subdir('src')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000..233a1846
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,13 @@
+option('system_user',
+        type : 'string', value : 'pulse',
+        description : 'User for running the PulseAudio daemon as a system-wide instance (pulse)')
+option('system_group',
+        type : 'string', value : 'pulse',
+        description : 'Group for running the PulseAudio daemon as a system-wide instance (pulse)')
+option('access_group',
+        type : 'string', value : 'pulse-access',
+        description : 'Group which is allowed access to a system-wide PulseAudio daemon (pulse-access)')
+option('database',
+        type : 'combo', value : 'tdb',
+        choices : [ 'gdbm', 'tdb', 'simple' ],
+        description : 'Database backend')
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index 98831267..6a395785 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -157,7 +157,11 @@ pa_daemon_conf *pa_daemon_conf_new(void) {
 #else
     if (pa_run_from_build_tree()) {
         pa_log_notice("Detected that we are run from the build tree, fixing search path.");
+#ifdef MESON_BUILD
+        c->dl_search_path = pa_xstrdup(PA_BUILDDIR PA_PATH_SEP "src" PA_PATH_SEP "modules");
+#else
         c->dl_search_path = pa_xstrdup(PA_BUILDDIR);
+#endif
     } else
         c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH);
 #endif
diff --git a/src/daemon/main.c b/src/daemon/main.c
index c80fa943..da26c385 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -98,6 +98,15 @@
 #include "ltdl-bind-now.h"
 #include "server-lookup.h"
 
+#ifdef DISABLE_LIBTOOL_PRELOAD
+/* FIXME: work around a libtool bug by making sure we have 2 elements. Bug has
+ * been reported: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=29576 */
+const lt_dlsymlist lt_preloaded_symbols[] = {
+    { "@PROGRAM@", NULL },
+    { NULL, NULL }
+};
+#endif
+
 #ifdef HAVE_LIBWRAP
 /* Only one instance of these variables */
 int allow_severity = LOG_INFO;
diff --git a/src/daemon/meson.build b/src/daemon/meson.build
new file mode 100644
index 00000000..3bf4a3b8
--- /dev/null
+++ b/src/daemon/meson.build
@@ -0,0 +1,34 @@
+pulseaudio_sources = [
+  'caps.c',
+  'cmdline.c',
+  'cpulimit.c',
+  'daemon-conf.c',
+  'dumpmodules.c',
+  'ltdl-bind-now.c',
+  'main.c',
+]
+
+pulseaudio_headers = [
+  'caps.h',
+  'cmdline.h',
+  'cpulimit.h',
+  'daemon-conf.h',
+  'dumpmodules.h',
+  'ltdl-bind-now.h',
+]
+
+if dbus_dep.found()
+  pulseaudio_sources += 'server-lookup.c'
+  pulseaudio_headers += 'server-lookup.h'
+endif
+
+# FIXME: man pages, dependencies
+executable('pulseaudio',
+  pulseaudio_sources,
+  pulseaudio_headers,
+  install: true,
+  include_directories : [configinc, topinc],
+  link_with : [libpulsecore, libpulsecommon, libpulse],
+  dependencies : [ltdl_dep, cap_dep, dbus_dep],
+  c_args : pa_c_args,
+)
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 00000000..1cc3b40e
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,194 @@
+libpulsecommon_sources = [
+  'pulse/client-conf.c',
+  'pulse/fork-detect.c',
+  'pulse/format.c',
+  'pulse/json.c',
+  'pulse/xmalloc.c',
+  'pulse/proplist.c',
+  'pulse/utf8.c',
+  'pulse/channelmap.c',
+  'pulse/sample.c',
+  'pulse/util.c',
+  'pulse/timeval.c',
+  'pulse/rtclock.c',
+  'pulse/volume.c',
+  'pulsecore/authkey.c',
+  'pulsecore/conf-parser.c',
+  'pulsecore/core-error.c',
+  'pulsecore/core-format.c',
+  'pulsecore/core-rtclock.c',
+  'pulsecore/core-util.c',
+  'pulsecore/dynarray.c',
+  'pulsecore/fdsem.c',
+  'pulsecore/flist.c',
+  'pulsecore/g711.c',
+  'pulsecore/hashmap.c',
+  'pulsecore/i18n.c',
+  'pulsecore/idxset.c',
+  'pulsecore/arpa-inet.c',
+  'pulsecore/iochannel.c',
+  'pulsecore/ioline.c',
+  'pulsecore/ipacl.c',
+  'pulsecore/lock-autospawn.c',
+  'pulsecore/log.c',
+  'pulsecore/ratelimit.c',
+  'pulsecore/mcalign.c',
+  'pulsecore/memblock.c',
+  'pulsecore/memblockq.c',
+  'pulsecore/memchunk.c',
+  'pulsecore/mutex-posix.c',
+  'pulsecore/native-common.c',
+  'pulsecore/once.c',
+  'pulsecore/packet.c',
+  'pulsecore/parseaddr.c',
+  'pulsecore/pdispatch.c',
+  'pulsecore/pid.c',
+  'pulsecore/pipe.c',
+  'pulsecore/memtrap.c',
+  'pulsecore/aupdate.c',
+  'pulsecore/proplist-util.c',
+  'pulsecore/pstream-util.c',
+  'pulsecore/pstream.c',
+  'pulsecore/queue.c',
+  'pulsecore/random.c',
+  'pulsecore/srbchannel.c',
+  'pulsecore/sample-util.c',
+  'pulsecore/semaphore-posix.c',
+  'pulsecore/shm.c',
+  'pulsecore/bitset.c',
+  'pulsecore/socket-client.c',
+  'pulsecore/socket-server.c',
+  'pulsecore/socket-util.c',
+  'pulsecore/strbuf.c',
+  'pulsecore/strlist.c',
+  'pulsecore/svolume_c.c',
+  'pulsecore/svolume_mmx.c',
+  'pulsecore/tagstruct.c',
+  'pulsecore/thread-posix.c',
+  'pulsecore/time-smoother.c',
+  'pulsecore/tokenizer.c',
+  'pulsecore/usergroup.c',
+  'pulsecore/sndfile-util.c',
+  'pulsecore/svolume_arm.c',
+]
+
+libpulsecommon_headers = [
+  'pulse/client-conf.h',
+  'pulse/fork-detect.h',
+  'pulse/format.h',
+  'pulse/json.h',
+  'pulse/xmalloc.h',
+  'pulse/proplist.h',
+  'pulse/utf8.h',
+  'pulse/channelmap.h',
+  'pulse/sample.h',
+  'pulse/util.h',
+  'pulse/timeval.h',
+  'pulse/rtclock.h',
+  'pulse/volume.h',
+  'pulsecore/atomic.h',
+  'pulsecore/authkey.h',
+  'pulsecore/conf-parser.h',
+  'pulsecore/core-error.h',
+  'pulsecore/core-format.h',
+  'pulsecore/core-rtclock.h',
+  'pulsecore/core-util.h',
+  'pulsecore/creds.h',
+  'pulsecore/dynarray.h',
+  'pulsecore/endianmacros.h',
+  'pulsecore/fdsem.h',
+  'pulsecore/flist.h',
+  'pulsecore/g711.h',
+  'pulsecore/hashmap.h',
+  'pulsecore/i18n.h',
+  'pulsecore/idxset.h',
+  'pulsecore/arpa-inet.h',
+  'pulsecore/iochannel.h',
+  'pulsecore/ioline.h',
+  'pulsecore/ipacl.h',
+  'pulsecore/llist.h',
+  'pulsecore/lock-autospawn.h',
+  'pulsecore/log.h',
+  'pulsecore/ratelimit.h',
+  'pulsecore/macro.h',
+  'pulsecore/mcalign.h',
+  'pulsecore/mem.h',
+  'pulsecore/memblock.h',
+  'pulsecore/memblockq.h',
+  'pulsecore/memchunk.h',
+  'pulsecore/mutex.h',
+  'pulsecore/native-common.h',
+  'pulsecore/once.h',
+  'pulsecore/packet.h',
+  'pulsecore/parseaddr.h',
+  'pulsecore/pdispatch.h',
+  'pulsecore/pid.h',
+  'pulsecore/pipe.h',
+  'pulsecore/memtrap.h',
+  'pulsecore/aupdate.h',
+  'pulsecore/proplist-util.h',
+  'pulsecore/pstream-util.h',
+  'pulsecore/pstream.h',
+  'pulsecore/queue.h',
+  'pulsecore/random.h',
+  'pulsecore/refcnt.h',
+  'pulsecore/srbchannel.h',
+  'pulsecore/sample-util.h',
+  'pulsecore/semaphore.h',
+  'pulsecore/shm.h',
+  'pulsecore/bitset.h',
+  'pulsecore/socket-client.h',
+  'pulsecore/socket-server.h',
+  'pulsecore/socket-util.h',
+  'pulsecore/strbuf.h',
+  'pulsecore/strlist.h',
+  'pulsecore/tagstruct.h',
+  'pulsecore/thread.h',
+  'pulsecore/time-smoother.h',
+  'pulsecore/tokenizer.h',
+  'pulsecore/usergroup.h',
+  'pulsecore/sndfile-util.h',
+  'pulsecore/socket.h',
+]
+
+if dbus_dep.found()
+  libpulsecommon_sources += [
+    'pulsecore/dbus-util.c',
+    'pulsecore/rtkit.c',
+  ]
+  libpulsecommon_headers += [
+    'pulsecore/dbus-util.h',
+    'pulsecore/rtkit.h',
+  ]
+endif
+
+if x11_dep.found()
+  libpulsecommon_sources += [
+    'pulse/client-conf-x11.c',
+    'pulsecore/x11prop.c',
+  ]
+  libpulsecommon_headers += [
+    'pulse/client-conf-x11.h',
+    'pulsecore/x11prop.h',
+  ]
+endif
+
+# FIXME: Do non-POSIX thread things
+# FIXME: Do SIMD things
+
+libpulsecommon = shared_library('pulsecommon-' + pa_version_major_minor,
+  libpulsecommon_sources,
+  libpulsecommon_headers,
+  include_directories : [configinc, topinc],
+  c_args : [pa_c_args],
+  install : true,
+  dependencies : [libm_dep, thread_dep, shm_dep, sndfile_dep, dbus_dep, x11_dep],
+  implicit_include_directories : false)
+
+libpulsecommon_dep = declare_dependency(link_with: libpulsecommon)
+
+subdir('pulse')
+subdir('pulsecore')
+subdir('daemon')
+subdir('modules')
+subdir('utils')
diff --git a/src/modules/alsa/meson.build b/src/modules/alsa/meson.build
new file mode 100644
index 00000000..e2a45e2c
--- /dev/null
+++ b/src/modules/alsa/meson.build
@@ -0,0 +1,31 @@
+libalsa_util_sources = [
+  'alsa-util.c',
+  'alsa-ucm.c',
+  'alsa-mixer.c',
+  'alsa-sink.c',
+  'alsa-source.c',
+  '../reserve-wrap.c',
+]
+
+libalsa_util_headers = [
+  'alsa-util.h',
+  'alsa-ucm.h',
+  'alsa-mixer.h',
+  'alsa-sink.h',
+  'alsa-source.h',
+  '../reserve-wrap.h',
+]
+
+if dbus_dep.found()
+    libalsa_util_sources += [ '../reserve.c', '../reserve-monitor.c' ]
+    libalsa_util_headers += [ '../reserve.h', '../reserve-monitor.h' ]
+endif
+
+libalsa_util = static_library('libalsa_util',
+  libalsa_util_sources,
+  libalsa_util_headers,
+  c_args : [pa_c_args, server_c_args],
+  include_directories : [configinc, topinc],
+  dependencies : [libpulse_dep, libpulsecore_dep, alsa_dep, dbus_dep],
+  install : false
+)
diff --git a/src/modules/meson.build b/src/modules/meson.build
new file mode 100644
index 00000000..3d6b53fe
--- /dev/null
+++ b/src/modules/meson.build
@@ -0,0 +1,127 @@
+# module name, sources, [headers, extra flags, extra deps, extra libs]
+all_modules = [
+  [ 'module-allow-passthrough', 'module-allow-passthrough.c' ],
+  [ 'module-always-sink', 'module-always-sink.c' ],
+  [ 'module-always-source', 'module-always-source.c' ],
+  [ 'module-augment-properties', 'module-augment-properties.c' ],
+  [ 'module-bluetooth-discover', 'bluetooth/module-bluetooth-discover.c' ],
+  [ 'module-bluetooth-policy', 'bluetooth/module-bluetooth-policy.c' ],
+#  [ 'module-bluez4-device', 'bluetooth/module-bluez4-device.c' ],
+#  [ 'module-bluez4-discover', 'bluetooth/module-bluez4-discover.c' ],
+#  [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c' ],
+#  [ 'module-bluez5-discover', 'bluetooth/module-bluez5-discover.c' ],
+#  [ 'module-bonjour-publish', 'macosx/module-bonjour-publish.c' ],
+  [ 'module-card-restore', 'module-card-restore.c' ],
+  [ 'module-cli', 'module-cli.c' ],
+  [ 'module-cli-protocol-tcp', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_CLI', '-DUSE_TCP_SOCKETS'] ],
+  [ 'module-cli-protocol-unix', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_CLI', '-DUSE_UNIX_SOCKETS'] ],
+  [ 'module-combine', 'module-combine.c' ],
+  [ 'module-combine-sink', 'module-combine-sink.c' ],
+#  [ 'module-console-kit', 'module-console-kit.c' ],
+#  [ 'module-coreaudio-detect', 'macosx/module-coreaudio-detect.c' ],
+#  [ 'module-coreaudio-device', 'macosx/module-coreaudio-device.c' ],
+#  [ 'module-dbus-protocol', 'module-dbus-protocol.c' ]
+  [ 'module-default-device-restore', 'module-default-device-restore.c', [], [], [], libprotocol_native ],
+  [ 'module-detect', 'module-detect.c' ],
+  [ 'module-device-manager', 'module-device-manager.c' ],
+  [ 'module-device-restore', 'module-device-restore.c', [], [], [dbus_dep], libprotocol_native ],
+#  [ 'module-echo-cancel', 'module-echo-cancel.c' ],
+  [ 'module-equalizer-sink', 'module-equalizer-sink.c', [], [], [dbus_dep] ],
+  [ 'module-esound-compat-spawnfd', 'module-esound-compat-spawnfd.c' ],
+  [ 'module-esound-compat-spawnpid', 'module-esound-compat-spawnpid.c' ],
+#  [ 'module-esound-protocol-tcp', 'module-protocol-stub.c' ],
+#  [ 'module-esound-protocol-unix', 'module-protocol-stub.c' ],
+  [ 'module-esound-sink', 'module-esound-sink.c' ],
+  [ 'module-filter-apply', 'module-filter-apply.c' ],
+  [ 'module-filter-heuristics', 'module-filter-heuristics.c' ],
+#  [ 'module-gconf', 'gconf/module-gconf.c' ],
+  [ 'module-hal-detect', 'module-hal-detect-compat.c' ],
+  [ 'module-http-protocol-tcp', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_HTTP', '-DUSE_TCP_SOCKETS'] ],
+  [ 'module-http-protocol-unix', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_HTTP', '-DUSE_UNIX_SOCKETS'] ],
+  [ 'module-intended-roles', 'module-intended-roles.c' ],
+#  [ 'module-jackdbus-detect', 'jack/module-jackdbus-detect.c' ],
+#  [ 'module-jack-sink', 'jack/module-jack-sink.c' ],
+#  [ 'module-jack-source', 'jack/module-jack-source.c' ],
+#  [ 'module-ladspa-sink', 'module-ladspa-sink.c' ],
+#  [ 'module-lirc', 'module-lirc.c' ],
+  [ 'module-loopback', 'module-loopback.c' ],
+  [ 'module-match', 'module-match.c' ],
+#  [ 'module-mmkbd-evdev', 'module-mmkbd-evdev.c' ],
+  [ 'module-native-protocol-fd', 'module-native-protocol-fd.c' ],
+  [ 'module-native-protocol-tcp', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_NATIVE', '-DUSE_TCP_SOCKETS'], [], libprotocol_native ],
+  [ 'module-native-protocol-unix', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_NATIVE', '-DUSE_UNIX_SOCKETS'], [], libprotocol_native ],
+  [ 'module-null-sink', 'module-null-sink.c' ],
+  [ 'module-null-source', 'module-null-source.c' ],
+#  [ 'module-oss', 'oss/module-oss.c' ],
+  [ 'module-pipe-sink', 'module-pipe-sink.c' ],
+  [ 'module-pipe-source', 'module-pipe-source.c' ],
+  [ 'module-position-event-sounds', 'module-position-event-sounds.c' ],
+#  [ 'module-raop-discover', 'raop/module-raop-discover.c' ],
+#  [ 'module-raop-sink', 'raop/module-raop-sink.c' ],
+  [ 'module-remap-sink', 'module-remap-sink.c' ],
+  [ 'module-remap-source', 'module-remap-source.c' ],
+  [ 'module-rescue-streams', 'module-rescue-streams.c' ],
+  [ 'module-role-cork', ['module-role-cork.c', 'stream-interaction.c'], 'stream-interaction.h' ],
+  [ 'module-role-ducking', ['module-role-ducking.c', 'stream-interaction.c'], 'stream-interaction.h' ],
+  [ 'module-rtp-recv', 'rtp/module-rtp-recv.c' ],
+  [ 'module-rtp-send', 'rtp/module-rtp-send.c' ],
+  [ 'module-rygel-media-server', 'module-rygel-media-server.c', [], [], [dbus_dep] ],
+  [ 'module-simple-protocol-tcp', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_SIMPLE', '-DUSE_TCP_SOCKETS'] ],
+  [ 'module-simple-protocol-unix', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_SIMPLE', '-DUSE_UNIX_SOCKETS'] ],
+  [ 'module-sine', 'module-sine.c' ],
+  [ 'module-sine-source', 'module-sine-source.c' ],
+#  [ 'module-solaris', 'module-solaris.c' ],
+  [ 'module-stream-restore', 'module-stream-restore.c', [], [], [dbus_dep], libprotocol_native ],
+  [ 'module-suspend-on-idle', 'module-suspend-on-idle.c' ],
+  [ 'module-switch-on-connect', 'module-switch-on-connect.c' ],
+  [ 'module-switch-on-port-available', 'module-switch-on-port-available.c' ],
+  [ 'module-systemd-login', 'module-systemd-login.c' ],
+  [ 'module-tunnel-sink', 'module-tunnel.c' ],
+  [ 'module-tunnel-sink-new', 'module-tunnel-sink-new.c' ],
+  [ 'module-tunnel-source', 'module-tunnel.c' ],
+  [ 'module-tunnel-source-new', 'module-tunnel-source-new.c' ],
+  [ 'module-virtual-sink', 'module-virtual-sink.c' ],
+  [ 'module-virtual-source', 'module-virtual-source.c' ],
+  [ 'module-virtual-surround-sink', 'module-virtual-surround-sink.c' ],
+  [ 'module-volume-restore', 'module-volume-restore.c' ],
+#  [ 'module-waveout', 'module-waveout.c' ],
+#  [ 'module-x11-bell', 'x11/module-x11-bell.c' ],
+#  [ 'module-x11-cork-request', 'x11/module-x11-cork-request.c' ],
+#  [ 'module-x11-publish', 'x11/module-x11-publish.c' ],
+#  [ 'module-x11-xsmp', 'x11/module-x11-xsmp.c' ],
+#  [ 'module-zeroconf-discover', 'module-zeroconf-discover.c' ],
+#  [ 'module-zeroconf-publish', 'module-zeroconf-publish.c' ],
+]
+
+if alsa_dep.found()
+  subdir('alsa')
+  all_modules += [
+    [ 'module-alsa-card', 'alsa/module-alsa-card.c', [], [], [alsa_dep], libalsa_util ],
+    [ 'module-alsa-sink', 'alsa/module-alsa-sink.c', [], [], [alsa_dep], libalsa_util ],
+    [ 'module-alsa-source', 'alsa/module-alsa-source.c', [], [], [alsa_dep], libalsa_util ],
+  ]
+endif
+
+if udev_dep.found()
+  all_modules += [ [ 'module-udev-detect', 'module-udev-detect.c', [], [], [udev_dep] ] ]
+endif
+
+foreach m : all_modules
+  name = m[0]
+  sources = m[1]
+  headers = m.get(2, [])
+  extra_flags = m.get(3, [])
+  extra_deps = m.get(4, [])
+  extra_libs = m.get(5, [])
+
+  mod = shared_module(name,
+    sources,
+    headers,
+    include_directories : [configinc, topinc],
+    c_args : [pa_c_args, server_c_args, '-DPA_MODULE_NAME=' + name.underscorify()] + extra_flags,
+    install : true,
+    dependencies : [thread_dep, libpulse_dep, libpulsecore_dep] + extra_deps,
+    link_with : extra_libs,
+    name_prefix : '',
+    implicit_include_directories : false)
+endforeach
diff --git a/src/modules/module-role-cork.c b/src/modules/module-role-cork.c
index b3c9d5f9..a13457ef 100644
--- a/src/modules/module-role-cork.c
+++ b/src/modules/module-role-cork.c
@@ -23,7 +23,7 @@
 
 #include <pulsecore/macro.h>
 #include <pulsecore/core.h>
-#include <stream-interaction.h>
+#include "stream-interaction.h"
 
 PA_MODULE_AUTHOR("Lennart Poettering");
 PA_MODULE_DESCRIPTION("Mute & cork streams with certain roles while others exist");
diff --git a/src/modules/module-role-ducking.c b/src/modules/module-role-ducking.c
index a1308c2a..1b2ecd73 100644
--- a/src/modules/module-role-ducking.c
+++ b/src/modules/module-role-ducking.c
@@ -23,7 +23,7 @@
 
 #include <pulsecore/macro.h>
 #include <pulsecore/core.h>
-#include <stream-interaction.h>
+#include "stream-interaction.h"
 
 PA_MODULE_AUTHOR("Flavio Ceolin <flavio.ceolin at profusion.mobi>");
 PA_MODULE_DESCRIPTION("Apply a ducking effect based on streams roles");
diff --git a/src/pulse/meson.build b/src/pulse/meson.build
new file mode 100644
index 00000000..d1d816ff
--- /dev/null
+++ b/src/pulse/meson.build
@@ -0,0 +1,73 @@
+libpulse_sources = [
+  'channelmap.c',
+  'context.c',
+  'direction.c',
+  'error.c',
+  'ext-device-manager.c',
+  'ext-device-restore.c',
+  'ext-stream-restore.c',
+  'format.c',
+  'introspect.c',
+  'mainloop-api.c',
+  'mainloop-signal.c',
+  'mainloop.c',
+  'operation.c',
+  'proplist.c',
+  'rtclock.c',
+  'sample.c',
+  'scache.c',
+  'stream.c',
+  'subscribe.c',
+  'thread-mainloop.c',
+  'timeval.c',
+  'utf8.c',
+  'util.c',
+  'volume.c',
+  'xmalloc.c',
+]
+
+libpulse_headers = [
+  'cdecl.h',
+  'channelmap.h',
+  'context.h',
+  'def.h',
+  'direction.h',
+  'error.h',
+  'ext-device-manager.h',
+  'ext-device-restore.h',
+  'ext-stream-restore.h',
+  'format.h',
+  'gccmacro.h',
+  'internal.h',
+  'introspect.h',
+  'mainloop-api.h',
+  'mainloop-signal.h',
+  'mainloop.h',
+  'operation.h',
+  'proplist.h',
+  'pulseaudio.h',
+  'rtclock.h',
+  'sample.h',
+  'scache.h',
+  'stream.h',
+  'subscribe.h',
+  'thread-mainloop.h',
+  'timeval.h',
+  'utf8.h',
+  'util.h',
+  'volume.h',
+  'xmalloc.h',
+]
+
+libpulse = shared_library('pulse',
+  libpulse_sources,
+  libpulse_headers,
+  version : libversion,
+  include_directories : [configinc, topinc],
+  c_args : [pa_c_args],
+  soversion : soversion,
+  install : true,
+  dependencies : [libm_dep, thread_dep, libpulsecommon_dep, dbus_dep],
+  implicit_include_directories : false)
+
+libpulse_dep = declare_dependency(link_with: libpulse)
diff --git a/src/pulsecore/meson.build b/src/pulsecore/meson.build
new file mode 100644
index 00000000..8c3555fe
--- /dev/null
+++ b/src/pulsecore/meson.build
@@ -0,0 +1,170 @@
+libpulsecore_sources = [
+  'asyncmsgq.c',
+  'asyncq.c',
+  'auth-cookie.c',
+  'card.c',
+  'cli-command.c',
+  'cli-text.c',
+  'client.c',
+  'core-scache.c',
+  'core-subscribe.c',
+  'core.c',
+  'cpu.c',
+  'cpu-arm.c',
+  'cpu-orc.c',
+  'cpu-x86.c',
+  'device-port.c',
+  'ffmpeg/resample2.c',
+  'filter/biquad.c',
+  'filter/crossover.c',
+  'filter/lfe-filter.c',
+  'hook-list.c',
+  'ltdl-helper.c',
+  'mix.c',
+  'modargs.c',
+  'modinfo.c',
+  'module.c',
+  'msgobject.c',
+  'namereg.c',
+  'object.c',
+  'play-memblockq.c',
+  'play-memchunk.c',
+  'remap.c',
+  'resampler.c',
+  'resampler/ffmpeg.c',
+  'resampler/peaks.c',
+  'resampler/trivial.c',
+  'rtpoll.c',
+  'sconv-s16be.c',
+  'sconv-s16le.c',
+  'sconv.c',
+  'shared.c',
+  'sink.c',
+  'sink-input.c',
+  'sioman.c',
+  'sound-file-stream.c',
+  'sound-file.c',
+  'source.c',
+  'source-output.c',
+  'start-child.c',
+  'stream-util.c',
+  'thread-mq.c',
+]
+
+libpulsecore_headers = [
+  'asyncmsgq.h',
+  'asyncq.h',
+  'auth-cookie.h',
+  'card.h',
+  'cli-command.h',
+  'cli-text.h',
+  'client.h',
+  'core.h',
+  'core-scache.h',
+  'core-subscribe.h',
+  'cpu.h',
+  'cpu-arm.h',
+  'cpu-orc.h',
+  'cpu-x86.h',
+  'database.h',
+  'device-port.h',
+  'ffmpeg/avcodec.h',
+  'ffmpeg/dsputil.h',
+  'filter/biquad.h',
+  'filter/crossover.h',
+  'filter/lfe-filter.h',
+  'hook-list.h',
+  'ltdl-helper.h',
+  'mix.h',
+  'modargs.h',
+  'modinfo.h',
+  'module.h',
+  'msgobject.h',
+  'namereg.h',
+  'object.h',
+  'play-memblockq.h',
+  'play-memchunk.h',
+  'remap.h',
+  'resampler.h',
+  'rtpoll.h',
+  'sconv.h',
+  'sconv-s16be.h',
+  'sconv-s16le.h',
+  'shared.h',
+  'sink-input.h',
+  'sink.h',
+  'sioman.h',
+  'sound-file-stream.h',
+  'sound-file.h',
+  'source-output.h',
+  'source.h',
+  'start-child.h',
+  'stream-util.h',
+  'thread-mq.h',
+  'typedefs.h',
+]
+
+if get_option('database') == 'tdb'
+  libpulsecore_sources += 'database-tdb.c'
+  database_c_args = '-DHAVE_TDB'
+elif get_option('database') == 'gdbm'
+  libpulsecore_sources += 'database-gdbm.c'
+  database_c_args = '-DHAVE_GDBM'
+else
+  libpulsecore_sources += 'database-simple.c'
+  database_c_args = '-DHAVE_SIMPLEDB'
+endif
+
+if dbus_dep.found()
+  libpulsecore_sources += [
+    'dbus-shared.c',
+    'protocol-dbus.c',
+  ]
+  libpulsecore_headers += [
+    'dbus-shared.h',
+    'protocol-dbus.h',
+  ]
+endif
+
+# FIXME: walk through dependencies and add files
+
+# FIXME: SIMD support (ORC)
+simd = import('unstable-simd')
+libpulsecore_simd = simd.check('libpulsecore_simd',
+  mmx : ['remap_mmx.c', 'svolume_mmx.c'],
+  sse : ['remap_sse.c', 'sconv_sse.c', 'svolume_sse.c'],
+  neon : ['remap_neon.c', 'sconv_neon.c', 'svolume_neon.c'],
+  c_args : [pa_c_args],
+  include_directories : [configinc, topinc],
+  implicit_include_directories : false,
+  compiler : cc)
+libpulsecore_simd_lib = libpulsecore_simd[0]
+cdata.merge_from(libpulsecore_simd[1])
+
+# FIXME: Implement Windows support
+#'mutex-win32.c',
+#'poll-win32.c',
+#'semaphore-win32.c',
+#'thread-win32.c',
+
+libpulsecore = shared_library('pulsecore-' + pa_version_major_minor,
+  libpulsecore_sources,
+  libpulsecore_headers,
+  include_directories : [configinc, topinc],
+  c_args : [pa_c_args, server_c_args],
+  install : true,
+  link_with : libpulsecore_simd_lib,
+  dependencies : [libm_dep, libpulsecommon_dep, libpulse_dep, ltdl_dep, shm_dep, sndfile_dep, database_dep, dbus_dep, x11_dep],
+  implicit_include_directories : false)
+
+libpulsecore_dep = declare_dependency(link_with: libpulsecore)
+
+# For modules that need protocol native functionality
+libprotocol_native = shared_library('protocol_native',
+  'protocol-native.c',
+  ['protocol-native.h', 'native-common.h'],
+  c_args : [pa_c_args, server_c_args, database_c_args],
+  include_directories : [configinc, topinc],
+  dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, dbus_dep],
+  install : true
+)
diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c
index 0478b6fb..70b81607 100644
--- a/src/pulsecore/module.c
+++ b/src/pulsecore/module.c
@@ -84,7 +84,11 @@ bool pa_module_exists(const char *name) {
     state = NULL;
     if (PA_UNLIKELY(pa_run_from_build_tree())) {
         while ((p = pa_split(paths, ":", &state))) {
+#ifdef MESON_BUILD
+            pathname = pa_sprintf_malloc("%s" PA_PATH_SEP "src" PA_PATH_SEP "modules" PA_PATH_SEP "%s" PA_SOEXT, p, n);
+#else
             pathname = pa_sprintf_malloc("%s" PA_PATH_SEP ".libs" PA_PATH_SEP "%s" PA_SOEXT, p, n);
+#endif
             result = access(pathname, F_OK) == 0 ? true : false;
             pa_log_debug("Checking for existence of '%s': %s", pathname, result ? "success" : "failure");
             pa_xfree(pathname);
diff --git a/src/utils/meson.build b/src/utils/meson.build
new file mode 100644
index 00000000..e407d072
--- /dev/null
+++ b/src/utils/meson.build
@@ -0,0 +1,67 @@
+pacat_sources = [
+  'pacat.c',
+]
+
+# FIXME: man pages
+executable('pacat',
+  pacat_sources,
+  install: true,
+  include_directories : [configinc, topinc],
+  link_with : [libpulsecommon, libpulse],
+  dependencies : [sndfile_dep],
+  c_args : pa_c_args,
+)
+
+pactl_sources = [
+  'pactl.c',
+]
+
+# FIXME: man pages
+executable('pactl',
+  pactl_sources,
+  install: true,
+  include_directories : [configinc, topinc],
+  link_with : [libpulsecommon, libpulse],
+  dependencies : [sndfile_dep],
+  c_args : pa_c_args,
+)
+
+pasuspender_sources = [
+  'pasuspender.c',
+]
+
+# FIXME: man pages
+executable('pasuspender',
+  pasuspender_sources,
+  install: true,
+  include_directories : [configinc, topinc],
+  link_with : [libpulsecommon, libpulse],
+  c_args : pa_c_args,
+)
+
+pacmd_sources = [
+  'pacmd.c',
+]
+
+# FIXME: man pages
+executable('pacmd',
+  pacmd_sources,
+  install: true,
+  include_directories : [configinc, topinc],
+  link_with : [libpulsecommon, libpulse],
+  c_args : pa_c_args,
+)
+
+pax11publish_sources = [
+  'pax11publish.c',
+]
+
+# FIXME: man pages
+executable('pax11publish',
+  pax11publish_sources,
+  install: true,
+  include_directories : [configinc, topinc],
+  link_with : [libpulsecommon, libpulse],
+  dependencies : [x11_dep],
+  c_args : pa_c_args,
+)

commit 04361ee0d2b1583dc65b5047a3002d1c03b3342f
Author: Jean-Philippe Guillemin <h1p8r10n at gmail.com>
Date:   Mon Feb 12 19:14:21 2018 +0200

    alsa-mixer: add a profile-set file to fix iec958 input and output on CMEDIA USB2.0 High-Speed True HD Audio
    
    The iec958 output uses device 2 and the iec958 input uses device 0. The
    USB configuration in alsa doesn't set up the device numbers correctly,
    which is why we need custom configuration in PulseAudio. Ideally this
    would be fixed in alsa, but trying to get help for that wasn't
    successful.

diff --git a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
index 264bfdb3..4dacb62b 100644
--- a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
+++ b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
@@ -106,5 +106,6 @@ ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02bb", ENV{PULSE_PROFILE_SET}="kinec
 ATTRS{idVendor}=="041e", ATTRS{idProduct}=="322c", ENV{PULSE_PROFILE_SET}="sb-omni-surround-5.1.conf"
 ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4014", ENV{PULSE_PROFILE_SET}="dell-dock-tb16-usb-audio.conf"
 ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1260", ENV{PULSE_PROFILE_SET}="steelseries-arctis-usb-audio.conf"
+ATTRS{idVendor}=="147a", ATTRS{idProduct}=="e055", ENV{PULSE_PROFILE_SET}="cmedia-high-speed-true-hdaudio.conf"
 
 LABEL="pulseaudio_end"
diff --git a/src/modules/alsa/mixer/profile-sets/cmedia-high-speed-true-hdaudio.conf b/src/modules/alsa/mixer/profile-sets/cmedia-high-speed-true-hdaudio.conf
new file mode 100644
index 00000000..1b6f61c7
--- /dev/null
+++ b/src/modules/alsa/mixer/profile-sets/cmedia-high-speed-true-hdaudio.conf
@@ -0,0 +1,66 @@
+# 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, see <http://www.gnu.org/licenses/>.
+
+# Config for CMEDIA USB2.0 High-Speed True HD Audio 147a:e055
+# Added by Jean-Philippe Guillemin <h1p8r10n at gmail.com>
+
+
+[General]
+auto-profiles = yes
+
+[Mapping analog-stereo]
+device-strings = front:%f
+channel-map = left,right
+paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
+priority = 10
+
+# If everything else fails, try to use hw:0 as a stereo device.
+[Mapping stereo-fallback]
+device-strings = hw:%f
+fallback = yes
+channel-map = front-left,front-right
+paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
+priority = 1
+
+[Mapping analog-surround-21]
+device-strings = surround21:%f
+channel-map = front-left,front-right,lfe
+paths-output = analog-output analog-output-lineout analog-output-speaker
+priority = 8
+direction = output
+
+[Mapping analog-surround-51]
+device-strings = surround51:%f
+channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
+paths-output = analog-output analog-output-lineout analog-output-speaker
+priority = 8
+direction = output
+
+[Mapping analog-surround-71]
+device-strings = surround71:%f
+channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
+description = Analog Surround 7.1
+paths-output = analog-output analog-output-lineout analog-output-speaker
+priority = 7
+direction = output
+
+[Mapping iec958-stereo]
+device-strings = hw:%f,2 hw:%f,0
+channel-map = left,right
+paths-output = iec958-stereo-output
+paths-input = iec958-stereo-input
+priority = 5



More information about the pulseaudio-commits mailing list