summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/Makefile.am4
-rw-r--r--audio/device.c23
-rw-r--r--audio/device.h2
-rw-r--r--audio/ipc.h10
-rw-r--r--audio/manager.c65
-rw-r--r--audio/manager.h7
-rw-r--r--audio/pcm_bluetooth.c47
-rw-r--r--audio/unix.c43
8 files changed, 148 insertions, 53 deletions
diff --git a/audio/Makefile.am b/audio/Makefile.am
index 240c737f..ce16cd12 100644
--- a/audio/Makefile.am
+++ b/audio/Makefile.am
@@ -25,8 +25,8 @@ alsa_LTLIBRARIES = libasound_module_pcm_bluetooth.la libasound_module_ctl_blueto
libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c ipc.h
libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version -export-dynamic
-libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @ALSA_LIBS@
-libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @SBC_CFLAGS@
+libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @BLUEZ_LIBS@ @ALSA_LIBS@
+libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@ @SBC_CFLAGS@
libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c ipc.h
libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version -export-dynamic
diff --git a/audio/device.c b/audio/device.c
index 2a6498ee..2c06233e 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -417,3 +417,26 @@ uint8_t device_get_state(struct device *dev)
return STATE_DISCONNECTED;
}
+
+gboolean device_is_connected(struct device *dev, const char *interface)
+{
+ if (!interface) {
+ if ((dev->sink || dev->source) &&
+ avdtp_is_connected(&dev->src, &dev->dst))
+ return TRUE;
+
+ if (dev->headset && headset_is_active(dev))
+ return TRUE;
+ }
+ else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
+ avdtp_is_connected(&dev->src, &dev->dst))
+ return TRUE;
+ else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&
+ avdtp_is_connected(&dev->src, &dev->dst))
+ return TRUE;
+ else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
+ headset_is_active(dev))
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/audio/device.h b/audio/device.h
index a527c096..a9954314 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -76,3 +76,5 @@ int device_remove_stored(struct device *dev);
void device_finish_sdp_transaction(struct device *device);
uint8_t device_get_state(struct device *dev);
+
+gboolean device_is_connected(struct device *dev, const char *interface);
diff --git a/audio/ipc.h b/audio/ipc.h
index 27ee742c..7eb6e398 100644
--- a/audio/ipc.h
+++ b/audio/ipc.h
@@ -22,6 +22,7 @@
*/
#include <stdint.h>
+#include <bluetooth/bluetooth.h>
#define IPC_TYPE_CONNECT 0x0001
@@ -34,10 +35,9 @@
#endif
/* Supported roles */
-#define PKT_ROLE_NONE 0
-#define PKT_ROLE_AUTO 1
-#define PKT_ROLE_VOICE 2
-#define PKT_ROLE_HIFI 3
+#define PKT_ROLE_AUTO 0
+#define PKT_ROLE_VOICE 1
+#define PKT_ROLE_HIFI 2
/* Packet types */
#define PKT_TYPE_CFG_REQ 0
@@ -52,7 +52,7 @@
#define PKT_ERROR_NONE 0
struct ipc_packet {
- uint8_t id; /* Device id */
+ bdaddr_t bdaddr; /* Address of the remote Device */
uint8_t role; /* Audio role eg: voice, wifi, auto... */
uint8_t type; /* Packet type */
uint8_t error; /* Packet error code */
diff --git a/audio/manager.c b/audio/manager.c
index c1a72b8f..b918ebba 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -108,19 +108,6 @@ static void get_next_record(struct audio_sdp_data *data);
static DBusHandlerResult get_handles(const char *uuid,
struct audio_sdp_data *data);
-static struct device *find_device(bdaddr_t *bda)
-{
- GSList *l;
-
- for (l = devices; l != NULL; l = l->next) {
- struct device *device = l->data;
- if (bacmp(&device->dst, bda) == 0)
- return device;
- }
-
- return NULL;
-}
-
static struct device *create_device(bdaddr_t *bda)
{
static int device_id = 0;
@@ -601,7 +588,7 @@ struct device *manager_device_connected(bdaddr_t *bda, const char *uuid)
const char *path;
gboolean headset = FALSE, created = FALSE;
- device = find_device(bda);
+ device = manager_find_device(bda, NULL, FALSE);
if (!device) {
device = create_device(bda);
if (!add_device(device)) {
@@ -735,7 +722,7 @@ static DBusHandlerResult am_create_device(DBusConnection *conn,
str2ba(address, &bda);
- device = find_device(&bda);
+ device = manager_find_device(&bda, NULL, FALSE);
if (!device) {
device = create_device(&bda);
return resolve_services(msg, device);
@@ -870,7 +857,7 @@ static DBusHandlerResult am_remove_device(DBusConnection *conn,
const char *param;
GSList *l;
- default_dev = manager_get_connected_device();
+ default_dev = manager_find_device(BDADDR_ANY, NULL, TRUE);
if (!default_dev) {
l = devices;
@@ -930,8 +917,7 @@ static DBusHandlerResult am_find_by_addr(DBusConnection *conn,
}
str2ba(address, &bda);
-
- device = find_device(&bda);
+ device = manager_find_device(&bda, NULL, FALSE);
if (!device)
return err_does_not_exist(conn, msg);
@@ -1069,7 +1055,7 @@ static void parse_stored_devices(char *key, char *value, void *data)
return;
str2ba(key, &dst);
- device = find_device(&dst);
+ device = manager_find_device(&dst, PKT_ROLE_AUTO, FALSE);
if (device)
return;
@@ -1093,8 +1079,8 @@ static void register_devices_stored(const char *adapter)
struct stat st;
struct device *device;
bdaddr_t default_src;
- bdaddr_t src;
bdaddr_t dst;
+ bdaddr_t src;
char *addr;
int dev_id;
@@ -1114,7 +1100,7 @@ static void register_devices_stored(const char *adapter)
dev_id = hci_get_route(&default_src);
if (dev_id < 0)
return;
-
+
hci_devba(dev_id, &default_src);
if (bacmp(&default_src, &src) != 0)
return;
@@ -1124,7 +1110,7 @@ static void register_devices_stored(const char *adapter)
return;
str2ba(addr, &dst);
- device = find_device(&dst);
+ device = manager_find_device(&dst, PKT_ROLE_AUTO, FALSE);
if (device) {
info("Setting %s as default device", addr);
@@ -1760,3 +1746,38 @@ gboolean manager_authorize(bdaddr_t *dba, const char *uuid,
return TRUE;
}
+
+struct device *manager_find_device(bdaddr_t *bda, const char *interface,
+ gboolean connected)
+{
+ GSList *l;
+
+ if (!bacmp(bda, BDADDR_ANY) && !interface && !connected)
+ return default_dev;
+
+ for (l = devices; l != NULL; l = l->next) {
+ struct device *dev = l->data;
+
+ if (bacmp(bda, BDADDR_ANY) && bacmp(&dev->dst, bda))
+ continue;
+
+ if (interface && !strcmp(AUDIO_HEADSET_INTERFACE, interface)
+ && !dev->headset)
+ continue;
+
+ if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface)
+ && !dev->sink)
+ continue;
+
+ if (interface && !strcmp(AUDIO_SOURCE_INTERFACE, interface)
+ && !dev->source)
+ continue;
+
+ if (connected && !device_is_connected(dev, interface))
+ continue;
+
+ return dev;
+ }
+
+ return NULL;
+}
diff --git a/audio/manager.h b/audio/manager.h
index 65992040..623a778c 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -42,11 +42,10 @@ void audio_exit(void);
uint32_t add_service_record(DBusConnection *conn, sdp_buf_t *buf);
int remove_service_record(DBusConnection *conn, uint32_t rec_id);
-struct device *manager_device_connected(bdaddr_t *bda, const char *uuid);
-
-struct device *manager_default_device();
+struct device *manager_find_device(bdaddr_t *bda, const char *interface,
+ gboolean connected);
-struct device *manager_get_connected_device(void);
+struct device *manager_device_connected(bdaddr_t *bda, const char *uuid);
gboolean manager_authorize(bdaddr_t *dba, const char *uuid,
DBusPendingCallNotifyFunction cb,
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
index c6df710b..2e5161e9 100644
--- a/audio/pcm_bluetooth.c
+++ b/audio/pcm_bluetooth.c
@@ -883,7 +883,7 @@ static int bluetooth_a2dp_init(struct bluetooth_data *data,
a2dp->sbc.blocks = sbc->blocks;
a2dp->sbc.bitpool = sbc->bitpool;
a2dp->codesize = a2dp->sbc.subbands * a2dp->sbc.blocks *
- a2dp->sbc.channels * 2;
+ a2dp->sbc.channels * 2;
a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
a2dp->pipefd[0] = -1;
a2dp->pipefd[1] = -1;
@@ -905,12 +905,52 @@ static int bluetooth_cfg(struct bluetooth_data *data, snd_config_t *conf)
struct ipc_packet *pkt = (void *) buf;
struct ipc_data_cfg *cfg = (void *) pkt->data;
struct ipc_codec_sbc *sbc = (void *) cfg->data;
+ snd_config_iterator_t i, next;
+ const char *addr, *pref;
DBG("Sending PKT_TYPE_CFG_REQ...");
memset(buf, 0, sizeof(buf));
+
+ snd_config_for_each(i, next, conf) {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id;
+
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+
+ printf("id = %s\n", id);
+ if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
+ continue;
+
+ if (strcmp(id, "device") == 0) {
+ if (snd_config_get_string(n, &addr) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+ str2ba(addr, &pkt->bdaddr);
+ continue;
+ }
+
+ if (strcmp(id, "preference") == 0) {
+ if (snd_config_get_string(n, &pref) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+ else if (!strcmp(pref, "voice") ||
+ !strcmp(pref, "sco"))
+ pkt->role = PKT_ROLE_VOICE;
+ else if (!strcmp(pref, "hifi") ||
+ !strcmp(pref, "a2dp"))
+ pkt->role = PKT_ROLE_HIFI;
+ continue;
+ }
+
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+
pkt->type = PKT_TYPE_CFG_REQ;
- pkt->role = PKT_ROLE_NONE;
pkt->error = PKT_ERROR_NONE;
ret = send(data->sock, pkt, sizeof(struct ipc_packet), 0);
@@ -969,11 +1009,10 @@ done:
data->cfg.pkt_len, data->cfg.sample_size, data->cfg.rate);
if (data->cfg.codec == CFG_CODEC_SBC) {
- struct bluetooth_a2dp *a2dp = &data->a2dp;
ret = bluetooth_a2dp_init(data, sbc);
if (ret < 0)
return ret;
- printf("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
+ DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
a2dp->sbc.allocation, a2dp->sbc.subbands,
a2dp->sbc.blocks, a2dp->sbc.bitpool);
}
diff --git a/audio/unix.c b/audio/unix.c
index 3488fd5f..2b9b74f0 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -116,7 +116,7 @@ static int unix_sendmsg_fd(int sock, int fd, struct ipc_packet *pkt)
struct iovec iov = {
.iov_base = pkt,
.iov_len = sizeof(struct ipc_packet)
- };
+ };
struct msghdr msgh = {
.msg_name = 0,
@@ -138,18 +138,23 @@ static int unix_sendmsg_fd(int sock, int fd, struct ipc_packet *pkt)
return sendmsg(sock, &msgh, MSG_NOSIGNAL);
}
-static service_type_t select_service(struct device *dev)
+static service_type_t select_service(struct device *dev, const char *interface)
{
- if (dev->sink && avdtp_is_connected(&dev->src, &dev->dst))
- return TYPE_SINK;
- else if (dev->headset && headset_is_active(dev))
- return TYPE_HEADSET;
- else if (dev->sink)
+ if (!interface) {
+ if (dev->sink && avdtp_is_connected(&dev->src, &dev->dst))
+ return TYPE_SINK;
+ else if (dev->headset && headset_is_active(dev))
+ return TYPE_HEADSET;
+ else if (dev->sink)
+ return TYPE_SINK;
+ else if (dev->headset)
+ return TYPE_HEADSET;
+ } else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink)
return TYPE_SINK;
- else if (dev->headset)
+ else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset)
return TYPE_HEADSET;
- else
- return TYPE_NONE;
+
+ return TYPE_NONE;
}
@@ -215,7 +220,7 @@ static void a2dp_setup_complete(struct avdtp *session, struct device *dev,
}
for (codec_cap = NULL; caps; caps = g_slist_next(caps)) {
- cap = caps->data;
+ cap = caps->data;
if (cap->category == AVDTP_MEDIA_CODEC) {
codec_cap = (void *) cap->data;
break;
@@ -253,7 +258,7 @@ static void a2dp_setup_complete(struct avdtp *session, struct device *dev,
cfg->codec = CFG_CODEC_SBC;
sbc->allocation = sbc_cap->allocation_method == A2DP_ALLOCATION_SNR ?
- 0x01 : 0x00;
+ 0x01 : 0x00;
sbc->subbands = sbc_cap->subbands == A2DP_SUBBANDS_4 ? 4 : 8;
switch (sbc_cap->block_length) {
@@ -298,17 +303,23 @@ static void cfg_event(struct unix_client *client, struct ipc_packet *pkt,
int ret, fd;
unsigned int id;
struct a2dp_data *a2dp;
+ const char *interface = NULL;
+
+ if (pkt->role == PKT_ROLE_VOICE)
+ interface = AUDIO_HEADSET_INTERFACE;
+ else if (pkt->role == PKT_ROLE_HIFI)
+ interface = AUDIO_SINK_INTERFACE;
- dev = manager_get_connected_device();
+ dev = manager_find_device(&pkt->bdaddr, interface, TRUE);
if (dev)
goto proceed;
- dev = manager_default_device();
+ dev = manager_find_device(&pkt->bdaddr, interface, FALSE);
if (!dev)
goto failed;
proceed:
- client->type = select_service(dev);
+ client->type = select_service(dev, interface);
switch (client->type) {
case TYPE_SINK:
@@ -320,7 +331,7 @@ proceed:
if (!a2dp->session) {
error("Unable to get a session");
goto failed;
- }
+ }
id = a2dp_source_request_stream(a2dp->session, dev,
TRUE, a2dp_setup_complete,