diff options
-rw-r--r-- | audio/Makefile.am | 4 | ||||
-rw-r--r-- | audio/device.c | 23 | ||||
-rw-r--r-- | audio/device.h | 2 | ||||
-rw-r--r-- | audio/ipc.h | 10 | ||||
-rw-r--r-- | audio/manager.c | 65 | ||||
-rw-r--r-- | audio/manager.h | 7 | ||||
-rw-r--r-- | audio/pcm_bluetooth.c | 47 | ||||
-rw-r--r-- | audio/unix.c | 43 |
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, |