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, | 
