[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.15-test5-116-g857a1f4

Lennart Poettering gitmailer-noreply at 0pointer.de
Mon Mar 30 11:58:19 PDT 2009


This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.

The master branch has been updated
      from  d33be12fde0910e4a7515c3f6a8b8f2165624cb0 (commit)

- Log -----------------------------------------------------------------
857a1f4 fix compiler warning
90fbc03 make sure we never access an invalid pa_bluetooth_device object
1c8f968 make sure we always read in all properties
66b80e9 get rid of old 'Connected' property parsing and make sure we don't execute two case branches
91355a1 introduce typedef for pa_bt_audio_state and use it everywhere
1390564 Merge commit 'elmarco/bluetooth-fixes'
87fcb3d bluetooth: use new audio State properties
38825d7 bluetooth: GetProperties after profile UUID show up
20bd1c6 bluetooth: remove racy GetProperties to check profile
9e8c2d3 bluetooth: don't access outside array range
61cd6d4 bluetooth: fail when switching on non-connected profile
62a4e36 bluetooth: connected can be -1, check > 0
13f1c44 Do not reconfigure capabilities.
168c741 Query and make use of the current configuration.
071b3e7 Update ipc to match new message headers introduced on BlueZ 4.34.
b03c545 Fix misuse of 'frame.joint' when estimating the frame length.
f80a1f6 Maintain the original code style for sbc.
-----------------------------------------------------------------------

Summary of changes:
 src/modules/bluetooth/bluetooth-util.c            |  120 +++++++++++++-------
 src/modules/bluetooth/bluetooth-util.h            |   39 ++++++-
 src/modules/bluetooth/ipc.c                       |    1 +
 src/modules/bluetooth/ipc.h                       |   73 ++++++++++---
 src/modules/bluetooth/module-bluetooth-device.c   |  125 +++++++++++++-------
 src/modules/bluetooth/module-bluetooth-discover.c |   14 ++-
 src/modules/bluetooth/sbc.c                       |   41 +++----
 src/modules/bluetooth/sbc.h                       |   12 +--
 8 files changed, 284 insertions(+), 141 deletions(-)

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

commit f80a1f6d31a6b3c0c8266c67b12b9e292347fa8b
Author: Luiz Augusto von Dentz <luiz.dentz at openbossa.org>
Date:   Mon Mar 23 11:29:41 2009 -0300

    Maintain the original code style for sbc.

diff --git a/src/modules/bluetooth/sbc.c b/src/modules/bluetooth/sbc.c
index 42bae91..12d3737 100644
--- a/src/modules/bluetooth/sbc.c
+++ b/src/modules/bluetooth/sbc.c
@@ -978,10 +978,8 @@ ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
 	return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
 }
 
-ssize_t sbc_decode(sbc_t *sbc,
-               const void *input, size_t input_len,
-               void *output, size_t output_len,
-               size_t *written)
+ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, size_t *written)
 {
 	struct sbc_priv *priv;
 	char *ptr;
@@ -1046,10 +1044,8 @@ ssize_t sbc_decode(sbc_t *sbc,
 	return framelen;
 }
 
-ssize_t sbc_encode(sbc_t *sbc,
-               const void *input, size_t input_len,
-               void *output, size_t output_len,
-               size_t *written)
+ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, size_t *written)
 {
 	struct sbc_priv *priv;
 	int framelen, samples;
diff --git a/src/modules/bluetooth/sbc.h b/src/modules/bluetooth/sbc.h
index 9a7b4ce..6543588 100644
--- a/src/modules/bluetooth/sbc.h
+++ b/src/modules/bluetooth/sbc.h
@@ -85,16 +85,12 @@ int sbc_reinit(sbc_t *sbc, unsigned long flags);
 
 ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
 
-ssize_t sbc_decode(sbc_t *sbc,
-               const void *input, size_t input_len,
-               void *output, size_t output_len,
-               size_t *written);
+ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, size_t *written);
 
 /* Encodes ONE input block into ONE output block */
-ssize_t sbc_encode(sbc_t *sbc,
-               const void *input, size_t input_len,
-               void *output, size_t output_len,
-               size_t *written);
+ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, size_t *written);
 
 /* Returns the output block size in bytes */
 size_t sbc_get_frame_length(sbc_t *sbc);

commit b03c5458504ce186025e99570f6d2c8d3a6c0cef
Author: Luiz Augusto von Dentz <luiz.dentz at openbossa.org>
Date:   Mon Mar 23 11:46:08 2009 -0300

    Fix misuse of 'frame.joint' when estimating the frame length.
    
    'frame.joint' is not the flag for joint stereo mode, it is a set of bits which
    show for which subbands channels joining was actually used.

diff --git a/src/modules/bluetooth/sbc.c b/src/modules/bluetooth/sbc.c
index 12d3737..779be4b 100644
--- a/src/modules/bluetooth/sbc.c
+++ b/src/modules/bluetooth/sbc.c
@@ -1004,7 +1004,7 @@ ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
 		sbc->bitpool = priv->frame.bitpool;
 
 		priv->frame.codesize = sbc_get_codesize(sbc);
-		priv->frame.length = sbc_get_frame_length(sbc);
+		priv->frame.length = framelen;
 	}
 
 	if (!output)
@@ -1136,30 +1136,25 @@ void sbc_finish(sbc_t *sbc)
 size_t sbc_get_frame_length(sbc_t *sbc)
 {
 	size_t ret;
-	uint8_t subbands, channels, blocks, joint;
+	uint8_t subbands, channels, blocks, joint, bitpool;
 	struct sbc_priv *priv;
 
 	priv = sbc->priv;
-	if (!priv->init) {
-		subbands = sbc->subbands ? 8 : 4;
-		blocks = 4 + (sbc->blocks * 4);
-		channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
-		joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
-	} else {
-		subbands = priv->frame.subbands;
-		blocks = priv->frame.blocks;
-		channels = priv->frame.channels;
-		joint = priv->frame.joint;
-	}
+	if (priv->init)
+		return priv->frame.length;
 
-	ret = 4 + (4 * subbands * channels) / 8;
+	subbands = sbc->subbands ? 8 : 4;
+	blocks = 4 + (sbc->blocks * 4);
+	channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+	joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
+	bitpool = sbc->bitpool;
 
+	ret = 4 + (4 * subbands * channels) / 8;
 	/* This term is not always evenly divide so we round it up */
 	if (channels == 1)
-		ret += ((blocks * channels * sbc->bitpool) + 7) / 8;
+		ret += ((blocks * channels * bitpool) + 7) / 8;
 	else
-		ret += (((joint ? subbands : 0) + blocks * sbc->bitpool) + 7)
-			/ 8;
+		ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8;
 
 	return ret;
 }

commit 071b3e7fc5a89ddc1c7d51ca5854aa661e4cc33b
Author: Luiz Augusto von Dentz <luiz.dentz at openbossa.org>
Date:   Wed Mar 25 17:57:19 2009 -0300

    Update ipc to match new message headers introduced on BlueZ 4.34.

diff --git a/src/modules/bluetooth/ipc.c b/src/modules/bluetooth/ipc.c
index f14c92c..dcecad8 100644
--- a/src/modules/bluetooth/ipc.c
+++ b/src/modules/bluetooth/ipc.c
@@ -35,6 +35,7 @@ static const char *strtypes[] = {
 /* This table contains the string representation for messages names */
 static const char *strnames[] = {
 	"BT_GET_CAPABILITIES",
+	"BT_OPEN",
 	"BT_SET_CONFIGURATION",
 	"BT_NEW_STREAM",
 	"BT_START_STREAM",
diff --git a/src/modules/bluetooth/ipc.h b/src/modules/bluetooth/ipc.h
index f030acf..2e170f5 100644
--- a/src/modules/bluetooth/ipc.h
+++ b/src/modules/bluetooth/ipc.h
@@ -71,7 +71,7 @@ extern "C" {
 #include <sys/un.h>
 #include <errno.h>
 
-#define BT_SUGGESTED_BUFFER_SIZE   128
+#define BT_SUGGESTED_BUFFER_SIZE   512
 #define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
 
 /* Generic message header definition, except for RESPONSE messages */
@@ -94,10 +94,12 @@ typedef struct {
 
 /* Messages names */
 #define BT_GET_CAPABILITIES		0
-#define BT_SET_CONFIGURATION		1
-#define BT_NEW_STREAM			2
-#define BT_START_STREAM			3
-#define BT_STOP_STREAM			4
+#define BT_OPEN				1
+#define BT_SET_CONFIGURATION		2
+#define BT_NEW_STREAM			3
+#define BT_START_STREAM			4
+#define BT_STOP_STREAM			5
+#define BT_CLOSE			6
 #define BT_CONTROL			7
 
 #define BT_CAPABILITIES_TRANSPORT_A2DP	0
@@ -112,19 +114,31 @@ typedef struct {
 
 struct bt_get_capabilities_req {
 	bt_audio_msg_header_t	h;
-	char			device[18];	/* Address of the remote Device */
+	char			source[18];	/* Address of the local Device */
+	char			destination[18];/* Address of the remote Device */
+	char			object[128];	/* DBus object path */
 	uint8_t			transport;	/* Requested transport */
 	uint8_t			flags;		/* Requested flags */
+	uint8_t			seid;		/* Requested capability configuration */
 } __attribute__ ((packed));
 
 /**
- * SBC Codec parameters as per A2DP profile 1.0 § 4.3
+ * SBC Codec parameters as per A2DP profile 1.0 § 4.3
  */
 
-#define BT_A2DP_CODEC_SBC			0x00
-#define BT_A2DP_CODEC_MPEG12			0x01
-#define BT_A2DP_CODEC_MPEG24			0x02
-#define BT_A2DP_CODEC_ATRAC			0x03
+/* A2DP seid are 6 bytes long so HSP/HFP are assigned to 7-8 bits */
+#define BT_A2DP_SEID_RANGE			(1 << 6) - 1
+
+#define BT_A2DP_SBC_SOURCE			0x00
+#define BT_A2DP_SBC_SINK			0x01
+#define BT_A2DP_MPEG12_SOURCE			0x02
+#define BT_A2DP_MPEG12_SINK			0x03
+#define BT_A2DP_MPEG24_SOURCE			0x04
+#define BT_A2DP_MPEG24_SINK			0x05
+#define BT_A2DP_ATRAC_SOURCE			0x06
+#define BT_A2DP_ATRAC_SINK			0x07
+#define BT_A2DP_UNKNOWN_SOURCE			0x08
+#define BT_A2DP_UNKNOWN_SINK			0x09
 
 #define BT_SBC_SAMPLING_FREQ_16000		(1 << 3)
 #define BT_SBC_SAMPLING_FREQ_32000		(1 << 2)
@@ -163,10 +177,16 @@ struct bt_get_capabilities_req {
 #define BT_PCM_FLAG_NREC			0x01
 #define BT_PCM_FLAG_PCM_ROUTING			0x02
 
+#define BT_WRITE_LOCK				(1 << 1)
+#define BT_READ_LOCK				1
+
 typedef struct {
+	uint8_t seid;
 	uint8_t transport;
 	uint8_t type;
 	uint8_t length;
+	uint8_t configured;
+	uint8_t lock;
 	uint8_t data[0];
 } __attribute__ ((packed)) codec_capabilities_t;
 
@@ -199,20 +219,35 @@ typedef struct {
 
 struct bt_get_capabilities_rsp {
 	bt_audio_msg_header_t	h;
+	char			source[18];	/* Address of the local Device */
+	char			destination[18];/* Address of the remote Device */
+	char			object[128];	/* DBus object path */
 	uint8_t			data[0];	/* First codec_capabilities_t */
 } __attribute__ ((packed));
 
+struct bt_open_req {
+	bt_audio_msg_header_t	h;
+	char			source[18];	/* Address of the local Device */
+	char			destination[18];/* Address of the remote Device */
+	char			object[128];	/* DBus object path */
+	uint8_t			seid;		/* Requested capability configuration to lock */
+	uint8_t			lock;		/* Requested lock */
+} __attribute__ ((packed));
+
+struct bt_open_rsp {
+	bt_audio_msg_header_t	h;
+	char			source[18];	/* Address of the local Device */
+	char			destination[18];/* Address of the remote Device */
+	char			object[128];	/* DBus object path */
+} __attribute__ ((packed));
+
 struct bt_set_configuration_req {
 	bt_audio_msg_header_t	h;
-	char			device[18];	/* Address of the remote Device */
-	uint8_t			access_mode;	/* Requested access mode */
 	codec_capabilities_t	codec;		/* Requested codec */
 } __attribute__ ((packed));
 
 struct bt_set_configuration_rsp {
 	bt_audio_msg_header_t	h;
-	uint8_t			transport;	/* Granted transport */
-	uint8_t			access_mode;	/* Granted access mode */
 	uint16_t		link_mtu;	/* Max length that transport supports */
 } __attribute__ ((packed));
 
@@ -241,6 +276,14 @@ struct bt_stop_stream_rsp {
 	bt_audio_msg_header_t	h;
 } __attribute__ ((packed));
 
+struct bt_close_req {
+	bt_audio_msg_header_t	h;
+} __attribute__ ((packed));
+
+struct bt_close_rsp {
+	bt_audio_msg_header_t	h;
+} __attribute__ ((packed));
+
 struct bt_suspend_stream_ind {
 	bt_audio_msg_header_t	h;
 } __attribute__ ((packed));
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 2500fb0..d09dc2c 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -311,7 +311,7 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *
     } else if (u->profile == PROFILE_A2DP) {
 
         while (bytes_left > 0) {
-            if (codec->type == BT_A2DP_CODEC_SBC)
+            if ((codec->type == BT_A2DP_SBC_SINK) && !codec->lock)
                 break;
 
             bytes_left -= codec->length;
@@ -321,7 +321,7 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *
         if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities))
             return -1;
 
-        pa_assert(codec->type == BT_A2DP_CODEC_SBC);
+        pa_assert(codec->type == BT_A2DP_SBC_SINK);
 
         memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities));
     }
@@ -344,7 +344,7 @@ static int get_caps(struct userdata *u) {
     msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
     msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
 
-    pa_strlcpy(msg.getcaps_req.device, u->address, sizeof(msg.getcaps_req.device));
+    pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object));
     if (u->profile == PROFILE_A2DP)
         msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
     else {
@@ -602,12 +602,29 @@ static void setup_sbc(struct a2dp_info *a2dp) {
 
 static int set_conf(struct userdata *u) {
     union {
+        struct bt_open_req open_req;
+        struct bt_open_rsp open_rsp;
         struct bt_set_configuration_req setconf_req;
         struct bt_set_configuration_rsp setconf_rsp;
         bt_audio_error_t error;
         uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
     } msg;
 
+    memset(&msg, 0, sizeof(msg));
+    msg.open_req.h.type = BT_REQUEST;
+    msg.open_req.h.name = BT_OPEN;
+    msg.open_req.h.length = sizeof(msg.open_req);
+
+    pa_strlcpy(msg.open_req.object, u->path, sizeof(msg.open_req.object));
+    msg.open_req.seid = u->profile == PROFILE_A2DP ? u->a2dp.sbc_capabilities.capability.seid : BT_A2DP_SEID_RANGE + 1;
+    msg.open_req.lock = u->profile == PROFILE_A2DP ? BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK;
+
+    if (service_send(u, &msg.open_req.h) < 0)
+        return -1;
+
+    if (service_expect(u, &msg.open_rsp.h, sizeof(msg), BT_OPEN, sizeof(msg.open_rsp)) < 0)
+        return -1;
+
     if (u->profile == PROFILE_A2DP ) {
         u->sample_spec.format = PA_SAMPLE_S16LE;
 
@@ -626,15 +643,14 @@ static int set_conf(struct userdata *u) {
     msg.setconf_req.h.name = BT_SET_CONFIGURATION;
     msg.setconf_req.h.length = sizeof(msg.setconf_req);
 
-    pa_strlcpy(msg.setconf_req.device, u->address, sizeof(msg.setconf_req.device));
-    msg.setconf_req.access_mode = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_ACCESS_MODE_WRITE : BT_CAPABILITIES_ACCESS_MODE_READWRITE;
-
-    msg.setconf_req.codec.transport = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_TRANSPORT_A2DP : BT_CAPABILITIES_TRANSPORT_SCO;
-
     if (u->profile == PROFILE_A2DP) {
         memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, sizeof(u->a2dp.sbc_capabilities));
-        msg.setconf_req.h.length += msg.setconf_req.codec.length - sizeof(msg.setconf_req.codec);
+    } else {
+        msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
+        msg.setconf_req.codec.seid = BT_A2DP_SEID_RANGE + 1;
+        msg.setconf_req.codec.length = sizeof(pcm_capabilities_t);
     }
+    msg.setconf_req.h.length += msg.setconf_req.codec.length - sizeof(msg.setconf_req.codec);
 
     if (service_send(u, &msg.setconf_req.h) < 0)
         return -1;
@@ -642,18 +658,6 @@ static int set_conf(struct userdata *u) {
     if (service_expect(u, &msg.setconf_rsp.h, sizeof(msg), BT_SET_CONFIGURATION, sizeof(msg.setconf_rsp)) < 0)
         return -1;
 
-    if ((u->profile == PROFILE_A2DP && msg.setconf_rsp.transport != BT_CAPABILITIES_TRANSPORT_A2DP) ||
-        (u->profile == PROFILE_HSP && msg.setconf_rsp.transport != BT_CAPABILITIES_TRANSPORT_SCO)) {
-        pa_log("Transport doesn't match what we requested.");
-        return -1;
-    }
-
-    if ((u->profile == PROFILE_A2DP && msg.setconf_rsp.access_mode != BT_CAPABILITIES_ACCESS_MODE_WRITE) ||
-        (u->profile == PROFILE_HSP && msg.setconf_rsp.access_mode != BT_CAPABILITIES_ACCESS_MODE_READWRITE)) {
-        pa_log("Access mode doesn't match what we requested.");
-        return -1;
-    }
-
     u->link_mtu = msg.setconf_rsp.link_mtu;
 
     /* setup SBC encoder now we agree on parameters */

commit 168c741b644a1134bc7c2ca51adb094ec736c160
Author: Luiz Augusto von Dentz <luiz.dentz at openbossa.org>
Date:   Tue Mar 24 12:04:52 2009 -0300

    Query and make use of the current configuration.

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index d09dc2c..bcb65a4 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -275,7 +275,7 @@ static ssize_t service_expect(struct userdata*u, bt_audio_msg_header_t *rsp, siz
     return 0;
 }
 
-static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *rsp) {
+static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capabilities_rsp *rsp) {
     uint16_t bytes_left;
     const codec_capabilities_t *codec;
 
@@ -306,6 +306,9 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *
 
         pa_assert(codec->type == BT_HFP_CODEC_PCM);
 
+        if (codec->configured && seid == 0)
+            return codec->seid;
+
         memcpy(&u->hsp.pcm_capabilities, codec, sizeof(u->hsp.pcm_capabilities));
 
     } else if (u->profile == PROFILE_A2DP) {
@@ -323,19 +326,23 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *
 
         pa_assert(codec->type == BT_A2DP_SBC_SINK);
 
+        if (codec->configured && seid == 0)
+            return codec->seid;
+
         memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities));
     }
 
     return 0;
 }
 
-static int get_caps(struct userdata *u) {
+static int get_caps(struct userdata *u, uint8_t seid) {
     union {
         struct bt_get_capabilities_req getcaps_req;
         struct bt_get_capabilities_rsp getcaps_rsp;
         bt_audio_error_t error;
         uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
     } msg;
+    int ret;
 
     pa_assert(u);
 
@@ -343,6 +350,7 @@ static int get_caps(struct userdata *u) {
     msg.getcaps_req.h.type = BT_REQUEST;
     msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
     msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
+    msg.getcaps_req.seid = seid;
 
     pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object));
     if (u->profile == PROFILE_A2DP)
@@ -359,7 +367,11 @@ static int get_caps(struct userdata *u) {
     if (service_expect(u, &msg.getcaps_rsp.h, sizeof(msg), BT_GET_CAPABILITIES, 0) < 0)
         return -1;
 
-    return parse_caps(u, &msg.getcaps_rsp);
+    ret = parse_caps(u, seid, &msg.getcaps_rsp);
+    if (ret <= 0)
+        return ret;
+
+    return get_caps(u, ret);
 }
 
 static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
@@ -1575,7 +1587,7 @@ static int init_bt(struct userdata *u) {
 static int setup_bt(struct userdata *u) {
     pa_assert(u);
 
-    if (get_caps(u) < 0)
+    if (get_caps(u, 0) < 0)
         return -1;
 
     pa_log_debug("Got device capabilities");

commit 13f1c4413b54489d8ff7ddbbd8d36de26049e12d
Author: Luiz Augusto von Dentz <luiz.dentz at openbossa.org>
Date:   Thu Mar 26 15:38:40 2009 -0300

    Do not reconfigure capabilities.

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index bcb65a4..0a3c91a 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -462,6 +462,9 @@ static int setup_a2dp(struct userdata *u) {
         }
     }
 
+    if (cap->capability.configured)
+        return 0;
+
     if (u->sample_spec.channels <= 1) {
         if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
             cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;

commit 62a4e36f5d136211599a02eff648d6ca2045d539
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Tue Mar 24 14:07:51 2009 +0200

    bluetooth: connected can be -1, check > 0

diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c
index 3288cc5..49c7a80 100644
--- a/src/modules/bluetooth/module-bluetooth-discover.c
+++ b/src/modules/bluetooth/module-bluetooth-discover.c
@@ -93,7 +93,7 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const
 
             /* Oh, awesome, a new device has shown up and been connected! */
 
-            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" profile=\"%s\"", d->address, d->path, d->headset_connected ? "hsp" : "a2dp");
+            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" profile=\"%s\"", d->address, d->path, d->headset_connected > 0 ? "hsp" : "a2dp");
 
 #ifdef NOKIA
             if (pa_modargs_get_value(u->modargs, "sco_sink", NULL) &&

commit 61cd6d4c19f77e560cec4325061efe4723816481
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Tue Mar 24 14:38:52 2009 +0200

    bluetooth: fail when switching on non-connected profile

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 0a3c91a..4c1f1c3 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -133,6 +133,7 @@ struct userdata {
 
     char *address;
     char *path;
+    const pa_bluetooth_device* device;
 
     pa_dbus_connection *connection;
 
@@ -1733,6 +1734,15 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
 
     d = PA_CARD_PROFILE_DATA(new_profile);
 
+    if (u->device->headset_connected <= 0 && *d == PROFILE_HSP) {
+        pa_log_warn("HSP is not connected, refused to switch profile");
+        return -1;
+    }
+    else if (u->device->audio_sink_connected <= 0 && *d == PROFILE_A2DP) {
+        pa_log_warn("A2DP is not connected, refused to switch profile");
+        return -1;
+    }
+
     if (u->sink) {
         inputs = pa_sink_move_all_start(u->sink);
 #ifdef NOKIA
@@ -1926,7 +1936,6 @@ int pa__init(pa_module* m) {
     uint32_t channels;
     struct userdata *u;
     const char *address, *path;
-    const pa_bluetooth_device *d;
     pa_bluetooth_discovery *y = NULL;
     DBusError err;
     char *mike, *speaker;
@@ -1987,11 +1996,11 @@ int pa__init(pa_module* m) {
     if (!(y = pa_bluetooth_discovery_get(m->core)))
         goto fail;
 
-    if (!(d = find_device(u, y, address, path)))
+    if (!(u->device = find_device(u, y, address, path))) /* should discovery ref be kept? */
         goto fail;
 
     /* Add the card structure. This will also initialize the default profile */
-    if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), d) < 0)
+    if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), u->device) < 0)
         goto fail;
 
     pa_bluetooth_discovery_unref(y);

commit 9e8c2d393a6e2ef8ceda58ff3db6c3a7a7223d46
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Thu Mar 26 21:31:12 2009 +0200

    bluetooth: don't access outside array range

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 4c1f1c3..2c4f29c 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -448,8 +448,8 @@ static int setup_a2dp(struct userdata *u) {
             break;
         }
 
-    if ((unsigned) i >= PA_ELEMENTSOF(freq_table)) {
-        for (; i >= 0; i--) {
+    if ((unsigned) i == PA_ELEMENTSOF(freq_table)) {
+        for (--i; i >= 0; i--) {
             if (cap->frequency & freq_table[i].cap) {
                 u->sample_spec.rate = freq_table[i].rate;
                 cap->frequency = freq_table[i].cap;
@@ -463,6 +463,8 @@ static int setup_a2dp(struct userdata *u) {
         }
     }
 
+    pa_assert(i < PA_ELEMENTSOF(freq_table));
+
     if (cap->capability.configured)
         return 0;
 

commit 20bd1c686ca3facb647db7189470ab1bcdae48b5
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Fri Mar 27 13:43:32 2009 +0200

    bluetooth: remove racy GetProperties to check profile

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 3dfc65e..3d410c5 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -401,12 +401,6 @@ static void found_device(pa_bluetooth_discovery *y, const char* path) {
 
     pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Device", "GetProperties"));
     send_and_add_to_pending(y, d, m, get_properties_reply);
-
-    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Headset", "GetProperties"));
-    send_and_add_to_pending(y, d, m, get_properties_reply);
-
-    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.AudioSink", "GetProperties"));
-    send_and_add_to_pending(y, d, m, get_properties_reply);
 }
 
 static void list_devices_reply(DBusPendingCall *pending, void *userdata) {

commit 38825d79123678bf0c5d156aaea4bedb888a7fcd
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Fri Mar 27 13:56:26 2009 +0200

    bluetooth: GetProperties after profile UUID show up

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 3d410c5..dfebf66 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -39,6 +39,9 @@ struct pa_bluetooth_discovery {
     pa_hook hook;
 };
 
+static void get_properties_reply(DBusPendingCall *pending, void *userdata);
+static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessage *m, DBusPendingCallNotifyFunction func);
+
 static pa_bluetooth_uuid *uuid_new(const char *uuid) {
     pa_bluetooth_uuid *u;
 
@@ -213,11 +216,20 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device
                 while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
                     pa_bluetooth_uuid *node;
                     const char *value;
+                    DBusMessage *m;
 
                     dbus_message_iter_get_basic(&ai, &value);
                     node = uuid_new(value);
                     PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node);
 
+                    if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) {
+                        pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset", "GetProperties"));
+                        send_and_add_to_pending(y, d, m, get_properties_reply);
+                    } else if (strcasecmp(A2DP_SINK_UUID, value) == 0) {
+                        pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSink", "GetProperties"));
+                        send_and_add_to_pending(y, d, m, get_properties_reply);
+                    }
+
                     if (!dbus_message_iter_next(&ai))
                         break;
                 }
diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h
index 1d05e63..57f1172 100644
--- a/src/modules/bluetooth/bluetooth-util.h
+++ b/src/modules/bluetooth/bluetooth-util.h
@@ -28,6 +28,20 @@
 #include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 
+/* UUID copied from bluez/audio/device.h */
+#define GENERIC_AUDIO_UUID      "00001203-0000-1000-8000-00805F9B34FB"
+
+#define HSP_HS_UUID             "00001108-0000-1000-8000-00805F9B34FB"
+#define HSP_AG_UUID             "00001112-0000-1000-8000-00805F9B34FB"
+
+#define HFP_HS_UUID             "0000111E-0000-1000-8000-00805F9B34FB"
+#define HFP_AG_UUID             "0000111F-0000-1000-8000-00805F9B34FB"
+
+#define ADVANCED_AUDIO_UUID     "0000110D-0000-1000-8000-00805F9B34FB"
+
+#define A2DP_SOURCE_UUID        "0000110A-0000-1000-8000-00805F9B34FB"
+#define A2DP_SINK_UUID          "0000110B-0000-1000-8000-00805F9B34FB"
+
 typedef struct pa_bluetooth_uuid pa_bluetooth_uuid;
 typedef struct pa_bluetooth_device pa_bluetooth_device;
 typedef struct pa_bluetooth_discovery pa_bluetooth_discovery;

commit 87fcb3d5925cc030e957f55399f8c3e96c66cbb5
Author: Marc-André Lureau <marc-andre.lureau at nokia.com>
Date:   Fri Mar 27 21:48:04 2009 +0200

    bluetooth: use new audio State properties

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index dfebf66..771afff 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -42,6 +42,22 @@ struct pa_bluetooth_discovery {
 static void get_properties_reply(DBusPendingCall *pending, void *userdata);
 static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessage *m, DBusPendingCallNotifyFunction func);
 
+static enum pa_bt_audio_state pa_bt_audio_state_from_string(const char* value) {
+    pa_assert(value);
+
+    if (pa_streq(value, "disconnected")) {
+        return PA_BT_AUDIO_STATE_DISCONNECTED;
+    } else if (pa_streq(value, "connecting")) {
+        return PA_BT_AUDIO_STATE_CONNECTING;
+    } else if (pa_streq(value, "connected")) {
+        return PA_BT_AUDIO_STATE_CONNECTED;
+    } else if (pa_streq(value, "playing")) {
+        return PA_BT_AUDIO_STATE_PLAYING;
+    }
+
+    return PA_BT_AUDIO_STATE_INVALID;
+}
+
 static pa_bluetooth_uuid *uuid_new(const char *uuid) {
     pa_bluetooth_uuid *u;
 
@@ -66,7 +82,7 @@ static pa_bluetooth_device* device_new(const char *path) {
 
     d->dead = FALSE;
 
-    d->device_info_valid = d->audio_sink_info_valid = d->headset_info_valid = 0;
+    d->device_info_valid = 0;
 
     d->name = NULL;
     d->path = pa_xstrdup(path);
@@ -78,9 +94,9 @@ static pa_bluetooth_device* device_new(const char *path) {
     d->class = -1;
     d->trusted = -1;
 
-    d->audio_sink_connected = -1;
-
-    d->headset_connected = -1;
+    d->audio_state = PA_BT_AUDIO_STATE_INVALID;
+    d->audio_sink_state = PA_BT_AUDIO_STATE_INVALID;
+    d->headset_state = PA_BT_AUDIO_STATE_INVALID;
 
     return d;
 }
@@ -102,25 +118,14 @@ static void device_free(pa_bluetooth_device *d) {
     pa_xfree(d);
 }
 
-static pa_bool_t device_is_loaded(pa_bluetooth_device *d) {
-    pa_assert(d);
-
-    return
-        d->device_info_valid &&
-        d->audio_sink_info_valid &&
-        d->headset_info_valid;
-}
-
 static pa_bool_t device_is_audio(pa_bluetooth_device *d) {
     pa_assert(d);
 
-    pa_assert(d->device_info_valid);
-    pa_assert(d->audio_sink_info_valid);
-    pa_assert(d->headset_info_valid);
-
     return
-        d->device_info_valid > 0 &&
-        (d->audio_sink_info_valid > 0 || d->headset_info_valid > 0);
+        d->device_info_valid &&
+        (d->audio_state != PA_BT_AUDIO_STATE_INVALID ||
+         d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID ||
+         d->headset_state != PA_BT_AUDIO_STATE_INVALID);
 }
 
 static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessageIter *i) {
@@ -222,6 +227,11 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device
                     node = uuid_new(value);
                     PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node);
 
+                    /* 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 */
+                    pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Audio", "GetProperties"));
+                    send_and_add_to_pending(y, d, m, get_properties_reply);
+
+                    /* Vudentz said the interfaces are here when the UUIDs are announced */
                     if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) {
                         pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset", "GetProperties"));
                         send_and_add_to_pending(y, d, m, get_properties_reply);
@@ -242,12 +252,12 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device
     return 0;
 }
 
-static int parse_audio_property(pa_bluetooth_discovery *u, int *connected, DBusMessageIter *i) {
+static int parse_audio_property(pa_bluetooth_discovery *u, int *state, DBusMessageIter *i) {
     const char *key;
     DBusMessageIter variant_i;
 
     pa_assert(u);
-    pa_assert(connected);
+    pa_assert(state);
     pa_assert(i);
 
     if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
@@ -269,17 +279,27 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *connected, DBusM
 
     dbus_message_iter_recurse(i, &variant_i);
 
-/*     pa_log_debug("Parsing property org.bluez.{AudioSink|Headset}.%s", key); */
+/*     pa_log_debug("Parsing property org.bluez.{Audio|AudioSink|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"))
+                *state = pa_bt_audio_state_from_string(value);
+/*             pa_log_debug("Value %s", value); */
+        }
+
         case DBUS_TYPE_BOOLEAN: {
 
             dbus_bool_t value;
             dbus_message_iter_get_basic(&variant_i, &value);
 
-            if (pa_streq(key, "Connected"))
-                *connected = !!value;
+            /* if (pa_streq(key, "Connected")) */
+            /*     *connected = !!value; */
 
 /*             pa_log_debug("Value %s", pa_yes_no(value)); */
 
@@ -294,9 +314,6 @@ static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_b
     pa_assert(y);
     pa_assert(d);
 
-    if (!device_is_loaded(d))
-        return;
-
     if (!device_is_audio(d))
         return;
 
@@ -326,10 +343,6 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) {
 
     if (dbus_message_is_method_call(p->message, "org.bluez.Device", "GetProperties"))
         d->device_info_valid = valid;
-    else if (dbus_message_is_method_call(p->message, "org.bluez.Headset", "GetProperties"))
-        d->headset_info_valid = valid;
-    else if (dbus_message_is_method_call(p->message, "org.bluez.AudioSink", "GetProperties"))
-        d->audio_sink_info_valid = valid;
 
     if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
 
@@ -361,12 +374,16 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) {
                 if (parse_device_property(y, d, &dict_i) < 0)
                     goto finish;
 
+            } else if (dbus_message_has_interface(p->message, "org.bluez.Audio")) {
+                if (parse_audio_property(y, &d->audio_state, &dict_i) < 0)
+                    goto finish;
+
             } else if (dbus_message_has_interface(p->message, "org.bluez.Headset")) {
-                if (parse_audio_property(y, &d->headset_connected, &dict_i) < 0)
+                if (parse_audio_property(y, &d->headset_state, &dict_i) < 0)
                     goto finish;
 
             }  else if (dbus_message_has_interface(p->message, "org.bluez.AudioSink")) {
-                if (parse_audio_property(y, &d->audio_sink_connected, &dict_i) < 0)
+                if (parse_audio_property(y, &d->audio_sink_state, &dict_i) < 0)
                     goto finish;
             }
         }
@@ -572,7 +589,8 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
         found_adapter(y, path);
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-    } else if (dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") ||
+    } 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.Device", "PropertyChanged")) {
 
@@ -590,12 +608,16 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
                 if (parse_device_property(y, d, &arg_i) < 0)
                     goto fail;
 
+            } else if (dbus_message_has_interface(m, "org.bluez.Audio")) {
+                if (parse_audio_property(y, &d->audio_state, &arg_i) < 0)
+                    goto fail;
+
             } else if (dbus_message_has_interface(m, "org.bluez.Headset")) {
-                if (parse_audio_property(y, &d->headset_connected, &arg_i) < 0)
+                if (parse_audio_property(y, &d->headset_state, &arg_i) < 0)
                     goto fail;
 
             }  else if (dbus_message_has_interface(m, "org.bluez.AudioSink")) {
-                if (parse_audio_property(y, &d->audio_sink_connected, &arg_i) < 0)
+                if (parse_audio_property(y, &d->audio_sink_state, &arg_i) < 0)
                     goto fail;
             }
 
@@ -690,6 +712,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
                 "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'", NULL) < 0) {
         pa_log("Failed to add D-Bus matches: %s", err.message);
@@ -746,6 +769,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
                                "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'", NULL);
 
@@ -833,3 +857,16 @@ char *pa_bluetooth_cleanup_name(const char *name) {
 
     return t;
 }
+
+pa_bool_t pa_bluetooth_uuid_has(pa_bluetooth_uuid *uuids, const char *uuid) {
+    pa_assert(uuid);
+
+    while (uuids) {
+        if (strcasecmp(uuids->uuid, uuid) == 0)
+            return TRUE;
+
+        uuids = uuids->next;
+    }
+
+    return FALSE;
+}
diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h
index 57f1172..5411473 100644
--- a/src/modules/bluetooth/bluetooth-util.h
+++ b/src/modules/bluetooth/bluetooth-util.h
@@ -53,12 +53,20 @@ struct pa_bluetooth_uuid {
     PA_LLIST_FIELDS(pa_bluetooth_uuid);
 };
 
+/* This enum is shared among Audio, Headset, and AudioSink, although not all values are acceptable in all profiles */
+enum pa_bt_audio_state {
+    PA_BT_AUDIO_STATE_INVALID = -1,
+    PA_BT_AUDIO_STATE_DISCONNECTED,
+    PA_BT_AUDIO_STATE_CONNECTING,
+    PA_BT_AUDIO_STATE_CONNECTED,
+    PA_BT_AUDIO_STATE_PLAYING,
+    PA_BT_AUDIO_STATE_LAST
+};
+
 struct pa_bluetooth_device {
     pa_bool_t dead;
 
     int device_info_valid;      /* 0: no results yet; 1: good results; -1: bad results ... */
-    int audio_sink_info_valid;  /* ... same here ... */
-    int headset_info_valid;     /* ... and here */
 
     /* Device information */
     char *name;
@@ -71,11 +79,14 @@ struct pa_bluetooth_device {
     int class;
     int trusted;
 
-    /* AudioSink information */
-    int audio_sink_connected;
+    /* Audio state */
+    int audio_state;
 
-    /* Headset information */
-    int headset_connected;
+    /* AudioSink state */
+    int audio_sink_state;
+
+    /* Headset state */
+    int headset_state;
 };
 
 pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);
@@ -93,4 +104,6 @@ const char* pa_bluetooth_get_form_factor(uint32_t class);
 
 char *pa_bluetooth_cleanup_name(const char *name);
 
+pa_bool_t pa_bluetooth_uuid_has(pa_bluetooth_uuid *uuids, const char *uuid);
+
 #endif
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 2c4f29c..9fc1531 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1736,11 +1736,11 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
 
     d = PA_CARD_PROFILE_DATA(new_profile);
 
-    if (u->device->headset_connected <= 0 && *d == PROFILE_HSP) {
+    if (u->device->headset_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) {
         pa_log_warn("HSP is not connected, refused to switch profile");
         return -1;
     }
-    else if (u->device->audio_sink_connected <= 0 && *d == PROFILE_A2DP) {
+    else if (u->device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP) {
         pa_log_warn("A2DP is not connected, refused to switch profile");
         return -1;
     }
@@ -1821,7 +1821,11 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl
 
     data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 
-    if (device->audio_sink_info_valid > 0) {
+    /* we base hsp/a2dp availability on UUIDs.
+       Ideally, it would be based on "Connected" state, but
+       we can't afford to wait for this information when
+       we are loaded with profile="hsp", for instance */
+    if (pa_bluetooth_uuid_has(device->uuids, A2DP_SINK_UUID)) {
         p = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP)"), sizeof(enum profile));
         p->priority = 10;
         p->n_sinks = 1;
@@ -1835,7 +1839,8 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl
         pa_hashmap_put(data.profiles, p->name, p);
     }
 
-    if (device->headset_info_valid > 0) {
+    if (pa_bluetooth_uuid_has(device->uuids, HSP_HS_UUID) ||
+	pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID)) {
         p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile));
         p->priority = 20;
         p->n_sinks = 1;
diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c
index 49c7a80..6f3dba1 100644
--- a/src/modules/bluetooth/module-bluetooth-discover.c
+++ b/src/modules/bluetooth/module-bluetooth-discover.c
@@ -84,8 +84,7 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const
     mi = pa_hashmap_get(u->hashmap, d->path);
 
     if (!d->dead &&
-        d->device_connected > 0 &&
-        (d->audio_sink_connected > 0 || d->headset_connected > 0)) {
+        d->device_connected > 0 && d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED) {
 
         if (!mi) {
             pa_module *m = NULL;
@@ -93,7 +92,16 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const
 
             /* Oh, awesome, a new device has shown up and been connected! */
 
-            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" profile=\"%s\"", d->address, d->path, d->headset_connected > 0 ? "hsp" : "a2dp");
+            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\"", d->address, d->path);
+#if 0
+            /* This is in case we have to use hsp immediately, without waiting for .Audio.State = Connected */
+            if (d->headset_state >= PA_BT_AUDIO_STATE_CONNECTED && somecondition) {
+                char *tmp;
+                tmp = pa_sprintf_malloc("%s profile=\"hsp\"", args);
+                pa_xfree(args);
+                args = tmp;
+            }
+#endif
 
 #ifdef NOKIA
             if (pa_modargs_get_value(u->modargs, "sco_sink", NULL) &&

commit 1390564227a01678f78431cd19e7c2077e962db5
Merge: d33be12 87fcb3d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 30 20:34:49 2009 +0200

    Merge commit 'elmarco/bluetooth-fixes'


commit 91355a1ce53c779849ded6db7bce85a30e4289bb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 30 20:55:10 2009 +0200

    introduce typedef for pa_bt_audio_state and use it everywhere

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 94c1d31..aaa4cc9 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -42,18 +42,17 @@ struct pa_bluetooth_discovery {
 static void get_properties_reply(DBusPendingCall *pending, void *userdata);
 static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessage *m, DBusPendingCallNotifyFunction func);
 
-static enum pa_bt_audio_state pa_bt_audio_state_from_string(const char* value) {
+static pa_bt_audio_state_t pa_bt_audio_state_from_string(const char* value) {
     pa_assert(value);
 
-    if (pa_streq(value, "disconnected")) {
+    if (pa_streq(value, "disconnected"))
         return PA_BT_AUDIO_STATE_DISCONNECTED;
-    } else if (pa_streq(value, "connecting")) {
+    else if (pa_streq(value, "connecting"))
         return PA_BT_AUDIO_STATE_CONNECTING;
-    } else if (pa_streq(value, "connected")) {
+    else if (pa_streq(value, "connected"))
         return PA_BT_AUDIO_STATE_CONNECTED;
-    } else if (pa_streq(value, "playing")) {
+    else if (pa_streq(value, "playing"))
         return PA_BT_AUDIO_STATE_PLAYING;
-    }
 
     return PA_BT_AUDIO_STATE_INVALID;
 }
diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h
index 5411473..265caf4 100644
--- a/src/modules/bluetooth/bluetooth-util.h
+++ b/src/modules/bluetooth/bluetooth-util.h
@@ -54,14 +54,14 @@ struct pa_bluetooth_uuid {
 };
 
 /* This enum is shared among Audio, Headset, and AudioSink, although not all values are acceptable in all profiles */
-enum pa_bt_audio_state {
+typedef enum pa_bt_audio_state {
     PA_BT_AUDIO_STATE_INVALID = -1,
     PA_BT_AUDIO_STATE_DISCONNECTED,
     PA_BT_AUDIO_STATE_CONNECTING,
     PA_BT_AUDIO_STATE_CONNECTED,
     PA_BT_AUDIO_STATE_PLAYING,
     PA_BT_AUDIO_STATE_LAST
-};
+} pa_bt_audio_state_t;
 
 struct pa_bluetooth_device {
     pa_bool_t dead;
@@ -80,13 +80,13 @@ struct pa_bluetooth_device {
     int trusted;
 
     /* Audio state */
-    int audio_state;
+    pa_bt_audio_state_t audio_state;
 
     /* AudioSink state */
-    int audio_sink_state;
+    pa_bt_audio_state_t audio_sink_state;
 
     /* Headset state */
-    int headset_state;
+    pa_bt_audio_state_t headset_state;
 };
 
 pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);

commit 66b80e9ecdf65861c07642a89779d7743d6888d9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 30 20:55:50 2009 +0200

    get rid of old 'Connected' property parsing and make sure we don't execute two case branches

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index aaa4cc9..02413f4 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -290,17 +290,6 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *state, DBusMessa
             if (pa_streq(key, "State"))
                 *state = pa_bt_audio_state_from_string(value);
 /*             pa_log_debug("Value %s", value); */
-        }
-
-        case DBUS_TYPE_BOOLEAN: {
-
-            dbus_bool_t value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            /* if (pa_streq(key, "Connected")) */
-            /*     *connected = !!value; */
-
-/*             pa_log_debug("Value %s", pa_yes_no(value)); */
 
             break;
         }

commit 1c8f968282208be391f062c1656d85e2ba5078ac
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 30 20:56:03 2009 +0200

    make sure we always read in all properties

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 02413f4..78c1bed 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -418,6 +418,15 @@ static void found_device(pa_bluetooth_discovery *y, const char* path) {
 
     pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Device", "GetProperties"));
     send_and_add_to_pending(y, d, m, get_properties_reply);
+
+    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Audio", "GetProperties"));
+    send_and_add_to_pending(y, d, m, get_properties_reply);
+
+    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Headset", "GetProperties"));
+    send_and_add_to_pending(y, d, m, get_properties_reply);
+
+    pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.AudioSink", "GetProperties"));
+    send_and_add_to_pending(y, d, m, get_properties_reply);
 }
 
 static void list_devices_reply(DBusPendingCall *pending, void *userdata) {

commit 90fbc036f47a10fb81833dcd7d150e669a30d57c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 30 20:57:12 2009 +0200

    make sure we never access an invalid pa_bluetooth_device object

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index f9800ac..fadfa54 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -132,7 +132,7 @@ struct userdata {
 
     char *address;
     char *path;
-    const pa_bluetooth_device* device;
+    pa_bluetooth_discovery *discovery;
 
     pa_dbus_connection *connection;
 
@@ -1728,6 +1728,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
     struct userdata *u;
     enum profile *d;
     pa_queue *inputs = NULL, *outputs = NULL;
+    const pa_bluetooth_device *device;
 
     pa_assert(c);
     pa_assert(new_profile);
@@ -1735,11 +1736,16 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
 
     d = PA_CARD_PROFILE_DATA(new_profile);
 
-    if (u->device->headset_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) {
+    if (!(device = pa_bluetooth_discovery_get_by_path(u->discovery, u->path))) {
+        pa_log_error("Failed to get device object.");
+        return -1;
+    }
+
+    if (device->headset_state != PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) {
         pa_log_warn("HSP is not connected, refused to switch profile");
         return -1;
     }
-    else if (u->device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP) {
+    else if (device->audio_sink_state != PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP) {
         pa_log_warn("A2DP is not connected, refused to switch profile");
         return -1;
     }
@@ -1884,11 +1890,10 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl
     return 0;
 }
 
-static const pa_bluetooth_device* find_device(struct userdata *u, pa_bluetooth_discovery *y, const char *address, const char *path) {
+static const pa_bluetooth_device* find_device(struct userdata *u, const char *address, const char *path) {
     const pa_bluetooth_device *d = NULL;
 
     pa_assert(u);
-    pa_assert(y);
 
     if (!address && !path) {
         pa_log_error("Failed to get device address/path from module arguments.");
@@ -1896,7 +1901,7 @@ static const pa_bluetooth_device* find_device(struct userdata *u, pa_bluetooth_d
     }
 
     if (path) {
-        if (!(d = pa_bluetooth_discovery_get_by_path(y, path))) {
+        if (!(d = pa_bluetooth_discovery_get_by_path(u->discovery, path))) {
             pa_log_error("%s is not a valid BlueZ audio device.", path);
             return NULL;
         }
@@ -1907,7 +1912,7 @@ static const pa_bluetooth_device* find_device(struct userdata *u, pa_bluetooth_d
         }
 
     } else {
-        if (!(d = pa_bluetooth_discovery_get_by_address(y, address))) {
+        if (!(d = pa_bluetooth_discovery_get_by_address(u->discovery, address))) {
             pa_log_error("%s is not known.", address);
             return NULL;
         }
@@ -1942,9 +1947,9 @@ int pa__init(pa_module* m) {
     uint32_t channels;
     struct userdata *u;
     const char *address, *path;
-    pa_bluetooth_discovery *y = NULL;
     DBusError err;
     char *mike, *speaker;
+    const pa_bluetooth_device *device;
 
     pa_assert(m);
 
@@ -1999,19 +2004,16 @@ int pa__init(pa_module* m) {
     if (setup_dbus(u) < 0)
         goto fail;
 
-    if (!(y = pa_bluetooth_discovery_get(m->core)))
+    if (!(u->discovery = pa_bluetooth_discovery_get(m->core)))
         goto fail;
 
-    if (!(u->device = find_device(u, y, address, path))) /* should discovery ref be kept? */
+    if (!(device = find_device(u, address, path)))
         goto fail;
 
     /* Add the card structure. This will also initialize the default profile */
-    if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), u->device) < 0)
+    if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), device) < 0)
         goto fail;
 
-    pa_bluetooth_discovery_unref(y);
-    y = NULL;
-
     /* Connect to the BT service and query capabilities */
     if (init_bt(u) < 0)
         goto fail;
@@ -2052,9 +2054,6 @@ int pa__init(pa_module* m) {
 
 fail:
 
-    if (y)
-        pa_bluetooth_discovery_unref(y);
-
     pa__done(m);
 
     dbus_error_free(&err);
@@ -2135,5 +2134,8 @@ void pa__done(pa_module *m) {
     pa_xfree(u->address);
     pa_xfree(u->path);
 
+    if (u->discovery)
+        pa_bluetooth_discovery_unref(u->discovery);
+
     pa_xfree(u);
 }

commit 857a1f4909f91fbf504ad05aca4b0dcd7945cacf
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Mar 30 20:57:23 2009 +0200

    fix compiler warning

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index fadfa54..96b95b4 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -462,7 +462,7 @@ static int setup_a2dp(struct userdata *u) {
         }
     }
 
-    pa_assert(i < PA_ELEMENTSOF(freq_table));
+    pa_assert((unsigned) i < PA_ELEMENTSOF(freq_table));
 
     if (cap->capability.configured)
         return 0;

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list