diff options
| author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2007-11-21 20:24:11 +0000 | 
|---|---|---|
| committer | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2007-11-21 20:24:11 +0000 | 
| commit | d4e24bf6a3d8af6479abce92fbbf1869a59669aa (patch) | |
| tree | 8ba8c084bb1eb1a3e1dd598127ca33553dbc6d23 | |
| parent | 47e2c26cc95d761099c367593bbbd4bc581bf0ac (diff) | |
Integrate new ipc API implementation.
| -rw-r--r-- | audio/Makefile.am | 14 | ||||
| -rw-r--r-- | audio/ctl_bluetooth.c | 134 | ||||
| -rw-r--r-- | audio/device.c | 2 | ||||
| -rw-r--r-- | audio/gsta2dpsink.c | 746 | ||||
| -rw-r--r-- | audio/gsta2dpsink.h | 8 | ||||
| -rw-r--r-- | audio/gstsbcenc.c | 276 | ||||
| -rw-r--r-- | audio/gstsbcenc.h | 4 | ||||
| -rw-r--r-- | audio/gstsbcparse.c | 49 | ||||
| -rw-r--r-- | audio/gstsbcutil.c | 174 | ||||
| -rw-r--r-- | audio/gstsbcutil.h | 9 | ||||
| -rw-r--r-- | audio/ipc.c | 119 | ||||
| -rw-r--r-- | audio/ipc.h | 367 | ||||
| -rw-r--r-- | audio/manager.c | 4 | ||||
| -rw-r--r-- | audio/pcm_bluetooth.c | 786 | ||||
| -rw-r--r-- | audio/unix.c | 433 | 
15 files changed, 1843 insertions, 1282 deletions
| diff --git a/audio/Makefile.am b/audio/Makefile.am index 48c2a80f..b04fc302 100644 --- a/audio/Makefile.am +++ b/audio/Makefile.am @@ -3,7 +3,7 @@ if AUDIOSERVICE  if CONFIGFILES  confdir = $(sysconfdir)/bluetooth -conf_DATA = audio.service +conf_DATA = audio.service audio.conf  endif  servicedir = $(libdir)/bluetooth @@ -11,7 +11,7 @@ servicedir = $(libdir)/bluetooth  service_PROGRAMS = bluetoothd-service-audio  bluetoothd_service_audio_SOURCES = main.c \ -	manager.h manager.c headset.h headset.c ipc.h unix.h unix.c \ +	manager.h manager.c headset.h headset.c ipc.h ipc.c unix.h unix.c \  	error.h error.c device.h device.c gateway.h gateway.c \  	sink.c sink.h avdtp.c avdtp.h a2dp.c a2dp.h control.c control.h @@ -23,12 +23,12 @@ alsadir = $(libdir)/alsa-lib  alsa_LTLIBRARIES = libasound_module_pcm_bluetooth.la libasound_module_ctl_bluetooth.la -libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c ipc.h rtp.h +libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c rtp.h ipc.h ipc.c  libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version -export-symbols-regex [_]*snd_pcm_.*  libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @ALSA_LIBS@  libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @SBC_CFLAGS@ -libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c ipc.h +libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c rtp.h ipc.h ipc.c  libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version -export-symbols-regex [_]*snd_ctl_.*  libasound_module_ctl_bluetooth_la_LIBADD = @ALSA_LIBS@  libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @@ -39,12 +39,13 @@ gstreamerdir = $(libdir)/gstreamer-0.10  gstreamer_LTLIBRARIES = libgstbluetooth.la -libgstbluetooth_la_SOURCES = gstbluetooth.c ipc.h rtp.h \ +libgstbluetooth_la_SOURCES = gstbluetooth.c \  				gstsbcenc.h gstsbcenc.c \  				gstsbcdec.h gstsbcdec.c \  				gstsbcparse.h gstsbcparse.c \  				gsta2dpsink.h gsta2dpsink.c \ -				gstsbcutil.h gstsbcutil.c +				gstsbcutil.h gstsbcutil.c \ +				rtp.h ipc.h ipc.c  libgstbluetooth_la_LDFLAGS = -module -avoid-version -export-symbols-regex gst_plugin_desc  libgstbluetooth_la_LIBADD = @SBC_LIBS@ @GSTREAMER_LIBS@ -lgstaudio-0.10  libgstbluetooth_la_CFLAGS = @GSTREAMER_CFLAGS@ @SBC_CFLAGS@ @@ -58,3 +59,4 @@ INCLUDES = -I$(top_srcdir)/common  EXTRA_DIST = audio.service audio.conf audio-api.txt test-audio asound.conf  MAINTAINERCLEANFILES = Makefile.in + diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c index 9e1c320c..5c198b1a 100644 --- a/audio/ctl_bluetooth.c +++ b/audio/ctl_bluetooth.c @@ -65,7 +65,7 @@ static void bluetooth_exit(struct bluetooth_data *data)  		return;  	if (data->sock >= 0) -		close(data->sock); +		bt_audio_service_close(data->sock);  	free(data);  } @@ -141,32 +141,49 @@ static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,  }  static int bluetooth_send_ctl(struct bluetooth_data *data, -				struct ipc_packet *pkt, int len) +			uint8_t mode, uint8_t key, struct bt_control_rsp *ctl_rsp)  {  	int ret; +	struct bt_control_req *ctl_req = (void *) ctl_rsp; +	const char *type; -	ret = send(data->sock, pkt, len, MSG_NOSIGNAL); +	memset(ctl_req, 0, BT_AUDIO_IPC_PACKET_SIZE); +	ctl_req->h.msg_type = BT_CONTROL_REQ; +	ctl_req->mode = mode; +	ctl_req->key = key; + +	ret = send(data->sock, ctl_req, BT_AUDIO_IPC_PACKET_SIZE, MSG_NOSIGNAL);  	if (ret <= 0) {  		SYSERR("Unable to request new volume value to server");  		return  -errno;  	} -	ret = recv(data->sock, pkt, len, 0); +	ret = recv(data->sock, ctl_rsp, BT_AUDIO_IPC_PACKET_SIZE, 0);  	if (ret <= 0) { -		SYSERR("Unable to receive new volume value from server"); +		SNDERR("Unable to receive new volume value from server");  		return  -errno;  	} -	if(pkt->type != PKT_TYPE_CTL_RSP) { -		SNDERR("Unexpected packet type %d received", pkt->type); +	type = bt_audio_strmsg(ctl_rsp->h.msg_type); +	if (!type) { +		SNDERR("Bogus message type %d " +				"received from audio service", +				ctl_rsp->h.msg_type);  		return -EINVAL;  	} -	if(pkt->length != sizeof(struct ipc_data_ctl)) { -		SNDERR("Unexpected packet length %d received", pkt->length); +	if (ctl_rsp->h.msg_type != BT_CONTROL_RSP) { +		SNDERR("Unexpected message %s received", type);  		return -EINVAL;  	} +	if (ctl_rsp->posix_errno != 0) { +		SNDERR("BT_CONTROL failed : %s (%d)", +					strerror(ctl_rsp->posix_errno), +					ctl_rsp->posix_errno); +		return -ctl_rsp->posix_errno; +	} +  	return 0;  } @@ -174,28 +191,21 @@ static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,  								long *value)  {  	struct bluetooth_data *data = ext->private_data; -	struct ipc_packet *pkt; -	struct ipc_data_ctl *ctl; -	int len, ret; +	int ret; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_control_rsp *rsp = (void *) buf;  	DBG("ext %p key %ld", ext, key); -	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl); -	pkt = malloc(len); -	memset(pkt, 0, len); +	memset(buf, 0, sizeof(buf));  	*value = 0; -	pkt->type = PKT_TYPE_CTL_REQ; -	pkt->length = sizeof(struct ipc_data_ctl); -	ctl = (struct ipc_data_ctl *) pkt->data; -	ctl->mode = key; - -	if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0) +	ret = bluetooth_send_ctl(data, key, 0, rsp); +	if (ret < 0)  		goto done; -	*value = ctl->key; +	*value = rsp->key;  done: -	free(pkt);  	return ret;  } @@ -203,38 +213,31 @@ static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,  								long *value)  {  	struct bluetooth_data *data = ext->private_data; -	struct ipc_packet *pkt; -	struct ipc_data_ctl *ctl; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_control_rsp *rsp = (void *) buf;  	long current; -	int len, ret; +	int ret, keyvalue;  	DBG("ext %p key %ld", ext, key); -	if ((ret = bluetooth_read_integer(ext, key, ¤t)) < 0) +	ret = bluetooth_read_integer(ext, key, ¤t); +	if (ret < 0)  		return ret;  	if (*value == current)  		return 0; -	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl); -	pkt = malloc(len); -	memset(pkt, 0, len); - -	pkt->length = sizeof(struct ipc_data_ctl); -	ctl = (struct ipc_data_ctl *) pkt->data; -	ctl->mode = key; -  	while (*value != current) { -		pkt->type = PKT_TYPE_CTL_REQ; -		ctl->key = (*value > current) ? CTL_KEY_VOL_UP : CTL_KEY_VOL_DOWN; +		keyvalue = (*value > current) ? BT_CONTROL_KEY_VOL_UP : +				BT_CONTROL_KEY_VOL_DOWN; -		if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0) +		ret = bluetooth_send_ctl(data, key, keyvalue, rsp); +		if (ret < 0)  			break; -		current = ctl->key; +		current = keyvalue;  	} -	free(pkt);  	return ret;  } @@ -242,33 +245,31 @@ static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,  						unsigned int *event_mask)  {  	struct bluetooth_data *data = ext->private_data; -	struct ipc_packet *pkt; -	struct ipc_data_ctl *ctl; -	int len, ret; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_control_ind *ind = (void *) buf; +	int ret; +	const char *type;  	DBG("ext %p id %p", ext, id); -	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl); -	pkt = malloc(len); -	memset(pkt, 0, len); - -	ret = recv(data->sock, pkt, len, MSG_DONTWAIT); -	if (ret <= 0) -		return  -errno; +	memset(buf, 0, sizeof(buf)); -	if(pkt->type != PKT_TYPE_CTL_NTFY) { -		SNDERR("Unexpected packet type %d received!", pkt->type); +	ret = recv(data->sock, ind, BT_AUDIO_IPC_PACKET_SIZE, MSG_DONTWAIT); +	type = bt_audio_strmsg(ind->h.msg_type); +	if (!type) { +		SNDERR("Bogus message type %d " +				"received from audio service", +				ind->h.msg_type);  		return -EAGAIN;  	} -	if(pkt->length != sizeof(struct ipc_data_ctl)) { -		SNDERR("Unexpected packet length %d received", pkt->length); +	if (ind->h.msg_type != BT_CONTROL_IND) { +		SNDERR("Unexpected message %s received", type);  		return -EAGAIN;  	} -	ctl = (struct ipc_data_ctl *) pkt->data;  	snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); -	snd_ctl_elem_id_set_name(id, ctl->mode == BLUETOOTH_PLAYBACK ? +	snd_ctl_elem_id_set_name(id, ind->mode == BLUETOOTH_PLAYBACK ?  				vol_devices[BLUETOOTH_PLAYBACK] :  				vol_devices[BLUETOOTH_CAPTURE]);  	*event_mask = SND_CTL_EVENT_MASK_VALUE; @@ -290,10 +291,7 @@ static snd_ctl_ext_callback_t bluetooth_callback = {  static int bluetooth_init(struct bluetooth_data *data)  { -	int sk, err, id; -	struct sockaddr_un addr = { -		AF_UNIX, IPC_SOCKET_NAME -	}; +	int sk;  	if (!data)  		return -EINVAL; @@ -302,21 +300,9 @@ static int bluetooth_init(struct bluetooth_data *data)  	data->sock = -1; -	id = abs(getpid() * rand()); - -	if ((sk = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { -		err = -errno; -		SNDERR("Can't open socket"); +	sk = bt_audio_service_open(); +	if (sk < 0)  		return -errno; -	} - -	DBG("Connecting to address: %s", addr.sun_path + 1); -	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -		err = -errno; -		SNDERR("Can't connect socket"); -		close(sk); -		return err; -	}  	data->sock = sk; diff --git a/audio/device.c b/audio/device.c index c86f711d..a5b9b0a9 100644 --- a/audio/device.c +++ b/audio/device.c @@ -450,7 +450,6 @@ static headset_state_t ipc_to_hs_state(uint8_t ipc_state)  		return HEADSET_STATE_DISCONNECTED;  	}  } -#endif  static uint8_t avdtp_to_ipc_state(avdtp_state_t state)  { @@ -504,6 +503,7 @@ uint8_t device_get_state(struct device *dev)  	return STATE_DISCONNECTED;  } +#endif  gboolean device_is_connected(struct device *dev, const char *interface)  { diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c index e605158f..535f6c5e 100644 --- a/audio/gsta2dpsink.c +++ b/audio/gsta2dpsink.c @@ -41,14 +41,6 @@  #include "gsta2dpsink.h" -enum { -        NOT_CONFIGURED, -        CONFIGURING_INIT, -        CONFIGURING_SENT_CONF, -        CONFIGURING_RCVD_DEV_CONF, -        CONFIGURED -}; -  GST_DEBUG_CATEGORY_STATIC(a2dp_sink_debug);  #define GST_CAT_DEFAULT a2dp_sink_debug @@ -62,24 +54,10 @@ GST_DEBUG_CATEGORY_STATIC(a2dp_sink_debug);  		g_mutex_unlock (s->sink_lock);		\  	} G_STMT_END -#define GST_A2DP_SINK_WAIT_CON_END(s) G_STMT_START {			\ -		s->waiting_con_conf = TRUE;				\ -		g_cond_wait (s->con_conf_end, s->sink_lock);		\ -		s->waiting_con_conf = FALSE;				\ -	} G_STMT_END - -#define GST_A2DP_SINK_CONFIGURATION_FAIL(s) G_STMT_START {		\ -		s->con_state = NOT_CONFIGURED;				\ -		g_cond_signal (s->con_conf_end);			\ -	} G_STMT_END - -#define GST_A2DP_SINK_CONFIGURATION_SUCCESS(s) G_STMT_START {		\ -		s->con_state = CONFIGURED;				\ -		g_cond_signal (s->con_conf_end);			\ -	} G_STMT_END  struct bluetooth_data { -	struct ipc_data_cfg cfg;	/* Bluetooth device config */ +	struct bt_getcapabilities_rsp cfg; /* Bluetooth device config */ +	gint link_mtu;  	int samples;			/* Number of encoded samples */  	gchar buffer[BUFFER_SIZE];	/* Codec transfer buffer */  	gsize count;			/* Codec transfer buffer counter */ @@ -121,6 +99,13 @@ static GstStaticPadTemplate a2dp_sink_factory =  				"rate = (int) { 16000, 22050, 24000, 32000, 44100, 48000 }, "  				"channels = (int) [ 1, 2 ]")); +static GIOError gst_a2dp_sink_audioservice_send(GstA2dpSink *self, +					const bt_audio_msg_header_t *msg); +static GIOError gst_a2dp_sink_audioservice_expect(GstA2dpSink *self, +				bt_audio_msg_header_t *outmsg, +				int expected_type); + +  static void gst_a2dp_sink_base_init(gpointer g_class)  {  	GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); @@ -137,8 +122,6 @@ static gboolean gst_a2dp_sink_stop(GstBaseSink *basesink)  	GST_INFO_OBJECT(self, "stop"); -	self->con_state = NOT_CONFIGURED; -  	if (self->watch_id != 0) {  		g_source_remove(self->watch_id);  		self->watch_id = 0; @@ -152,7 +135,7 @@ static gboolean gst_a2dp_sink_stop(GstBaseSink *basesink)  	}  	if (self->server) { -		g_io_channel_close(self->server); +		bt_audio_service_close(g_io_channel_unix_get_fd(self->server));  		g_io_channel_unref(self->server);  		self->server = NULL;  	} @@ -162,9 +145,9 @@ static gboolean gst_a2dp_sink_stop(GstBaseSink *basesink)  		self->data = NULL;  	} -	if (self->sbc) { -		g_free(self->sbc); -		self->sbc = NULL; +	if (self->stream_caps) { +		gst_caps_unref(self->stream_caps); +		self->stream_caps = NULL;  	}  	if (self->dev_caps) { @@ -185,12 +168,6 @@ static void gst_a2dp_sink_finalize(GObject *object)  	if (self->device)  		g_free(self->device); -	/* unlock any thread waiting for this signal */ -	GST_A2DP_SINK_MUTEX_LOCK(self); -	GST_A2DP_SINK_CONFIGURATION_FAIL(self); -	GST_A2DP_SINK_MUTEX_UNLOCK(self); - -	g_cond_free(self->con_conf_end);  	g_mutex_free(self->sink_lock);  	G_OBJECT_CLASS(parent_class)->finalize(object); @@ -232,19 +209,10 @@ static void gst_a2dp_sink_get_property(GObject *object, guint prop_id,  static gint gst_a2dp_sink_bluetooth_recvmsg_fd(GstA2dpSink *sink)  { -	char cmsg_b[CMSG_SPACE(sizeof(int))], m; -	int err, ret, stream_fd; -	struct iovec iov = { &m, sizeof(m) }; -	struct msghdr msgh; -	struct cmsghdr *cmsg; - -	memset(&msgh, 0, sizeof(msgh)); -	msgh.msg_iov = &iov; -	msgh.msg_iovlen = 1; -	msgh.msg_control = &cmsg_b; -	msgh.msg_controllen = CMSG_LEN(sizeof(int)); - -	ret = recvmsg(g_io_channel_unix_get_fd(sink->server), &msgh, 0); +	int err, ret; + +	ret = bt_audio_service_get_data_fd(g_io_channel_unix_get_fd(sink->server)); +  	if (ret < 0) {  		err = errno;  		GST_ERROR_OBJECT(sink, "Unable to receive fd: %s (%d)", @@ -252,76 +220,20 @@ static gint gst_a2dp_sink_bluetooth_recvmsg_fd(GstA2dpSink *sink)  		return -err;  	} -	/* Receive auxiliary data in msgh */ -	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; -			cmsg = CMSG_NXTHDR(&msgh, cmsg)) { -		if (cmsg->cmsg_level == SOL_SOCKET -				&& cmsg->cmsg_type == SCM_RIGHTS) { -			stream_fd = (*(int *) CMSG_DATA(cmsg)); -			sink->stream = g_io_channel_unix_new(stream_fd); - -			GST_DEBUG_OBJECT(sink, "stream_fd=%d", stream_fd); -			return 0; -		} -	} - -	return -EINVAL; -} - -static void gst_a2dp_sink_check_dev_caps(GstA2dpSink *self) -{ -	GstStructure *structure; -	GstCaps *dev_caps; -	gint channels; - -	structure = gst_caps_get_structure(self->dev_caps, 0); -	if (!gst_structure_get_int(structure, "channels", &channels)) -		channels = 2; /* FIXME how to get channels */ -	dev_caps = gst_sbc_caps_from_sbc(&(self->data->cfg), self->sbc, -			channels); - -	self->new_dev_caps = TRUE; -	gst_caps_unref(self->dev_caps); -	self->dev_caps = gst_caps_ref(dev_caps); - - -} - -static int gst_a2dp_sink_bluetooth_a2dp_init(GstA2dpSink *self, -			struct ipc_codec_sbc *sbc) -{ -	struct bluetooth_data *data = self->data; -	struct ipc_data_cfg *cfg = &data->cfg; - -	if (cfg == NULL) { -		GST_ERROR_OBJECT(self, "Error getting codec parameters"); -		return -1; -	} - -	if (cfg->codec != CFG_CODEC_SBC) -		return -1; - -	data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); - -	GST_DEBUG_OBJECT(self, "Codec parameters: " -				"\tallocation=%u\n\tsubbands=%u\n " -				"\tblocks=%u\n\tbitpool=%u\n", -				sbc->allocation, sbc->subbands, -				sbc->blocks, sbc->bitpool); +	sink->stream = g_io_channel_unix_new(ret); +	GST_DEBUG_OBJECT(sink, "stream_fd=%d", ret);  	return 0;  }  static gboolean gst_a2dp_sink_init_pkt_conf(GstA2dpSink *sink,  					GstCaps *caps, -					struct ipc_packet *pkt) +					sbc_capabilities_t *pkt)  { - -	struct ipc_data_cfg *cfg = (void *) pkt->data; -	struct ipc_codec_sbc *sbc = (void *) cfg->data; +	sbc_capabilities_t *cfg = &sink->data->cfg.sbc_capabilities;  	const GValue *value = NULL;  	const char *pref, *name; -	GstStructure *structure = gst_caps_get_structure(caps,0); +	GstStructure *structure = gst_caps_get_structure(caps, 0);  	name = gst_structure_get_name(structure);  	/* FIXME only sbc supported here, should suport mp3 */ @@ -330,26 +242,21 @@ static gboolean gst_a2dp_sink_init_pkt_conf(GstA2dpSink *sink,  		return FALSE;  	} -	if (sink->device) -		strncpy(pkt->device, sink->device, 18); - -	pkt->role = PKT_ROLE_HIFI; -  	value = gst_structure_get_value(structure, "rate"); -	cfg->rate = g_value_get_int(value); +	cfg->frequency = g_value_get_int(value);  	value = gst_structure_get_value(structure, "mode");  	pref = g_value_get_string(value);  	if (strcmp(pref, "auto") == 0) -		cfg->mode = CFG_MODE_AUTO; +		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_AUTO;  	else if (strcmp(pref, "mono") == 0) -		cfg->mode = CFG_MODE_MONO; +		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;  	else if (strcmp(pref, "dual") == 0) -		cfg->mode = CFG_MODE_DUAL_CHANNEL; +		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;  	else if (strcmp(pref, "stereo") == 0) -		cfg->mode = CFG_MODE_STEREO; +		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;  	else if (strcmp(pref, "joint") == 0) -		cfg->mode = CFG_MODE_JOINT_STEREO; +		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;  	else {  		GST_ERROR_OBJECT(sink, "Invalid mode %s", pref);  		return FALSE; @@ -358,107 +265,27 @@ static gboolean gst_a2dp_sink_init_pkt_conf(GstA2dpSink *sink,  	value = gst_structure_get_value(structure, "allocation");  	pref = g_value_get_string(value);  	if (strcmp(pref, "auto") == 0) -		sbc->allocation = CFG_ALLOCATION_AUTO; +		cfg->allocation_method = BT_A2DP_ALLOCATION_AUTO;  	else if (strcmp(pref, "loudness") == 0) -		sbc->allocation = CFG_ALLOCATION_LOUDNESS; +		cfg->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;  	else if (strcmp(pref, "snr") == 0) -		sbc->allocation = CFG_ALLOCATION_SNR; +		cfg->allocation_method = BT_A2DP_ALLOCATION_SNR;  	else {  		GST_ERROR_OBJECT(sink, "Invalid allocation: %s", pref);  		return FALSE;  	}  	value = gst_structure_get_value(structure, "subbands"); -	sbc->subbands = g_value_get_int(value); +	cfg->subbands = g_value_get_int(value);  	value = gst_structure_get_value(structure, "blocks"); -	sbc->blocks = g_value_get_int(value); +	cfg->block_length = g_value_get_int(value); +	/* FIXME min and max ??? */  	value = gst_structure_get_value(structure, "bitpool"); -	sbc->bitpool = g_value_get_int(value); - -	pkt->length = sizeof(*cfg) + sizeof(*sbc); -	pkt->type = PKT_TYPE_CFG_REQ; -	pkt->error = PKT_ERROR_NONE; - -	return TRUE; -} - -static gboolean gst_a2dp_sink_conf_resp(GstA2dpSink *sink) -{ -	gchar buf[IPC_MTU]; -	GIOError io_error; -	gsize ret; -	gint total; -	struct ipc_packet *pkt = (void *) buf; -	struct ipc_data_cfg *cfg = (void *) pkt->data; -	struct ipc_codec_sbc *sbc = (void *) cfg->data; - -	memset(buf, 0, sizeof(buf)); - -	io_error = g_io_channel_read(sink->server, (gchar *) buf, -			sizeof(*pkt) + sizeof(*cfg), &ret); -	if (io_error != G_IO_ERROR_NONE && ret > 0) { -		GST_ERROR_OBJECT(sink, "Error ocurred while receiving " -					"configurarion packet answer"); -		return FALSE; -	} - -	total = ret; -	if (pkt->type != PKT_TYPE_CFG_RSP) { -		GST_ERROR_OBJECT(sink, "Unexpected packet type %d " -					"received", pkt->type); -		return FALSE; -	} - -	if (pkt->error != PKT_ERROR_NONE) { -		GST_ERROR_OBJECT(sink, "Error %d while configuring " -					"device", pkt->error); -		return FALSE; -	} - -	if (cfg->codec != CFG_CODEC_SBC) { -		GST_ERROR_OBJECT(sink, "Unsupported format"); -		return FALSE; -	} - -	io_error = g_io_channel_read(sink->server, (gchar *) sbc, -					sizeof(*sbc), &ret); -	if (io_error != G_IO_ERROR_NONE) { -		GST_ERROR_OBJECT(sink, "Error while reading data from socket " -				"%s (%d)", strerror(errno), errno); -		return FALSE; -	} else if (ret == 0) { -		GST_ERROR_OBJECT(sink, "Read 0 bytes from socket"); -		return FALSE; -	} - -	total += ret; -	GST_DEBUG_OBJECT(sink, "OK - %d bytes received", total); - -	if (pkt->length != (total - sizeof(struct ipc_packet))) { -		GST_ERROR_OBJECT(sink, "Error while configuring device: " -			"packet size doesn't match"); -		return FALSE; -	} - -	memcpy(&sink->data->cfg, cfg, sizeof(*cfg)); -	memcpy(sink->sbc, sbc, sizeof(struct ipc_codec_sbc)); +	cfg->max_bitpool = cfg->min_bitpool = g_value_get_int(value); -	gst_a2dp_sink_check_dev_caps(sink); - -	GST_DEBUG_OBJECT(sink, "Device configuration:\n\tchannel=%p\n\t" -			"fd_opt=%u\n\tpkt_len=%u\n\tsample_size=%u\n\trate=%u", -			sink->stream, sink->data->cfg.fd_opt, -			sink->data->cfg.pkt_len, sink->data->cfg.sample_size, -			sink->data->cfg.rate); - -	if (sink->data->cfg.codec == CFG_CODEC_SBC) { -		/* FIXME is this necessary? */ -		ret = gst_a2dp_sink_bluetooth_a2dp_init(sink, sbc); -		if (ret < 0) -			return FALSE; -	} +	memcpy(pkt, cfg, sizeof(*pkt));  	return TRUE;  } @@ -504,7 +331,7 @@ static gboolean gst_a2dp_sink_conf_recv_stream_fd(GstA2dpSink *self)  	GST_LOG_OBJECT(self, "emptying stream pipe");  	while (1) {  		err = g_io_channel_read(self->stream, data->buffer, -					(gsize) data->cfg.pkt_len, +					(gsize) data->cfg.link_mtu,  					&read);  		if (err != G_IO_ERROR_NONE || read <= 0)  			break; @@ -531,33 +358,6 @@ static gboolean gst_a2dp_sink_conf_recv_stream_fd(GstA2dpSink *self)  	return TRUE;  } -static void gst_a2dp_sink_conf_recv_data(GstA2dpSink *sink) -{ -	/* -	 * We hold the lock, since we can send a signal. -	 * It is a good practice, according to the glib api. -	 */ -	GST_A2DP_SINK_MUTEX_LOCK(sink); - -	switch (sink->con_state) { -	case CONFIGURING_SENT_CONF: -		if (gst_a2dp_sink_conf_resp(sink)) -			sink->con_state = CONFIGURING_RCVD_DEV_CONF; -		else -			GST_A2DP_SINK_CONFIGURATION_FAIL(sink); -		break; -	case CONFIGURING_RCVD_DEV_CONF: -		if (gst_a2dp_sink_conf_recv_stream_fd(sink)) -			GST_A2DP_SINK_CONFIGURATION_SUCCESS(sink); -		else -			GST_A2DP_SINK_CONFIGURATION_FAIL(sink); -		break; -	} - -	GST_A2DP_SINK_MUTEX_UNLOCK(sink); -} - -  static gboolean server_callback(GIOChannel *chan,  					GIOCondition cond, gpointer data)  { @@ -568,16 +368,217 @@ static gboolean server_callback(GIOChannel *chan,  	else if (cond & G_IO_ERR) {  		sink = GST_A2DP_SINK(data);  		GST_WARNING_OBJECT(sink, "Untreated callback G_IO_ERR"); -	} else if (cond & G_IO_IN) { -		sink = GST_A2DP_SINK(data); -		if (sink->con_state != NOT_CONFIGURED && -			sink->con_state != CONFIGURED) -			gst_a2dp_sink_conf_recv_data(sink); -		else -			GST_WARNING_OBJECT(sink, "Unexpected data received"); +	} + +	return TRUE; +} + +static gboolean gst_a2dp_sink_update_caps(GstA2dpSink *self) +{ +	sbc_capabilities_t *sbc = &self->data->cfg.sbc_capabilities; +	GstStructure *structure; +	GValue *value; +	GValue *list; +	gchar *tmp; + +	GST_LOG_OBJECT(self, "updating device caps"); + +	structure = gst_structure_empty_new("audio/x-sbc"); +	value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING); + +	/* mode */ +	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); +	if (sbc->channel_mode == BT_A2DP_CHANNEL_MODE_AUTO) { +		g_value_set_static_string(value, "joint"); +		gst_value_list_prepend_value(list, value); +		g_value_set_static_string(value, "stereo"); +		gst_value_list_prepend_value(list, value); +		g_value_set_static_string(value, "mono"); +		gst_value_list_prepend_value(list, value); +		g_value_set_static_string(value, "dual"); +		gst_value_list_prepend_value(list, value);  	} else { -		sink = GST_A2DP_SINK(data); -		GST_WARNING_OBJECT(sink, "Unexpected callback call"); +		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) { +			g_value_set_static_string(value, "mono"); +			gst_value_list_prepend_value(list, value); +		} +		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) { +			g_value_set_static_string(value, "stereo"); +			gst_value_list_prepend_value(list, value); +		} +		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) { +			g_value_set_static_string(value, "dual"); +			gst_value_list_prepend_value(list, value); +		} +		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) { +			g_value_set_static_string(value, "joint"); +			gst_value_list_prepend_value(list, value); +		} +	} +	g_value_unset(value); +	if (list) { +		gst_structure_set_value(structure, "mode", list); +		g_free(list); +		list = NULL; +	} + +	/* subbands */ +	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); +	value = g_value_init(value, G_TYPE_INT); +	if (sbc->subbands & BT_A2DP_SUBBANDS_4) { +		g_value_set_int(value, 4); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->subbands & BT_A2DP_SUBBANDS_8) { +		g_value_set_int(value, 8); +		gst_value_list_prepend_value(list, value); +	} +	g_value_unset(value); +	if (list) { +		gst_structure_set_value(structure, "subbands", list); +		g_free(list); +		list = NULL; +	} + +	/* blocks */ +	value = g_value_init(value, G_TYPE_INT); +	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); +	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) { +		g_value_set_int(value, 16); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) { +		g_value_set_int(value, 12); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) { +		g_value_set_int(value, 8); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) { +		g_value_set_int(value, 4); +		gst_value_list_prepend_value(list, value); +	} +	g_value_unset(value); +	if (list) { +		gst_structure_set_value(structure, "blocks", list); +		g_free(list); +		list = NULL; +	} + +	/* allocation */ +	g_value_init(value, G_TYPE_STRING); +	list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST); +	if (sbc->allocation_method == BT_A2DP_ALLOCATION_AUTO) { +		g_value_set_static_string(value, "loudness"); +		gst_value_list_prepend_value(list, value); +		g_value_set_static_string(value, "snr"); +		gst_value_list_prepend_value(list, value); +	} else { +		if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) { +			g_value_set_static_string(value, "loudness"); +			gst_value_list_prepend_value(list, value); +		} +		if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) { +			g_value_set_static_string(value, "snr"); +			gst_value_list_prepend_value(list, value); +		} +	} +	g_value_unset(value); +	if (list) { +		gst_structure_set_value(structure, "allocation", list); +		g_free(list); +		list = NULL; +	} + +	/* rate */ +	g_value_init(value, G_TYPE_INT); +	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); +	if (sbc->frequency & BT_A2DP_SAMPLING_FREQ_48000) { +		g_value_set_int(value, 48000); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->frequency & BT_A2DP_SAMPLING_FREQ_44100) { +		g_value_set_int(value, 44100); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->frequency & BT_A2DP_SAMPLING_FREQ_32000) { +		g_value_set_int(value, 32000); +		gst_value_list_prepend_value(list, value); +	} +	if (sbc->frequency & BT_A2DP_SAMPLING_FREQ_16000) { +		g_value_set_int(value, 16000); +		gst_value_list_prepend_value(list, value); +	} +	g_value_unset(value); +	if (list) { +		gst_structure_set_value(structure, "rate", list); +		g_free(list); +		list = NULL; +	} + +	/* bitpool */ +	value = g_value_init(value, GST_TYPE_INT_RANGE); +	gst_value_set_int_range(value, sbc->min_bitpool, sbc->max_bitpool); +	gst_structure_set_value(structure, "bitpool", value); + +	/* channels */ +	gst_value_set_int_range(value, 1, 2); +	gst_structure_set_value(structure, "channels", value); + +	g_free(value); + +	self->dev_caps = gst_caps_new_full(structure, NULL); + +	tmp = gst_caps_to_string(self->dev_caps); +	GST_DEBUG_OBJECT(self, "Device capabilities: %s", tmp); +	g_free(tmp); + +	return TRUE; +} + +static gboolean gst_a2dp_sink_get_capabilities(GstA2dpSink *self) +{ +	gchar *buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_getcapabilities_req *req = (void *) buf; +	struct bt_getcapabilities_rsp *rsp = (void *) buf; +	GIOError io_error; + +	memset(req, 0, BT_AUDIO_IPC_PACKET_SIZE); + +	req->h.msg_type = BT_GETCAPABILITIES_REQ; +	strncpy(req->device, self->device, 18); + +	req->transport = BT_CAPABILITIES_TRANSPORT_A2DP; +	req->access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE; +	io_error = gst_a2dp_sink_audioservice_send(self, &req->h); +	if (io_error != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error while asking device caps"); +	} + +	io_error = gst_a2dp_sink_audioservice_expect(self, &rsp->h, +			BT_GETCAPABILITIES_RSP); +	if (io_error != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error while getting device caps"); +		return FALSE; +	} + +	if (rsp->posix_errno != 0) { +		GST_ERROR_OBJECT(self, "BT_GETCAPABILITIES failed : %s(%d)", +					strerror(rsp->posix_errno), +					rsp->posix_errno); +		return FALSE; +	} + +	if (rsp->transport != BT_CAPABILITIES_TRANSPORT_A2DP) { +		GST_ERROR_OBJECT(self, "Non a2dp answer from device"); +		return FALSE; +	} + +	memcpy(&self->data->cfg, rsp, sizeof(*rsp)); +	if (!gst_a2dp_sink_update_caps(self)) { +		GST_WARNING_OBJECT(self, "failed to update capabilities"); +		return FALSE;  	}  	return TRUE; @@ -586,7 +587,6 @@ static gboolean server_callback(GIOChannel *chan,  static gboolean gst_a2dp_sink_start(GstBaseSink *basesink)  {  	GstA2dpSink *self = GST_A2DP_SINK(basesink); -	struct sockaddr_un addr = { AF_UNIX, IPC_SOCKET_NAME };  	gint sk;  	gint err; @@ -594,107 +594,146 @@ static gboolean gst_a2dp_sink_start(GstBaseSink *basesink)  	self->watch_id = 0; -	sk = socket(PF_LOCAL, SOCK_STREAM, 0); -	if (sk < 0) { +	sk = bt_audio_service_open(); +	if (sk <= 0) {  		err = errno; -		GST_ERROR_OBJECT(self, "Cannot open socket: %s (%d)", -			strerror(err), err); -		return FALSE; -	} - -	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -		err = errno; -		GST_ERROR_OBJECT(self, "Connection fail %s (%d)", -			strerror(err), err); -		close(sk); -		return FALSE; +		GST_ERROR_OBJECT(self, "Cannot open connection to bt " +			"audio service: %s %d", strerror(err), err); +		goto failed;  	}  	self->server = g_io_channel_unix_new(sk); - -	self->watch_id = g_io_add_watch(self->server, G_IO_IN | G_IO_HUP | -			G_IO_ERR | G_IO_NVAL, server_callback, self); +	self->watch_id = g_io_add_watch(self->server, G_IO_HUP | G_IO_ERR | +					G_IO_NVAL, server_callback, self);  	self->data = g_new0(struct bluetooth_data, 1);  	memset(self->data, 0, sizeof(struct bluetooth_data)); -	self->sbc = g_new0(struct ipc_codec_sbc, 1); -  	self->stream = NULL; -	self->con_state = NOT_CONFIGURED; -	self->new_dev_caps = FALSE; -	self->dev_caps = NULL; +	self->stream_caps = NULL; -	self->waiting_con_conf = FALSE; +	if (!gst_a2dp_sink_get_capabilities(self)) +		goto failed;  	return TRUE; + +failed: +	bt_audio_service_close(sk); +	return FALSE;  } -static gboolean gst_a2dp_sink_send_conf_pkt(GstA2dpSink *sink, GstCaps *caps) +static gboolean gst_a2dp_sink_stream_start(GstA2dpSink *self)  { -	gchar buf[IPC_MTU]; -	struct ipc_packet *pkt = (void *) buf; -	gboolean ret; -	gsize bytes_sent; +	gchar buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_streamstart_req *req = (void *) buf; +	struct bt_streamstart_rsp *rsp = (void *) buf; +	struct bt_datafd_ind *ind = (void*) buf;  	GIOError io_error; -	g_assert(sink->con_state == NOT_CONFIGURED); +	GST_DEBUG_OBJECT(self, "stream start"); -	memset (pkt, 0, sizeof(buf)); -	ret = gst_a2dp_sink_init_pkt_conf(sink, caps, pkt); -	if (!ret) { -		GST_ERROR_OBJECT(sink, "Couldn't initialize parse caps " -				"to packet configuration"); +	memset (req, 0, sizeof(buf)); +	req->h.msg_type = BT_STREAMSTART_REQ; + +	io_error = gst_a2dp_sink_audioservice_send(self, &req->h); +	if (io_error != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error ocurred while sending " +					"start packet");  		return FALSE;  	} -	sink->con_state = CONFIGURING_INIT; +	GST_DEBUG_OBJECT(self, "stream start packet sent"); -	io_error = g_io_channel_write(sink->server, (gchar *) pkt, -			sizeof(*pkt) + pkt->length, &bytes_sent); +	io_error = gst_a2dp_sink_audioservice_expect(self, &rsp->h, +			BT_STREAMSTART_RSP);  	if (io_error != G_IO_ERROR_NONE) { -		GST_ERROR_OBJECT(sink, "Error ocurred while sending " -					"configurarion packet"); -		sink->con_state = NOT_CONFIGURED; +		GST_ERROR_OBJECT(self, "Error while stream start confirmation"); +		return FALSE; +	} + +	if (rsp->posix_errno != 0) { +		GST_ERROR_OBJECT(self, "BT_STREAMSTART_RSP failed : %s(%d)", +					strerror(rsp->posix_errno), +					rsp->posix_errno); +		return FALSE; +	} + +	GST_DEBUG_OBJECT(self, "stream started"); + +	io_error = gst_a2dp_sink_audioservice_expect(self, &ind->h, +			BT_STREAMFD_IND); +	if (io_error != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error while receiving stream fd");  		return FALSE;  	} -	GST_DEBUG_OBJECT(sink, "%d bytes sent", bytes_sent); -	sink->con_state = CONFIGURING_SENT_CONF; +	if (!gst_a2dp_sink_conf_recv_stream_fd(self)) +		return FALSE;  	return TRUE;  } -static gboolean gst_a2dp_sink_start_dev_conf(GstA2dpSink *sink, GstCaps *caps) +static gboolean gst_a2dp_sink_configure(GstA2dpSink *self, GstCaps *caps)  { +	gchar buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_setconfiguration_req *req = (void *) buf; +	struct bt_setconfiguration_rsp *rsp = (void *) buf;  	gboolean ret; +	GIOError io_error; + +	GST_DEBUG_OBJECT(self, "configuring device"); + +	memset (req, 0, sizeof(buf)); +	req->h.msg_type = BT_SETCONFIGURATION_REQ; +	strncpy(req->device, self->device, 18); +	ret = gst_a2dp_sink_init_pkt_conf(self, caps, &req->sbc_capabilities); +	if (!ret) { +		GST_ERROR_OBJECT(self, "Couldn't parse caps " +				"to packet configuration"); +		return FALSE; +	} -	g_assert(sink->con_state == NOT_CONFIGURED); +	io_error = gst_a2dp_sink_audioservice_send(self, &req->h); +	if (io_error != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error ocurred while sending " +					"configurarion packet"); +		return FALSE; +	} -	GST_DEBUG_OBJECT(sink, "starting device configuration"); +	GST_DEBUG_OBJECT(self, "configuration packet sent"); -	ret = gst_a2dp_sink_send_conf_pkt(sink, caps); +	io_error = gst_a2dp_sink_audioservice_expect(self, &rsp->h, +			BT_SETCONFIGURATION_RSP); +	if (io_error != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error while receiving device confirmation"); +		return FALSE; +	} -	return ret; +	if (rsp->posix_errno != 0) { +		GST_ERROR_OBJECT(self, "BT_SETCONFIGURATION_RSP failed : %s(%d)", +					strerror(rsp->posix_errno), +					rsp->posix_errno); +		return FALSE; +	} + +	GST_DEBUG_OBJECT(self, "configuration set"); + +	return TRUE;  }  static GstFlowReturn gst_a2dp_sink_preroll(GstBaseSink *basesink,  					GstBuffer *buffer)  {  	GstA2dpSink *sink = GST_A2DP_SINK(basesink); +	gboolean ret;  	GST_A2DP_SINK_MUTEX_LOCK(sink); -	if (sink->con_state == NOT_CONFIGURED) -		gst_a2dp_sink_start_dev_conf(sink, GST_BUFFER_CAPS(buffer)); - -	/* wait for the connection process to finish */ -	if (sink->con_state != CONFIGURED) -		GST_A2DP_SINK_WAIT_CON_END(sink); +	ret = gst_a2dp_sink_stream_start(sink);  	GST_A2DP_SINK_MUTEX_UNLOCK(sink); -	if (sink->con_state != CONFIGURED) +	if (!ret)  		return GST_FLOW_ERROR;  	return GST_FLOW_OK; @@ -745,7 +784,7 @@ static GstFlowReturn gst_a2dp_sink_render(GstBaseSink *basesink,  	encoded = GST_BUFFER_SIZE(buffer); -	if (data->count + encoded >= data->cfg.pkt_len) { +	if (data->count + encoded >= data->cfg.link_mtu) {  		ret = gst_a2dp_sink_avdtp_write(self);  		if (ret < 0)  			return GST_FLOW_ERROR; @@ -758,24 +797,28 @@ static GstFlowReturn gst_a2dp_sink_render(GstBaseSink *basesink,  	return GST_FLOW_OK;  } +static GstCaps* gst_a2dp_sink_get_caps(GstBaseSink *basesink) +{ +	GstA2dpSink *self = GST_A2DP_SINK(basesink); + +	return self->dev_caps ? gst_caps_ref(self->dev_caps): NULL; +} +  static gboolean gst_a2dp_sink_set_caps(GstBaseSink *basesink, GstCaps *caps)  {  	GstA2dpSink *self = GST_A2DP_SINK(basesink); +	gboolean ret;  	GST_A2DP_SINK_MUTEX_LOCK(self); -	if (self->con_state == NOT_CONFIGURED) { -		gst_a2dp_sink_start_dev_conf(self, caps); +	ret = gst_a2dp_sink_configure(self, caps); -		if (self->dev_caps) -			gst_caps_unref(self->dev_caps); -		self->dev_caps = gst_caps_ref(caps); +	if (self->stream_caps) +		gst_caps_unref(self->stream_caps); +	self->stream_caps = gst_caps_ref(caps); -		/* we suppose the device will accept this caps */ -		self->new_dev_caps = FALSE; -	}  	GST_A2DP_SINK_MUTEX_UNLOCK(self); -	return TRUE; +	return ret;  }  static gboolean gst_a2dp_sink_unlock(GstBaseSink *basesink) @@ -800,12 +843,7 @@ static GstFlowReturn gst_a2dp_sink_buffer_alloc(GstBaseSink *basesink,  		return GST_FLOW_ERROR;  	} -	if (self->new_dev_caps && self->dev_caps) { -		GST_INFO_OBJECT(self, "new caps from device"); -		gst_buffer_set_caps(*buf, self->dev_caps); -		self->new_dev_caps = FALSE; -	} else -		gst_buffer_set_caps(*buf, caps); +	gst_buffer_set_caps(*buf, caps);  	GST_BUFFER_OFFSET(*buf) = offset; @@ -830,6 +868,7 @@ static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass)  	basesink_class->render = GST_DEBUG_FUNCPTR(gst_a2dp_sink_render);  	basesink_class->preroll = GST_DEBUG_FUNCPTR(gst_a2dp_sink_preroll);  	basesink_class->set_caps = GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps); +	basesink_class->get_caps = GST_DEBUG_FUNCPTR(gst_a2dp_sink_get_caps);  	basesink_class->unlock = GST_DEBUG_FUNCPTR(gst_a2dp_sink_unlock);  	basesink_class->buffer_alloc =  		GST_DEBUG_FUNCPTR(gst_a2dp_sink_buffer_alloc); @@ -847,12 +886,79 @@ static void gst_a2dp_sink_init(GstA2dpSink *self, GstA2dpSinkClass *klass)  {  	self->device = NULL;  	self->data = NULL; -	self->sbc = NULL;  	self->stream = NULL; -	self->con_state = NOT_CONFIGURED; -	self->con_conf_end = g_cond_new(); -	self->waiting_con_conf = FALSE; +	self->dev_caps = NULL; +  	self->sink_lock = g_mutex_new();  } + +static GIOError gst_a2dp_sink_audioservice_send(GstA2dpSink *self, +					const bt_audio_msg_header_t *msg) +{ +	gint err; +	GIOError error; +	gsize written; + +	GST_DEBUG_OBJECT(self, "sending %s", bt_audio_strmsg(msg->msg_type)); + +	error = g_io_channel_write(self->server, (const gchar*) msg, +			BT_AUDIO_IPC_PACKET_SIZE, &written); +	if (error != G_IO_ERROR_NONE) { +		err = errno; +		GST_ERROR_OBJECT(self, "Error sending data to audio service:" +			" %s(%d)", strerror(err), err); +	} + +	return error; +} + +static GIOError gst_a2dp_sink_audioservice_recv(GstA2dpSink *self, +					bt_audio_msg_header_t *inmsg) +{ +	GIOError status; +	gsize bytes_read; +	const char *type; + +	status = g_io_channel_read(self->server, (gchar*) inmsg, +			BT_AUDIO_IPC_PACKET_SIZE, &bytes_read); +	if (status != G_IO_ERROR_NONE) { +		GST_ERROR_OBJECT(self, "Error receiving data from service"); +		return status; +	} + +	type = bt_audio_strmsg(inmsg->msg_type); +	if (!type) { +		GST_ERROR_OBJECT(self, "Bogus message type %d " +				"received from audio service", +				inmsg->msg_type); +		return G_IO_ERROR_INVAL; +	} + +	GST_DEBUG_OBJECT(self, "Received %s", type); + +	return status; +} + +static GIOError gst_a2dp_sink_audioservice_expect(GstA2dpSink *self, +					bt_audio_msg_header_t *outmsg, +					int expected_type) +{ +	GIOError status; + +	status = gst_a2dp_sink_audioservice_recv(self, outmsg); +	if (status != G_IO_ERROR_NONE) +		return status; + +	if (outmsg->msg_type != expected_type) { +		GST_ERROR_OBJECT(self, "Bogus message %s " +				"received while %s was expected", +				bt_audio_strmsg(outmsg->msg_type), +				bt_audio_strmsg(expected_type)); +		return G_IO_ERROR_INVAL; +	} + +	return status; +} + diff --git a/audio/gsta2dpsink.h b/audio/gsta2dpsink.h index ea750406..f5b9b69b 100644 --- a/audio/gsta2dpsink.h +++ b/audio/gsta2dpsink.h @@ -49,15 +49,13 @@ struct _GstA2dpSink {  	GIOChannel *stream;  	struct bluetooth_data *data; -	struct ipc_codec_sbc *sbc;  	GIOChannel *server; -	gint con_state; +	/* stream connection data */ +	GstCaps *stream_caps; +  	GstCaps *dev_caps; -	gboolean new_dev_caps; -	GCond *con_conf_end; -	gboolean waiting_con_conf;  	GMutex *sink_lock;  	guint watch_id; diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 54bb7f8a..021ecacf 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -27,14 +27,17 @@  #include <string.h> +#include "ipc.h"  #include "gstsbcenc.h"  #include "gstsbcutil.h" -#define SBC_ENC_DEFAULT_MODE CFG_MODE_AUTO -#define SBC_ENC_DEFAULT_BLOCKS 16 -#define SBC_ENC_DEFAULT_SUB_BANDS 8 -#define SBC_ENC_DEFAULT_BITPOOL 53 -#define SBC_ENC_DEFAULT_ALLOCATION CFG_ALLOCATION_AUTO +#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_AUTO +#define SBC_ENC_DEFAULT_BLOCKS 0 +#define SBC_ENC_DEFAULT_SUB_BANDS 0 +#define SBC_ENC_DEFAULT_BITPOOL 0 +#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_AUTO +#define SBC_ENC_DEFAULT_RATE 0 +#define SBC_ENC_DEFAULT_CHANNELS 0  GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug);  #define GST_CAT_DEFAULT sbc_enc_debug @@ -65,9 +68,9 @@ static GType gst_sbc_allocation_get_type(void)  {  	static GType sbc_allocation_type = 0;  	static GEnumValue sbc_allocations[] = { -		{ CFG_ALLOCATION_AUTO,		"Auto",		"auto" }, -		{ CFG_ALLOCATION_LOUDNESS,	"Loudness",	"loudness" }, -		{ CFG_ALLOCATION_SNR,		"SNR",		"snr" }, +		{ BT_A2DP_ALLOCATION_AUTO,	"Auto",		"auto" }, +		{ BT_A2DP_ALLOCATION_LOUDNESS,	"Loudness",	"loudness" }, +		{ BT_A2DP_ALLOCATION_SNR,	"SNR",		"snr" },  		{ -1, NULL, NULL}  	}; @@ -115,73 +118,193 @@ static GstStaticPadTemplate sbc_enc_src_factory =  				"allocation = (string) { snr, loudness },"  				"bitpool = (int) [ 2, 64 ]")); -static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) +gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps); + +static void sbc_enc_set_structure_int_param(GstSbcEnc *enc, +			GstStructure *structure, const gchar* field, +			gint field_value) +{ +	GValue *value; + +	value = g_new0(GValue,1); +	value = g_value_init(value, G_TYPE_INT); +	g_value_set_int(value, field_value); +	gst_structure_set_value(structure, field, value); +	g_free(value); +} + +static void sbc_enc_set_structure_string_param(GstSbcEnc *enc, +			GstStructure *structure, const gchar* field, +			const gchar* field_value) +{ +	GValue *value; + +	value = g_new0(GValue,1); +	value = g_value_init(value, G_TYPE_STRING); +	g_value_set_string(value, field_value); +	gst_structure_set_value(structure, field, value); +	g_free(value); +} + +static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc)  { -	gint rate; -	gint channels;  	GstCaps* src_caps;  	GstStructure *structure; -	const gchar *mode; -	const gchar *allocation; +	GEnumValue *enum_value; +	GEnumClass *enum_class; +	gchar* temp; + +	src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad)); +	structure = gst_caps_get_structure(src_caps, 0); + +	if (enc->rate != 0) +		sbc_enc_set_structure_int_param(enc, structure, "rate", +			enc->rate); + +	if (enc->channels != 0) +		sbc_enc_set_structure_int_param(enc, structure, "channels", +			enc->channels); + +	if (enc->subbands != 0) +		sbc_enc_set_structure_int_param(enc, structure, "subbands", +			enc->subbands); + +	if (enc->blocks != 0) +		sbc_enc_set_structure_int_param(enc, structure, "blocks", +			enc->blocks); + +	if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { +		enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); +		enum_value = g_enum_get_value(enum_class, enc->mode); +		sbc_enc_set_structure_string_param(enc, structure, "mode", +			enum_value->value_nick); +		g_type_class_unref(enum_class); +	} -	structure = gst_caps_get_structure(caps, 0); +	if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) { +		enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION); +		enum_value = g_enum_get_value(enum_class, enc->allocation); +		sbc_enc_set_structure_string_param(enc, structure, "allocation", +			enum_value->value_nick); +		g_type_class_unref(enum_class); +	} -	if (!gst_structure_get_int (structure, "rate", &rate)) -		return NULL; -	if (!gst_structure_get_int (structure, "channels", &channels)) +	temp = gst_caps_to_string(src_caps); +	GST_DEBUG_OBJECT(enc, "Srcpad caps: %s", temp); +	g_free(temp); + +	return src_caps; +} + +static GstCaps* sbc_enc_src_getcaps (GstPad * pad) +{ +	GstSbcEnc *enc; + +	enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); + +	return sbc_enc_generate_srcpad_caps(enc); +} + +static gboolean sbc_enc_src_setcaps (GstPad *pad, GstCaps *caps) +{ +	GstCaps* srcpad_caps; +	GstCaps* temp_caps; +	gboolean res = TRUE; +	GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); + +	GST_LOG_OBJECT(enc, "setting srcpad caps"); + +	srcpad_caps = sbc_enc_generate_srcpad_caps(enc); +	temp_caps = gst_caps_intersect(srcpad_caps, caps); +	if (temp_caps == GST_CAPS_NONE) +		res = FALSE; + +	gst_caps_unref(temp_caps); +	gst_caps_unref(srcpad_caps); + +	g_return_val_if_fail(res, FALSE); + +	return gst_sbc_enc_fill_sbc_params(enc, caps); +} + +static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) +{ + +	gchar *error_message = NULL; +	GstCaps* result; + +	result = gst_sbc_util_caps_fixate(caps, &error_message); + +	if (!result) { +		GST_ERROR_OBJECT (enc, "Invalid input caps caused parsing " +				"error: %s", error_message); +		g_free(error_message);  		return NULL; +	} -	enc->sbc.rate = rate; -	enc->sbc.channels = channels; +	return result; +} -	if (enc->mode == CFG_MODE_AUTO) -		enc->mode = CFG_MODE_JOINT_STEREO; +static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) +{ +	GstCaps *peer_caps; +	GstCaps *src_caps; +	GstCaps *caps; +	gboolean res = TRUE; +	GstCaps *result_caps = NULL; + +	peer_caps = gst_pad_peer_get_caps(enc->srcpad); +	if (!peer_caps) +		return NULL; -	if (enc->mode == CFG_MODE_MONO || enc->mode == CFG_MODE_JOINT_STEREO) -		enc->sbc.joint = 1; +	src_caps = sbc_enc_generate_srcpad_caps(enc); +	caps = gst_caps_intersect(src_caps, peer_caps); -	enc->sbc.blocks = enc->blocks; -	enc->sbc.subbands = enc->subbands; -	if (enc->allocation == 0) -		enc->sbc.allocation = CFG_ALLOCATION_LOUDNESS; -	else -		enc->sbc.allocation = enc->allocation; +	if (caps == GST_CAPS_NONE || gst_caps_is_empty(caps)) { +		res = FALSE; +		goto done; +	} -	enc->sbc.bitpool = SBC_ENC_DEFAULT_BITPOOL; +	result_caps = sbc_enc_src_caps_fixate(enc, caps); -	mode = gst_sbc_get_mode_string(enc->sbc.joint); -	allocation = gst_sbc_get_allocation_string(enc->sbc.allocation); +done: -	src_caps = gst_caps_new_simple("audio/x-sbc", -					"rate", G_TYPE_INT, enc->sbc.rate, -					"channels", G_TYPE_INT, enc->sbc.channels, -					"mode", G_TYPE_STRING, mode, -					"subbands", G_TYPE_INT, enc->sbc.subbands, -					"blocks", G_TYPE_INT, enc->sbc.blocks, -					"allocation", G_TYPE_STRING, allocation, -					"bitpool", G_TYPE_INT, enc->sbc.bitpool, -					NULL); +	gst_caps_unref(src_caps); +	gst_caps_unref(peer_caps); +	gst_caps_unref(caps); -	return src_caps; +	if (!res) +		return NULL; + +	return result_caps;  }  static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps)  {  	GstSbcEnc *enc;  	GstStructure *structure; -	GstCaps *othercaps; +	GstCaps *src_caps; +	gint rate, channels; +	gboolean res;  	enc = GST_SBC_ENC(GST_PAD_PARENT (pad));  	structure = gst_caps_get_structure(caps, 0); -	othercaps = sbc_enc_generate_srcpad_caps(enc, caps); -	if (othercaps == NULL) +	if (!gst_structure_get_int(structure, "rate", &rate)) +		goto error; +	if (!gst_structure_get_int(structure, "channels", &channels))  		goto error; -	gst_pad_set_caps (enc->srcpad, othercaps); -	gst_caps_unref(othercaps); +	enc->rate = rate; +	enc->channels = channels; -	return TRUE; +	src_caps = sbc_enc_get_fixed_srcpad_caps(enc); +	if (!src_caps) +		goto error; +	res = gst_pad_set_caps(enc->srcpad, src_caps); +	gst_caps_unref(src_caps); + +	return res;  error:  	GST_ERROR_OBJECT (enc, "invalid input caps"); @@ -215,14 +338,13 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps)  	if (!(allocation = gst_structure_get_string(structure, "allocation")))  		return FALSE; -	sbc_reinit(&enc->sbc, 0); -	enc->sbc.rate = rate; -	enc->sbc.channels = channels; -	enc->blocks = blocks; -	enc->sbc.subbands = subbands; +	enc->rate = enc->sbc.rate = rate; +	enc->channels = enc->sbc.channels = channels; +	enc->blocks = enc->sbc.blocks = blocks; +	enc->subbands = enc->sbc.subbands = subbands;  	enc->sbc.bitpool = bitpool; -	enc->mode = gst_sbc_get_mode_int(mode); -	enc->allocation = gst_sbc_get_allocation_mode_int(allocation); +	enc->mode = enc->sbc.joint = gst_sbc_get_mode_int(mode); +	enc->allocation = enc->sbc.allocation = gst_sbc_get_allocation_mode_int(allocation);  	return TRUE;  } @@ -291,11 +413,8 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer)  		GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer);  		res = gst_pad_push(enc->srcpad, output); -		if (res != GST_FLOW_OK) { -			GST_ERROR_OBJECT(enc, "pad pushing failed"); +		if (res != GST_FLOW_OK)  			goto done; -		} -  	}  done: @@ -350,12 +469,30 @@ static void gst_sbc_enc_base_init(gpointer g_class)  	gst_element_class_set_details(element_class, &sbc_enc_details);  } +static gboolean sbc_enc_set_blocks(GstSbcEnc *enc, gint value) +{ +	if (value != 4 && value != 8 && value != 12 && +			value != 16 && value != 0) +		return FALSE; +	enc->blocks = value; +	return TRUE; +} + +static gboolean sbc_enc_set_subbands(GstSbcEnc *enc, gint value) +{ +	if (value != 4 && value != 8 && value != 0) +		return FALSE; +	enc->subbands = value; +	return TRUE; +} +  static void gst_sbc_enc_set_property(GObject *object, guint prop_id,  					const GValue *value, GParamSpec *pspec)  {  	GstSbcEnc *enc = GST_SBC_ENC(object); -	/* TODO - CAN ONLY BE CHANGED ON READY AND BELOW */ +	/* changes to those properties will only happen on the next caps +	 * negotiation */  	switch (prop_id) {  	case PROP_MODE: @@ -365,12 +502,14 @@ static void gst_sbc_enc_set_property(GObject *object, guint prop_id,  		enc->allocation = g_value_get_enum(value);  		break;  	case PROP_BLOCKS: -		/* TODO - verify consistency */ -		enc->blocks = g_value_get_int(value); +		if (!sbc_enc_set_blocks(enc, g_value_get_int(value))) +			GST_WARNING_OBJECT(enc, "invalid value %d for " +				"blocks property", g_value_get_int(value));  		break;  	case PROP_SUBBANDS: -		/* TODO - verify consistency */ -		enc->subbands = g_value_get_int(value); +		if (!sbc_enc_set_subbands(enc, g_value_get_int(value))) +			GST_WARNING_OBJECT(enc, "invalid value %d for " +				"subbands property", g_value_get_int(value));  		break;  	default:  		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -428,7 +567,7 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass)  	g_object_class_install_property(object_class, PROP_BLOCKS,  			g_param_spec_int("blocks", "Blocks",  				"Blocks", 0, G_MAXINT, -				SBC_ENC_DEFAULT_BLOCKS,	G_PARAM_READWRITE)); +				SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE));  	g_object_class_install_property(object_class, PROP_SUBBANDS,  			g_param_spec_int("subbands", "Sub Bands", @@ -447,13 +586,18 @@ static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass)  	gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);  	self->srcpad = gst_pad_new_from_static_template(&sbc_enc_src_factory, "src"); -	gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); +	gst_pad_set_getcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps)); +	gst_pad_set_setcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps));  	gst_element_add_pad(GST_ELEMENT(self), self->srcpad); +	gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); +  	self->subbands = SBC_ENC_DEFAULT_SUB_BANDS;  	self->blocks = SBC_ENC_DEFAULT_BLOCKS;  	self->mode = SBC_ENC_DEFAULT_MODE;  	self->allocation = SBC_ENC_DEFAULT_ALLOCATION; +	self->rate = SBC_ENC_DEFAULT_RATE; +	self->channels = SBC_ENC_DEFAULT_CHANNELS;  	self->adapter = gst_adapter_new();  } diff --git a/audio/gstsbcenc.h b/audio/gstsbcenc.h index c5fc6bcc..f65bcc94 100644 --- a/audio/gstsbcenc.h +++ b/audio/gstsbcenc.h @@ -25,8 +25,6 @@  #include <gst/base/gstadapter.h>  #include "sbc.h" -#include "ipc.h" -  G_BEGIN_DECLS @@ -51,6 +49,8 @@ struct _GstSbcEnc {  	GstPad *srcpad;  	GstAdapter *adapter; +	gint rate; +	gint channels;  	gint mode;  	gint blocks;  	gint allocation; diff --git a/audio/gstsbcparse.c b/audio/gstsbcparse.c index 185cda03..bae7d623 100644 --- a/audio/gstsbcparse.c +++ b/audio/gstsbcparse.c @@ -57,6 +57,7 @@ static GstStaticPadTemplate sbc_parse_src_factory =  				"bitpool = (int) [ 2, 64 ]"));  /* Creates a fixed caps from the caps given. */ +/* FIXME use gstsbcutil caps fixating function */  static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  {  	GstCaps *result; @@ -67,6 +68,11 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  	const gchar* allocation = NULL;  	const gchar* mode = NULL;  	const gchar* error_message = NULL; +	gchar* str; + +	str = gst_caps_to_string(caps); +	GST_DEBUG_OBJECT(parse, "Parsing caps: %s", str); +	g_free(str);  	structure = gst_caps_get_structure(caps, 0); @@ -76,11 +82,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "rate"); -		if (GST_VALUE_HOLDS_LIST(value)) { +		if (GST_VALUE_HOLDS_LIST(value))  			temp = gst_sbc_select_rate_from_list(value); -		} else { +		else  			temp = g_value_get_int(value); -		}  		rate = temp;  	} @@ -90,11 +95,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "channels"); -		if (GST_VALUE_HOLDS_INT_RANGE(value)) { +		if (GST_VALUE_HOLDS_INT_RANGE(value))  			temp = gst_sbc_select_channels_from_range(value); -		} else { +		else  			temp = g_value_get_int(value); -		}  		channels = temp;  	} @@ -104,11 +108,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "blocks"); -		if (GST_VALUE_HOLDS_LIST(value)) { +		if (GST_VALUE_HOLDS_LIST(value))  			temp = gst_sbc_select_blocks_from_list(value); -		} else { +		else  			temp = g_value_get_int(value); -		}  		blocks = temp;  	} @@ -118,11 +121,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "subbands"); -		if (GST_VALUE_HOLDS_LIST(value)) { +		if (GST_VALUE_HOLDS_LIST(value))  			temp = gst_sbc_select_subbands_from_list(value); -		} else { +		else  			temp = g_value_get_int(value); -		}  		subbands = temp;  	} @@ -132,11 +134,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "bitpool"); -		if (GST_VALUE_HOLDS_INT_RANGE(value)) { +		if (GST_VALUE_HOLDS_INT_RANGE(value))  			temp = gst_sbc_select_bitpool_from_range(value); -		} else { +		else  			temp = g_value_get_int(value); -		}  		bitpool = temp;  	} @@ -146,11 +147,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "allocation"); -		if (GST_VALUE_HOLDS_LIST(value)) { +		if (GST_VALUE_HOLDS_LIST(value))  			allocation = gst_sbc_get_allocation_from_list(value); -		} else { +		else  			allocation = g_value_get_string(value); -		}  	}  	if (!gst_structure_has_field(structure, "mode")) { @@ -159,11 +159,10 @@ static GstCaps* sbc_parse_select_caps(GstSbcParse *parse, GstCaps *caps)  		goto error;  	} else {  		value = gst_structure_get_value(structure, "mode"); -		if (GST_VALUE_HOLDS_LIST(value)) { +		if (GST_VALUE_HOLDS_LIST(value))  			mode = gst_sbc_get_mode_from_list(value); -		} else { +		else  			mode = g_value_get_string(value); -		}  	}  error: @@ -205,9 +204,15 @@ static gboolean sbc_parse_sink_setcaps(GstPad * pad, GstCaps * caps)  		other = gst_caps_new_any();  	inter = gst_caps_intersect(caps, other); +	if (gst_caps_is_empty(inter)) { +		gst_caps_unref(inter); +		return FALSE; +	}  	srccaps = sbc_parse_select_caps(parse, inter); -	if (srccaps == NULL) +	if (srccaps == NULL) { +		gst_caps_unref(inter);  		return FALSE; +	}  	gst_pad_set_caps(parse->srcpad, srccaps); diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c index 1d7a1227..f2351e6b 100644 --- a/audio/gstsbcutil.c +++ b/audio/gstsbcutil.c @@ -99,11 +99,11 @@ const gchar *gst_sbc_get_mode_from_list(const GValue *value)  gint gst_sbc_get_allocation_mode_int(const gchar *allocation)  {  	if (g_ascii_strcasecmp(allocation, "loudness") == 0) -		return CFG_ALLOCATION_LOUDNESS; +		return BT_A2DP_ALLOCATION_LOUDNESS;  	else if (g_ascii_strcasecmp(allocation, "snr") == 0) -		return CFG_ALLOCATION_SNR; +		return BT_A2DP_ALLOCATION_SNR;  	else if (g_ascii_strcasecmp(allocation, "auto") == 0) -		return CFG_ALLOCATION_AUTO; +		return BT_A2DP_ALLOCATION_AUTO;  	else  		return -1;  } @@ -111,15 +111,15 @@ gint gst_sbc_get_allocation_mode_int(const gchar *allocation)  gint gst_sbc_get_mode_int(const gchar *mode)  {  	if (g_ascii_strcasecmp(mode, "joint") == 0) -		return CFG_MODE_JOINT_STEREO; +		return BT_A2DP_CHANNEL_MODE_JOINT_STEREO;  	else if (g_ascii_strcasecmp(mode, "stereo") == 0) -		return CFG_MODE_STEREO; +		return BT_A2DP_CHANNEL_MODE_STEREO;  	else if (g_ascii_strcasecmp(mode, "dual") == 0) -		return CFG_MODE_DUAL_CHANNEL; +		return BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;  	else if (g_ascii_strcasecmp(mode, "mono") == 0) -		return CFG_MODE_MONO; +		return BT_A2DP_CHANNEL_MODE_MONO;  	else if (g_ascii_strcasecmp(mode, "auto") == 0) -		return CFG_MODE_AUTO; +		return BT_A2DP_CHANNEL_MODE_AUTO;  	else  		return -1;  } @@ -127,15 +127,15 @@ gint gst_sbc_get_mode_int(const gchar *mode)  const gchar *gst_sbc_get_mode_string(int joint)  {  	switch (joint) { -	case CFG_MODE_MONO: +	case BT_A2DP_CHANNEL_MODE_MONO:  		return "mono"; -	case CFG_MODE_DUAL_CHANNEL: +	case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:  		return "dual"; -	case CFG_MODE_STEREO: +	case BT_A2DP_CHANNEL_MODE_STEREO:  		return "stereo"; -	case CFG_MODE_JOINT_STEREO: +	case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:  		return "joint"; -	case CFG_MODE_AUTO: +	case BT_A2DP_CHANNEL_MODE_AUTO:  		return NULL; /* TODO what should be selected here? */  	default:  		return NULL; @@ -145,37 +145,165 @@ const gchar *gst_sbc_get_mode_string(int joint)  const gchar *gst_sbc_get_allocation_string(int alloc)  {  	switch (alloc) { -	case CFG_ALLOCATION_LOUDNESS: +	case BT_A2DP_ALLOCATION_LOUDNESS:  		return "loudness"; -	case CFG_ALLOCATION_SNR: +	case BT_A2DP_ALLOCATION_SNR:  		return "snr"; -	case CFG_ALLOCATION_AUTO: +	case BT_A2DP_ALLOCATION_AUTO:  		return "loudness"; /* TODO what should be selected here? */  	default:  		return NULL;  	}  } -GstCaps* gst_sbc_caps_from_sbc(struct ipc_data_cfg *cfg, -		struct ipc_codec_sbc *sbc, gint channels) +GstCaps* gst_sbc_caps_from_sbc(sbc_capabilities_t *sbc, gint channels)  {  	GstCaps *caps;  	const gchar *mode_str;  	const gchar *allocation_str; -	mode_str = gst_sbc_get_mode_string(cfg->mode); -	allocation_str = gst_sbc_get_allocation_string(sbc->allocation); +	mode_str = gst_sbc_get_mode_string(sbc->channel_mode); +	allocation_str = gst_sbc_get_allocation_string(sbc->allocation_method);  	caps = gst_caps_new_simple("audio/x-sbc", -				"rate", G_TYPE_INT, cfg->rate, +				"rate", G_TYPE_INT, sbc->frequency,  				"channels", G_TYPE_INT, channels,  				"mode", G_TYPE_STRING, mode_str,  				"subbands", G_TYPE_INT, sbc->subbands, -				"blocks", G_TYPE_INT, sbc->blocks, +				"blocks", G_TYPE_INT, sbc->block_length,  				"allocation", G_TYPE_STRING, allocation_str, -				"bitpool", G_TYPE_INT, sbc->bitpool, +				"bitpool", G_TYPE_INT, sbc->max_bitpool,  				NULL);  	return caps;  } +/* + * Given a GstCaps, this will return a fixed GstCaps on sucessfull conversion. + * If an error occurs, it will return NULL and error_message will contain the + * error message. + * + * error_message must be passed NULL, if an error occurs, the caller has the + * ownership of the error_message, it must be freed after use. + */ +GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message) +{ +	GstCaps *result; +	GstStructure *structure; +	const GValue *value; +	gboolean error = FALSE; +	gint temp, rate, channels, blocks, subbands, bitpool; +	const gchar* allocation = NULL; +	const gchar* mode = NULL; + +	g_assert(*error_message == NULL); + +	structure = gst_caps_get_structure(caps, 0); + +	if (!gst_structure_has_field(structure, "rate")) { +		error = TRUE; +		*error_message = g_strdup("no rate"); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "rate"); +		if (GST_VALUE_HOLDS_LIST(value)) +			temp = gst_sbc_select_rate_from_list(value); +		else +			temp = g_value_get_int(value); +		rate = temp; +	} + +	if (!gst_structure_has_field(structure, "channels")) { +		error = TRUE; +		*error_message = g_strdup("no channels"); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "channels"); +		if (GST_VALUE_HOLDS_INT_RANGE(value)) +			temp = gst_sbc_select_channels_from_range(value); +		else +			temp = g_value_get_int(value); +		channels = temp; +	} + +	if (!gst_structure_has_field(structure, "blocks")) { +		error = TRUE; +		*error_message = g_strdup("no blocks."); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "blocks"); +		if (GST_VALUE_HOLDS_LIST(value)) +			temp = gst_sbc_select_blocks_from_list(value); +		else +			temp = g_value_get_int(value); +		blocks = temp; +	} + +	if (!gst_structure_has_field(structure, "subbands")) { +		error = TRUE; +		*error_message = g_strdup("no subbands"); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "subbands"); +		if (GST_VALUE_HOLDS_LIST(value)) +			temp = gst_sbc_select_subbands_from_list(value); +		else +			temp = g_value_get_int(value); +		subbands = temp; +	} + +	if (!gst_structure_has_field(structure, "bitpool")) { +		error = TRUE; +		*error_message = g_strdup("no bitpool"); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "bitpool"); +		if (GST_VALUE_HOLDS_INT_RANGE(value)) +			temp = gst_sbc_select_bitpool_from_range(value); +		else +			temp = g_value_get_int(value); +		bitpool = temp; +	} + +	if (!gst_structure_has_field(structure, "allocation")) { +		error = TRUE; +		*error_message = g_strdup("no allocation"); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "allocation"); +		if (GST_VALUE_HOLDS_LIST(value)) +			allocation = gst_sbc_get_allocation_from_list(value); +		else +			allocation = g_value_get_string(value); +	} + +	if (!gst_structure_has_field(structure, "mode")) { +		error = TRUE; +		*error_message = g_strdup("no mode"); +		goto error; +	} else { +		value = gst_structure_get_value(structure, "mode"); +		if (GST_VALUE_HOLDS_LIST(value)) +			mode = gst_sbc_get_mode_from_list(value); +		else +			mode = g_value_get_string(value); +	} + +error: +	if (error) +		return NULL; + +	result = gst_caps_new_simple("audio/x-sbc", +					"rate", G_TYPE_INT, rate, +					"channels", G_TYPE_INT, channels, +					"mode", G_TYPE_STRING, mode, +					"blocks", G_TYPE_INT, blocks, +					"subbands", G_TYPE_INT, subbands, +					"allocation", G_TYPE_STRING, allocation, +					"bitpool", G_TYPE_INT, bitpool, +					NULL); + +	return result; +} + + diff --git a/audio/gstsbcutil.h b/audio/gstsbcutil.h index 0c91fe82..4581abf7 100644 --- a/audio/gstsbcutil.h +++ b/audio/gstsbcutil.h @@ -22,10 +22,9 @@   */  #include <gst/gst.h> -#include "sbc.h" -struct ipc_data_cfg; /* FIXME can't include ipc.h */ -struct ipc_codec_sbc; +#include "sbc.h" +#include "ipc.h"  gint gst_sbc_select_rate_from_list(const GValue *value); @@ -47,6 +46,6 @@ const gchar *gst_sbc_get_mode_from_list(const GValue *value);  gint gst_sbc_get_mode_int(const gchar *mode);  const gchar *gst_sbc_get_mode_string(int joint); -GstCaps* gst_sbc_caps_from_sbc(struct ipc_data_cfg *cfg, struct ipc_codec_sbc *sbc, -		gint channels); +GstCaps* gst_sbc_caps_from_sbc(sbc_capabilities_t *sbc, gint channels); +GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message); diff --git a/audio/ipc.c b/audio/ipc.c new file mode 100644 index 00000000..05920648 --- /dev/null +++ b/audio/ipc.c @@ -0,0 +1,119 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org> + * + *  This library is free software; you can redistribute it and/or + *  modify it under the terms of the GNU Lesser General Public + *  License as published by the Free Software Foundation; either + *  version 2.1 of the License, or (at your option) any later version. + * + *  This library is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  Lesser General Public License for more details. + * + *  You should have received a copy of the GNU Lesser General Public + *  License along with this library; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#include "ipc.h" + +/* This table contains the string representation for messages */ +static const char *strmsg[] = { +	"BT_GETCAPABILITIES_REQ", +	"BT_GETCAPABILITIES_RSP", +	"BT_SETCONFIGURATION_REQ", +	"BT_SETCONFIGURATION_RSP", +	"BT_STREAMSTART_REQ", +	"BT_STREAMSTART_RSP", +	"BT_STREAMSTOP_REQ", +	"BT_STREAMSTOP_RSP", +	"BT_STREAMSUSPEND_IND", +	"BT_STREAMRESUME_IND", +	"BT_CONTROL_REQ", +	"BT_CONTROL_RSP", +	"BT_CONTROL_IND", +	"BT_STREAMFD_IND", +}; + +int bt_audio_service_open() +{ +	int sk; +	int err; +	struct sockaddr_un addr = { +		AF_UNIX, BT_IPC_SOCKET_NAME +	}; + +	sk = socket(PF_LOCAL, SOCK_STREAM, 0); +	if (sk < 0) { +		err = errno; +		fprintf(stderr, "%s: Cannot open socket: %s (%d)\n", +			__FUNCTION__, strerror(err), err); +		errno = err; +		return -1; +	} + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		err = errno; +		fprintf(stderr, "%s: connect() failed: %s (%d)\n", +			__FUNCTION__, strerror(err), err); +		close(sk); +		errno = err; +		return -1; +	} + +	return sk; +} + +int bt_audio_service_close(int sk) +{ +	return close(sk); +} + +int bt_audio_service_get_data_fd(int sk) +{ +	char cmsg_b[CMSG_SPACE(sizeof(int))], m; +	int err, ret; +	struct iovec iov = { &m, sizeof(m) }; +	struct msghdr msgh; +	struct cmsghdr *cmsg; + +	memset(&msgh, 0, sizeof(msgh)); +	msgh.msg_iov = &iov; +	msgh.msg_iovlen = 1; +	msgh.msg_control = &cmsg_b; +	msgh.msg_controllen = CMSG_LEN(sizeof(int)); + +	ret = recvmsg(sk, &msgh, 0); +	if (ret < 0) { +		err = errno; +		fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n", +			__FUNCTION__, strerror(err), err); +		errno = err; +		return -1; +	} + +	/* Receive auxiliary data in msgh */ +	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; +			cmsg = CMSG_NXTHDR(&msgh, cmsg)) { +		if (cmsg->cmsg_level == SOL_SOCKET +				&& cmsg->cmsg_type == SCM_RIGHTS) +			return (*(int *) CMSG_DATA(cmsg)); +	} + +	errno = EINVAL; +	return -1; +} + +const char *bt_audio_strmsg(int type) +{ +	if (type < 0 || type > (sizeof(strmsg) / sizeof(strmsg[0]))) +		return NULL; + +	return strmsg[type]; +} + diff --git a/audio/ipc.h b/audio/ipc.h index 1c26e304..0384cfd6 100644 --- a/audio/ipc.h +++ b/audio/ipc.h @@ -4,132 +4,285 @@   *   *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>   * + *  This library is free software; you can redistribute it and/or + *  modify it under the terms of the GNU Lesser General Public + *  License as published by the Free Software Foundation; either + *  version 2.1 of the License, or (at your option) any later version.   * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License as published by - *  the Free Software Foundation; either version 2 of the License, or - *  (at your option) any later version. - * - *  This program is distributed in the hope that it will be useful, + *  This library is distributed in the hope that it will be useful,   *  but WITHOUT ANY WARRANTY; without even the implied warranty of - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - *  GNU General Public License for more details. + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  Lesser General Public License for more details.   * - *  You should have received a copy of the GNU General Public License - *  along with this program; if not, write to the Free Software + *  You should have received a copy of the GNU Lesser General Public + *  License along with this library; if not, write to the Free Software   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA   *   */ -#include <stdint.h> +/* +  Message sequence chart of streaming sequence for A2DP transport + +  Audio daemon                       User +                             on snd_pcm_open +                 <--BT_GETCAPABILITIES_REQ + +  BT_GETCAPABILITIES_RSP--> + +                        on snd_pcm_hw_params +                <--BT_SETCONFIGURATION_REQ + +  BT_SETCONFIGURATION_RSP--> + +			on snd_pcm_prepare +                <--BT_STREAMSTART_REQ + +  <Moves to streaming state> +  BT_STREAMSTART_RSP--> -#define IPC_TYPE_CONNECT  0x0001 +  BT_STREAMFD_IND --> -#define IPC_MTU 128 +                          <  streams data > +                             .......... -#define IPC_SOCKET_NAME "\0/org/bluez/audio" +               on snd_pcm_drop/snd_pcm_drain -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX 108 +                <--BT_STREAMSTOP_REQ + +  <Moves to open state> +  BT_STREAMSTOP_RSP--> + +			on IPC close or appl crash +  <Moves to idle> + + */ + +#ifndef BT_AUDIOCLIENT_H +#define BT_AUDIOCLIENT_H + +#ifdef __cplusplus +extern "C" {  #endif -/* Supported roles */ -#define PKT_ROLE_AUTO			0 -#define PKT_ROLE_VOICE			1 -#define PKT_ROLE_HIFI			2 - -/* Packet types */ -#define PKT_TYPE_CFG_REQ		0 -#define PKT_TYPE_CFG_RSP		1 -#define PKT_TYPE_STATE_REQ		2 -#define PKT_TYPE_STATE_RSP		3 -#define PKT_TYPE_CTL_REQ		4 -#define PKT_TYPE_CTL_RSP		5 -#define PKT_TYPE_CTL_NTFY		6 - -/* Errors codes */ -#define PKT_ERROR_NONE			0 - -struct ipc_packet { -	char device[18];	/* 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 */ -	uint8_t length;		/* Payload length in bytes */ -	uint8_t data[0];	/* Packet payload */ -} __attribute__ ((packed)); +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> + +#define BT_AUDIO_IPC_PACKET_SIZE   128 +#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio" -/* File descriptor options */ -#define CFG_FD_OPT_READ		0 -#define CFG_FD_OPT_WRITE	1 -#define CFG_FD_OPT_READWRITE	2 - -/* Audio channel mode */ -#define CFG_MODE_AUTO		0 -#define CFG_MODE_MONO		1 -#define CFG_MODE_DUAL_CHANNEL	2 -#define CFG_MODE_STEREO		3 -#define CFG_MODE_JOINT_STEREO	4 - -/* Allocation method */ -#define CFG_ALLOCATION_AUTO	0 -#define CFG_ALLOCATION_LOUDNESS	1 -#define CFG_ALLOCATION_SNR	2 - -/* Codec options */ -#define CFG_CODEC_NONE		0 -#define CFG_CODEC_SCO		1 -#define CFG_CODEC_SBC		2 - -struct ipc_data_cfg { -	uint8_t  fd_opt;	/* Stream file descriptor options: read, -				   write or readwrite */ -	uint16_t pkt_len;	/* Stream packet length */ -	uint8_t  sample_size;	/* Sample size in bytes */ -	uint8_t  mode;		/* Audio channel mode */ -	uint16_t rate;		/* Stream sample rate */ -	uint8_t  codec;		/* Stream codec */ -	uint8_t  data[0];	/* Codec payload */ +/* Generic message header definition */ +typedef struct { +	uint8_t msg_type; +} __attribute__ ((packed)) bt_audio_msg_header_t; + +/* Messages list */ +#define BT_GETCAPABILITIES_REQ		0 +#define BT_GETCAPABILITIES_RSP		1 + +#define BT_SETCONFIGURATION_REQ		2 +#define BT_SETCONFIGURATION_RSP		3 + +#define BT_STREAMSTART_REQ		4 +#define BT_STREAMSTART_RSP		5 + +#define BT_STREAMSTOP_REQ		6 +#define BT_STREAMSTOP_RSP		7 + +#define BT_STREAMSUSPEND_IND		8 +#define BT_STREAMRESUME_IND		9 + +#define BT_CONTROL_REQ		       10 +#define BT_CONTROL_RSP		       11 +#define BT_CONTROL_IND		       12 + +#define BT_STREAMFD_IND		       13 + +/* BT_GETCAPABILITIES_REQ */ + +#define BT_CAPABILITIES_TRANSPORT_A2DP	0 +#define BT_CAPABILITIES_TRANSPORT_SCO	1 +#define BT_CAPABILITIES_TRANSPORT_ANY	2 + +#define BT_CAPABILITIES_ACCESS_MODE_READ	1 +#define BT_CAPABILITIES_ACCESS_MODE_WRITE	2 +#define BT_CAPABILITIES_ACCESS_MODE_READWRITE	3 + +struct bt_getcapabilities_req { +	bt_audio_msg_header_t	h; +	char			device[18];	/* Address of the remote Device */ +	uint8_t			transport;	/* Requested transport */ +	uint8_t			access_mode;	/* Requested access mode */  } __attribute__ ((packed)); -struct ipc_codec_sbc { -	uint8_t allocation; +/* BT_GETCAPABILITIES_RSP */ + +/** + * SBC Codec parameters as per A2DP profile 1.0 § 4.3 + */ + +#define BT_A2DP_SAMPLING_FREQ_16000		(1 << 3) +#define BT_A2DP_SAMPLING_FREQ_32000		(1 << 2) +#define BT_A2DP_SAMPLING_FREQ_44100		(1 << 1) +#define BT_A2DP_SAMPLING_FREQ_48000		1 + +#define BT_A2DP_CHANNEL_MODE_MONO		(1 << 3) +#define BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2) +#define BT_A2DP_CHANNEL_MODE_STEREO		(1 << 1) +#define BT_A2DP_CHANNEL_MODE_JOINT_STEREO	1 +#define BT_A2DP_CHANNEL_MODE_AUTO		0 + +#define BT_A2DP_BLOCK_LENGTH_4			(1 << 3) +#define BT_A2DP_BLOCK_LENGTH_8			(1 << 2) +#define BT_A2DP_BLOCK_LENGTH_12			(1 << 1) +#define BT_A2DP_BLOCK_LENGTH_16			1 + +#define BT_A2DP_SUBBANDS_4			(1 << 1) +#define BT_A2DP_SUBBANDS_8			1 + +#define BT_A2DP_ALLOCATION_SNR			(1 << 1) +#define BT_A2DP_ALLOCATION_LOUDNESS		1 +#define BT_A2DP_ALLOCATION_AUTO			0 + +typedef struct { +	uint8_t channel_mode; +	uint8_t frequency; +	uint8_t allocation_method;  	uint8_t subbands; -	uint8_t blocks; -	uint8_t bitpool; +	uint8_t block_length; +	uint8_t min_bitpool; +	uint8_t max_bitpool; +} __attribute__ ((packed)) sbc_capabilities_t; + +/* To be defined */ +typedef struct { +} __attribute__ ((packed)) mpeg_capabilities_t; + +struct bt_getcapabilities_rsp { +	bt_audio_msg_header_t	h; +	uint8_t			posix_errno; +	uint8_t			transport;		/* Granted transport */ +	uint8_t			access_mode;		/* Granted access mode */ +	uint16_t		link_mtu;		/* Max length that transport supports */ +	sbc_capabilities_t	sbc_capabilities;	/* A2DP only */ +	mpeg_capabilities_t	mpeg_capabilities;	/* A2DP only */ +	uint16_t		sampling_rate;		/* SCO only */ +} __attribute__ ((packed)); + +/* BT_SETCONFIGURATION_REQ */ +struct bt_setconfiguration_req { +	bt_audio_msg_header_t	h; +	char			device[18];		/* Address of the remote Device */ +	sbc_capabilities_t	sbc_capabilities;	/* A2DP only - only one of this field +							and next one must be filled */ +	mpeg_capabilities_t	mpeg_capabilities;	/* A2DP only */ +} __attribute__ ((packed)); + +/* BT_SETCONFIGURATION_RSP */ +struct bt_setconfiguration_rsp { +	bt_audio_msg_header_t	h; +	uint8_t			posix_errno; +} __attribute__ ((packed)); + +/* BT_STREAMSTART_REQ */ +#define BT_STREAM_ACCESS_READ		0 +#define BT_STREAM_ACCESS_WRITE		1 +#define BT_STREAM_ACCESS_READWRITE	2 +struct bt_streamstart_req { +	bt_audio_msg_header_t	h; +} __attribute__ ((packed)); + +/* BT_STREAMSTART_RSP */ +struct bt_streamstart_rsp { +	bt_audio_msg_header_t	h; +	uint8_t			posix_errno; +} __attribute__ ((packed)); + +/* BT_STREAMFD_IND */ +/* This message is followed by one byte of data containing the stream data fd +   as ancilliary data */ +struct bt_datafd_ind { +	bt_audio_msg_header_t	h; +} __attribute__ ((packed)); + +/* BT_STREAMSTOP_REQ */ +struct bt_streamstop_req { +	bt_audio_msg_header_t	h; +} __attribute__ ((packed)); + +/* BT_STREAMSTOP_RSP */ +struct bt_streamstop_rsp { +	bt_audio_msg_header_t	h; +	uint8_t			posix_errno;  } __attribute__ ((packed)); -/* Device status */ -#define STATE_DISCONNECTED		0 -#define STATE_CONNECTING		1 -#define STATE_CONNECTED			2 -#define STATE_STREAM_STARTING		3 -#define STATE_STREAMING			4 +/* BT_STREAMSUSPEND_IND */ +struct bt_streamsuspend_ind { +	bt_audio_msg_header_t	h; +} __attribute__ ((packed)); -struct ipc_data_state { -	uint8_t state;		/* Stream state */ +/* BT_STREAMRESUME_IND */ +struct bt_streamresume_ind { +	bt_audio_msg_header_t	h;  } __attribute__ ((packed)); -#define CTL_MODE_PLAYBACK		0 -#define CTL_MODE_CAPTURE		1 -#define CTL_MODE_GENERAL		2 - -/* Supported control operations */ -#define CTL_KEY_POWER			0x40 -#define CTL_KEY_VOL_UP			0x41 -#define CTL_KEY_VOL_DOWN		0x42 -#define CTL_KEY_MUTE			0x43 -#define CTL_KEY_PLAY			0x44 -#define CTL_KEY_STOP			0x45 -#define CTL_KEY_PAUSE			0x46 -#define CTL_KEY_RECORD			0x47 -#define CTL_KEY_REWIND			0x48 -#define CTL_KEY_FAST_FORWARD		0x49 -#define CTL_KEY_EJECT			0x4A -#define CTL_KEY_FORWARD			0x4B -#define CTL_KEY_BACKWARD		0x4C - -struct ipc_data_ctl { -	uint8_t mode;		/* Control Mode */ -	uint8_t key;		/* Control Key */ -}  __attribute__ ((packed)); +/* BT_CONTROL_REQ */ + +#define BT_CONTROL_KEY_POWER			0x40 +#define BT_CONTROL_KEY_VOL_UP			0x41 +#define BT_CONTROL_KEY_VOL_DOWN			0x42 +#define BT_CONTROL_KEY_MUTE			0x43 +#define BT_CONTROL_KEY_PLAY			0x44 +#define BT_CONTROL_KEY_STOP			0x45 +#define BT_CONTROL_KEY_PAUSE			0x46 +#define BT_CONTROL_KEY_RECORD			0x47 +#define BT_CONTROL_KEY_REWIND			0x48 +#define BT_CONTROL_KEY_FAST_FORWARD		0x49 +#define BT_CONTROL_KEY_EJECT			0x4A +#define BT_CONTROL_KEY_FORWARD			0x4B +#define BT_CONTROL_KEY_BACKWARD			0x4C + +struct bt_control_req { +	bt_audio_msg_header_t	h; +	uint8_t			mode;		/* Control Mode */ +	uint8_t			key;		/* Control Key */ +} __attribute__ ((packed)); + +/* BT_CONTROL_RSP */ +struct bt_control_rsp { +	bt_audio_msg_header_t	h; +	uint8_t			posix_errno; +	uint8_t			mode;		/* Control Mode */ +	uint8_t			key;		/* Control Key */ +} __attribute__ ((packed)); + +/* BT_CONTROL_IND */ +struct bt_control_ind { +	bt_audio_msg_header_t	h; +	uint8_t			mode;		/* Control Mode */ +	uint8_t			key;		/* Control Key */ +} __attribute__ ((packed)); + +/* Function declaration */ + +/* Opens a connection to the audio service: return a socket descriptor */ +int bt_audio_service_open(); + +/* Closes a connection to the audio service */ +int bt_audio_service_close(int sk); + +/* Receives stream data file descriptor : must be called after a +BT_STREAMFD_IND message is returned */ +int bt_audio_service_get_data_fd(int sk); + +/* Human readable message type string */ +const char *bt_audio_strmsg(int type); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_AUDIOCLIENT_H */ diff --git a/audio/manager.c b/audio/manager.c index b0cc3340..d80fb962 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -1052,7 +1052,7 @@ static void parse_stored_devices(char *key, char *value, void *data)  		return;  	str2ba(key, &dst); -	device = manager_find_device(&dst, PKT_ROLE_AUTO, FALSE); +	device = manager_find_device(&dst, NULL, FALSE);  	if (device)  		return; @@ -1111,7 +1111,7 @@ static void register_devices_stored(const char *adapter)  		return;  	str2ba(addr, &dst); -	device = manager_find_device(&dst, PKT_ROLE_AUTO, FALSE); +	device = manager_find_device(&dst, NULL, FALSE);  	if (device) {  		info("Setting %s as default device", addr); diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index efe1d2aa..f4a20015 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -76,33 +76,60 @@  #endif  struct bluetooth_a2dp { -	sbc_t sbc;			/* Codec data */ -	int codesize;			/* SBC codesize */ -	int samples;			/* Number of encoded samples */ -	uint8_t buffer[BUFFER_SIZE];	/* Codec transfer buffer */ -	int count;			/* Codec transfer buffer counter */ - -	int nsamples;			/* Cumulative number of codec samples */ -	uint16_t seq_num;		/* Cumulative packet sequence */ -	int frame_count;		/* Current frames in buffer*/ +	sbc_capabilities_t sbc_capabilities; +	sbc_t sbc;				/* Codec data */ +	int sbc_initialized;			/* Keep track if the encoder is initialized */ +	int codesize;				/* SBC codesize */ +	int samples;				/* Number of encoded samples */ +	uint8_t buffer[BUFFER_SIZE];		/* Codec transfer buffer */ +	int count;				/* Codec transfer buffer counter */ + +	int nsamples;				/* Cumulative number of codec samples */ +	uint16_t seq_num;			/* Cumulative packet sequence */ +	int frame_count;			/* Current frames in buffer*/ +}; + +struct bluetooth_alsa_config { +	char device[18];		/* Address of the remote Device */ +	int has_device; +	uint8_t transport;		/* Requested transport */ +	int has_transport; +	uint16_t rate; +	int has_rate; +	uint8_t channel_mode;		/* A2DP only */ +	int has_channel_mode; +	uint8_t allocation_method;	/* A2DP only */ +	int has_allocation_method; +	uint8_t subbands;		/* A2DP only */ +	int has_subbands; +	uint8_t block_length;		/* A2DP only */ +	int has_block_length; +	uint8_t bitpool;		/* A2DP only */ +	int has_bitpool;  };  struct bluetooth_data {  	snd_pcm_ioplug_t io; +	struct bluetooth_alsa_config alsa_config;	/* ALSA resource file parameters */  	volatile snd_pcm_sframes_t hw_ptr; -	struct ipc_data_cfg cfg;	/* Bluetooth device config */ -	struct pollfd stream;		/* Audio stream filedescriptor */ -	struct pollfd server;		/* Audio daemon filedescriptor */ -	uint8_t buffer[BUFFER_SIZE];	/* Encoded transfer buffer */ -	int count;			/* Transfer buffer counter */ -	struct bluetooth_a2dp a2dp;	/* A2DP data */ - -	pthread_t hw_thread;		/* Makes virtual hw pointer move */ -	int pipefd[2];			/* Inter thread communication */ +	int transport;					/* chosen transport SCO or AD2P */ +	int link_mtu;					/* MTU for selected transport channel */ +	volatile struct pollfd stream;			/* Audio stream filedescriptor */ +	struct pollfd server;				/* Audio daemon filedescriptor */ +	uint8_t buffer[BUFFER_SIZE];		/* Encoded transfer buffer */ +	int count;					/* Transfer buffer counter */ +	struct bluetooth_a2dp a2dp;			/* A2DP data */ + +	pthread_t hw_thread;				/* Makes virtual hw pointer move */ +	int pipefd[2];					/* Inter thread communication */  	int stopped;  	sig_atomic_t reset;             /* Request XRUN handling */  }; +static int audioservice_send(int sk, const bt_audio_msg_header_t *msg); +static int audioservice_expect(int sk, bt_audio_msg_header_t *outmsg, +				int expected_type); +  static int bluetooth_start(snd_pcm_ioplug_t *io)  {  	DBG("bluetooth_start %p", io); @@ -215,62 +242,6 @@ iter_sleep:  	pthread_exit(NULL);  } -#if 0 -static int bluetooth_state_init(struct ipc_packet *pkt, int newstate) -{ -	struct ipc_data_state *state = (void *) pkt->data; - -	pkt->length = sizeof(*state); -	pkt->type = PKT_TYPE_STATE_REQ; -	pkt->error = PKT_ERROR_NONE; -	state->state = newstate; - -	return 0; -} - -static int bluetooth_state(struct bluetooth_data *data, int newstate) -{ -	char buf[IPC_MTU]; -	struct ipc_packet *pkt = (void *) buf; -	struct ipc_data_state *state = (void *) pkt->data; -	int ret; - -	memset(buf, 0, sizeof(buf)); - -	ret = bluetooth_state_init(pkt, newstate); -	if (ret < 0) -		return -ret; - -	ret = send(data->server.fd, pkt, sizeof(*pkt) + pkt->length, 0); -	if (ret < 0) -		return -errno; -	else if (ret == 0) -		return -EIO; - -	DBG("OK - %d bytes sent. Waiting for response...", ret); - -	memset(buf, 0, sizeof(buf)); - -	ret = recv(data->server.fd, buf, sizeof(*pkt) + sizeof(*state), 0); -	if (ret < 0) -		return -errno; -	else if (ret == 0) -		return -EIO; - -	if (pkt->type != PKT_TYPE_STATE_RSP) { -		SNDERR("Unexpected packet type %d received", pkt->type); -		return -EINVAL; -	} - -	if (pkt->error != PKT_ERROR_NONE) { -		SNDERR("Error %d while configuring device", pkt->error); -		return -pkt->error; -	} - -	return 0; -} -#endif -  static int bluetooth_playback_start(snd_pcm_ioplug_t *io)  {  	struct bluetooth_data *data = io->private_data; @@ -278,9 +249,6 @@ static int bluetooth_playback_start(snd_pcm_ioplug_t *io)  	DBG("%p", io); -#if 0 -	bluetooth_state(data, STATE_STREAMING); -#endif  	data->stopped = 0;  	if (data->hw_thread) @@ -297,9 +265,6 @@ static int bluetooth_playback_stop(snd_pcm_ioplug_t *io)  	DBG("%p", io); -#if 0 -	bluetooth_state(data, STATE_CONNECTED); -#endif  	data->stopped = 1;  	return 0; @@ -317,7 +282,7 @@ static void bluetooth_exit(struct bluetooth_data *data)  	struct bluetooth_a2dp *a2dp = &data->a2dp;  	if (data->server.fd >= 0) -		close(data->server.fd); +		bt_audio_service_close(data->server.fd);  	if (data->stream.fd >= 0)  		close(data->stream.fd); @@ -327,7 +292,7 @@ static void bluetooth_exit(struct bluetooth_data *data)  		pthread_join(data->hw_thread, 0);  	} -	if (data->cfg.codec == CFG_CODEC_SBC) +	if (a2dp->sbc_initialized)  		sbc_finish(&a2dp->sbc);  	if (data->pipefd[0] > 0) @@ -354,12 +319,27 @@ static int bluetooth_prepare(snd_pcm_ioplug_t *io)  {  	struct bluetooth_data *data = io->private_data;  	char c = 'w'; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_streamstart_req *start_req = (void*) buf; +	struct bt_streamstart_rsp *start_rsp = (void*) buf; +	struct bt_datafd_ind *datafd_ind = (void*) buf; +	uint32_t period_count = io->buffer_size / io->period_size; +	int opt_name, err; +	struct timeval t = { 0, period_count };  	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",  					io->period_size, io->buffer_size);  	data->reset = 0; +	/* As we're gonna receive messages on the server socket, we have to stop the +	   hw thread that is polling on it, if any */ +	if (data->hw_thread) { +		pthread_cancel(data->hw_thread); +		pthread_join(data->hw_thread, 0); +		data->hw_thread = 0; +	} +  	if (io->stream == SND_PCM_STREAM_PLAYBACK)  		/* If not null for playback, xmms doesn't display time  		 * correctly */ @@ -369,63 +349,174 @@ static int bluetooth_prepare(snd_pcm_ioplug_t *io)  		 * If it is, capture won't start */  		data->hw_ptr = io->period_size; -	/* wake up any client polling at us */ -	return write(data->pipefd[1], &c, 1); -} +	/* send start */ +	memset(start_req, 0, BT_AUDIO_IPC_PACKET_SIZE); +	start_req->h.msg_type = BT_STREAMSTART_REQ; -static int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io, -					snd_pcm_hw_params_t *params) -{ -	struct bluetooth_data *data = io->private_data; -	uint32_t period_count = io->buffer_size / io->period_size; -	int opt_name, err; +	err = audioservice_send(data->server.fd, &start_req->h); +	if (err < 0) +		return err; + +	err = audioservice_expect(data->server.fd, &start_rsp->h, +					BT_STREAMSTART_RSP); +	if (err < 0) +		return err; + +	if (start_rsp->posix_errno != 0) { +		SNDERR("BT_START failed : %s(%d)", +					strerror(start_rsp->posix_errno), +					start_rsp->posix_errno); +		return -start_rsp->posix_errno; +	} + +	err = audioservice_expect(data->server.fd, &datafd_ind->h, +					BT_STREAMFD_IND); +	if (err < 0) +		return err; + +	if (data->stream.fd >= 0) +		close(data->stream.fd); + +	data->stream.fd = bt_audio_service_get_data_fd(data->server.fd); +	if (data->stream.fd < 0) { +		return -errno; +	} -	DBG("fd=%d period_count=%d", data->stream.fd, period_count); +	if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) { +		opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? +						SO_SNDTIMEO : SO_RCVTIMEO; -	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? +		if (setsockopt(data->stream.fd, SOL_SOCKET, opt_name, &t, +							sizeof(t)) < 0) +			return -errno; +	} else { +		opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?  						SCO_TXBUFS : SCO_RXBUFS; -	if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count, +		if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,  						sizeof(period_count)) == 0) -		return 0; +			return 0; -	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? +		opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?  						SO_SNDBUF : SO_RCVBUF; -	if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count, +		if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,  						sizeof(period_count)) == 0) -		return 0; - -	err = errno; +			return 0; -	SNDERR("%s (%d)", strerror(err), err); +		/* FIXME : handle error codes */ +	} -	/* FIXME: We should not ignores errors in the future. */ -	return 0; +	/* wake up any client polling at us */ +	return write(data->pipefd[1], &c, 1);  }  static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,  					snd_pcm_hw_params_t *params)  {  	struct bluetooth_data *data = io->private_data; -	uint32_t period_count = io->buffer_size / io->period_size; -	int opt_name, err; -	struct timeval t = { 0, period_count }; +	struct bluetooth_a2dp *a2dp = &data->a2dp; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_setconfiguration_req *setconf_req = (void*) buf; +	struct bt_setconfiguration_rsp *setconf_rsp = (void*) buf; +	int err; +	sbc_capabilities_t active_capabilities; -	DBG("fd=%d period_count=%d", data->stream.fd, period_count); +	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", +					io->period_size, io->buffer_size); -	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? -						SO_SNDTIMEO : SO_RCVTIMEO; +	/* FIXME: this needs to be really implemented (take into account +	real asoundrc settings + ALSA hw settings ) once server side sends us +	more than one possible configuration */ +	active_capabilities = a2dp->sbc_capabilities; -	if (setsockopt(data->stream.fd, SOL_SOCKET, opt_name, &t, -							sizeof(t)) == 0) -		return 0; +	memset(setconf_req, 0, BT_AUDIO_IPC_PACKET_SIZE); +	setconf_req->h.msg_type = BT_SETCONFIGURATION_REQ; +	setconf_req->sbc_capabilities = active_capabilities; -	err = errno; +	err = audioservice_send(data->server.fd, &setconf_req->h); +	if (err < 0) +		return err; -	SNDERR("%s (%d)", strerror(err), err); +	err = audioservice_expect(data->server.fd, &setconf_rsp->h, +					BT_SETCONFIGURATION_RSP); +	if (err < 0) +		return err; -	return -err; +	if (setconf_rsp->posix_errno != 0) { +		SNDERR("BT_SETCONFIGURATION failed : %s(%d)", +					strerror(setconf_rsp->posix_errno), +					setconf_rsp->posix_errno); +		return -setconf_rsp->posix_errno; +	} + +	/* Setup SBC encoder now we agree on parameters */ +	if (a2dp->sbc_initialized) +		sbc_finish(&a2dp->sbc); + +	/* FIXME: init using flags? */ +	sbc_init(&a2dp->sbc, 0); +	a2dp->sbc_initialized = 1; +	if (active_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_16000) +		a2dp->sbc.rate = 16000; + +	if (active_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_32000) +		a2dp->sbc.rate = 32000; + +	if (active_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_44100) +		a2dp->sbc.rate = 44100; + +	if (active_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_48000) +		a2dp->sbc.rate = 48000; + +	if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO) +		a2dp->sbc.channels = 1; +	else +		a2dp->sbc.channels = 2; + +	if (active_capabilities.channel_mode & +			(BT_A2DP_CHANNEL_MODE_MONO || BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) +		a2dp->sbc.joint = 1; +	else +		a2dp->sbc.joint = 0; + +	a2dp->sbc.allocation = active_capabilities.allocation_method +					== BT_A2DP_ALLOCATION_SNR ? 0x01 : 0x00; + +	switch (active_capabilities.subbands) { +	case BT_A2DP_SUBBANDS_4: +		a2dp->sbc.subbands = 4; +		break; +	case BT_A2DP_SUBBANDS_8: +		a2dp->sbc.subbands = 8; +		break; +	} + +	switch (active_capabilities.block_length) { +	case BT_A2DP_BLOCK_LENGTH_4: +		a2dp->sbc.blocks = 4; +		break; +	case BT_A2DP_BLOCK_LENGTH_8: +		a2dp->sbc.blocks = 8; +		break; +	case BT_A2DP_BLOCK_LENGTH_12: +		a2dp->sbc.blocks = 12; +		break; +	case BT_A2DP_BLOCK_LENGTH_16: +		a2dp->sbc.blocks = 16; +		break; +	} + +	a2dp->sbc.bitpool = active_capabilities.max_bitpool; +	a2dp->codesize = a2dp->sbc.subbands * a2dp->sbc.blocks * +						a2dp->sbc.channels * 2; +	a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + +	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); + +	return 0;  }  static int bluetooth_poll_descriptors(snd_pcm_ioplug_t *io, @@ -504,7 +595,6 @@ static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,  				snd_pcm_uframes_t size)  {  	struct bluetooth_data *data = io->private_data; -	struct ipc_data_cfg cfg = data->cfg;  	snd_pcm_uframes_t frames_to_write, ret;  	unsigned char *buff;  	int nrecv, frame_size = 0; @@ -517,7 +607,7 @@ static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,  	frame_size = areas->step / 8; -	nrecv = recv(data->stream.fd, data->buffer, cfg.pkt_len, +	nrecv = recv(data->stream.fd, data->buffer, data->link_mtu,  			MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));  	if (nrecv < 0) { @@ -525,28 +615,28 @@ static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,  		goto done;  	} -	if (nrecv != cfg.pkt_len) { +	if (nrecv != data->link_mtu) {  		ret = -EIO;  		SNDERR(strerror(-ret));  		goto done;  	}  	/* Increment hardware transmition pointer */ -	data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % +	data->hw_ptr = (data->hw_ptr + data->link_mtu / frame_size) %  								io->buffer_size;  proceed:  	buff = (unsigned char *) areas->addr +  			(areas->first + areas->step * offset) / 8; -	if ((data->count + size * frame_size) <= cfg.pkt_len) +	if ((data->count + size * frame_size) <= data->link_mtu)  		frames_to_write = size;  	else -		frames_to_write = (cfg.pkt_len - data->count) / frame_size; +		frames_to_write = (data->link_mtu - data->count) / frame_size;  	memcpy(buff, data->buffer + data->count, frame_size * frames_to_write);  	data->count += (frame_size * frames_to_write); -	data->count %= cfg.pkt_len; +	data->count %= data->link_mtu;  	/* Return written frames count */  	ret = frames_to_write; @@ -562,7 +652,6 @@ static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io,  				snd_pcm_uframes_t size)  {  	struct bluetooth_data *data = io->private_data; -	struct ipc_data_cfg cfg = data->cfg;  	snd_pcm_sframes_t ret = 0;  	snd_pcm_uframes_t frames_to_read;  	uint8_t *buff; @@ -579,10 +668,10 @@ static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io,  	}  	frame_size = areas->step / 8; -	if ((data->count + size * frame_size) <= cfg.pkt_len) +	if ((data->count + size * frame_size) <= data->link_mtu)  		frames_to_read = size;  	else -		frames_to_read = (cfg.pkt_len - data->count) / frame_size; +		frames_to_read = (data->link_mtu - data->count) / frame_size;  	DBG("count=%d frames_to_read=%lu", data->count, frames_to_read); @@ -593,12 +682,12 @@ static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io,  	/* Remember we have some frames in the pipe now */  	data->count += frames_to_read * frame_size; -	if (data->count != cfg.pkt_len) { +	if (data->count != data->link_mtu) {  		ret = frames_to_read;  		goto done;  	} -	rsend = send(data->stream.fd, data->buffer, cfg.pkt_len, +	rsend = send(data->stream.fd, data->buffer, data->link_mtu,  			io->nonblock ? MSG_DONTWAIT : 0);  	if (rsend > 0) {  		/* Reset count pointer */ @@ -710,7 +799,7 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,  			frames_to_read = (a2dp->codesize - data->count) / frame_size;  		DBG("count=%d frames_to_read=%lu", data->count, frames_to_read); -		DBG("a2dp.count=%d cfg.pkt_len=%d", a2dp->count, data->cfg.pkt_len); +		DBG("a2dp.count=%d data.link_mtu=%d", a2dp->count, data->link_mtu);  		/* FIXME: If state is not streaming then return */ @@ -747,10 +836,11 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,  				written, a2dp->count);  		/* No space left for another frame then send */ -		if (a2dp->count + written >= data->cfg.pkt_len) { +		if (a2dp->count + written >= data->link_mtu) {  			avdtp_write(data); -			DBG("sending packet %d, count %d, pkt_len %u", c, -					old_count, data->cfg.pkt_len); +			DBG("sending packet %d, count %d, link_mtu %u", +					a2dp->seq_num, a2dp->count, +					data->link_mtu);  		}  		ret += frames_to_read; @@ -791,7 +881,6 @@ static snd_pcm_ioplug_callback_t bluetooth_hsp_playback = {  	.stop			= bluetooth_playback_stop,  	.pointer		= bluetooth_pointer,  	.close			= bluetooth_close, -	.hw_params		= bluetooth_hsp_hw_params,  	.prepare		= bluetooth_prepare,  	.transfer		= bluetooth_hsp_write,  	.poll_descriptors	= bluetooth_playback_poll_descriptors, @@ -804,7 +893,6 @@ static snd_pcm_ioplug_callback_t bluetooth_hsp_capture = {  	.stop			= bluetooth_stop,  	.pointer		= bluetooth_pointer,  	.close			= bluetooth_close, -	.hw_params		= bluetooth_hsp_hw_params,  	.prepare		= bluetooth_prepare,  	.transfer		= bluetooth_hsp_read,  	.poll_descriptors	= bluetooth_poll_descriptors, @@ -841,7 +929,6 @@ static snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = {  static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io)  {  	struct bluetooth_data *data = io->private_data; -	struct ipc_data_cfg cfg = data->cfg;  	snd_pcm_access_t access_list[] = {  		SND_PCM_ACCESS_RW_INTERLEAVED,  		/* Mmap access is really useless fo this driver, but we @@ -852,7 +939,7 @@ static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io)  	unsigned int format_list[] = {  		SND_PCM_FORMAT_S16_LE  	}; -	int err, channels; +	int err;  	/* access type */  	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, @@ -867,21 +954,20 @@ static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io)  		return err;  	/* supported channels */ -	channels = cfg.mode == CFG_MODE_MONO ? 1 : 2;  	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, -							channels, channels); +							1, 1);  	if (err < 0)  		return err;  	/* supported rate */  	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, -							cfg.rate, cfg.rate); +							8000, 8000);  	if (err < 0)  		return err;  	/* supported block size */  	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, -						cfg.pkt_len, cfg.pkt_len); +						data->link_mtu, data->link_mtu);  	if (err < 0)  		return err; @@ -896,7 +982,7 @@ static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io)  static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  {  	struct bluetooth_data *data = io->private_data; -	struct ipc_data_cfg cfg = data->cfg; +	struct bluetooth_a2dp *a2dp = &data->a2dp;  	snd_pcm_access_t access_list[] = {  		SND_PCM_ACCESS_RW_INTERLEAVED,  		/* Mmap access is really useless fo this driver, but we @@ -907,10 +993,12 @@ static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  	unsigned int format_list[] = {  		SND_PCM_FORMAT_S16_LE  	}; +	unsigned int rate_list[4]; +	unsigned int rate_count; +	int err, min_channels, max_channels;  	unsigned int period_list[] = {  		4096, /* 23/46ms (stereo/mono 16bit at 44.1kHz) */  	}; -	int err, channels;  	/* access type */  	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, @@ -925,15 +1013,18 @@ static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  		return err;  	/* supported channels */ -	channels = cfg.mode == CFG_MODE_MONO ? 1 : 2; -	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, -							channels, channels); -	if (err < 0) -		return err; +	if (a2dp->sbc_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO) +		min_channels = 1; +	else +		min_channels = 2; -	/* supported rate */ -	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, -							cfg.rate, cfg.rate); +	if (a2dp->sbc_capabilities.channel_mode & (~BT_A2DP_CHANNEL_MODE_MONO)) +		max_channels = 2; +	else +		max_channels = 1; + +	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, +							min_channels, max_channels);  	if (err < 0)  		return err; @@ -949,96 +1040,44 @@ static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  	if (err < 0)  		return err; -	return 0; -} - -static int bluetooth_recvmsg_fd(struct bluetooth_data *data) -{ -	char cmsg_b[CMSG_SPACE(sizeof(int))], m; -	int err, ret; -	struct iovec iov = { &m, sizeof(m) }; -	struct msghdr msgh; -	struct cmsghdr *cmsg; - -	memset(&msgh, 0, sizeof(msgh)); -	msgh.msg_iov = &iov; -	msgh.msg_iovlen = 1; -	msgh.msg_control = &cmsg_b; -	msgh.msg_controllen = CMSG_LEN(sizeof(int)); - -	ret = recvmsg(data->server.fd, &msgh, 0); -	if (ret < 0) { -		err = errno; -		SNDERR("Unable to receive fd: %s (%d)", strerror(err), err); -		return -err; +	/* supported rates */ +	rate_count = 0; +	if (a2dp->sbc_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_16000) { +		rate_list[rate_count] = 16000; +		rate_count++;  	} -	/* Receive auxiliary data in msgh */ -	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; -			cmsg = CMSG_NXTHDR(&msgh, cmsg)) { -		if (cmsg->cmsg_level == SOL_SOCKET -				&& cmsg->cmsg_type == SCM_RIGHTS) { -			data->stream.fd = (*(int *) CMSG_DATA(cmsg)); -			DBG("stream_fd=%d", data->stream.fd); -			return 0; -		} +	if (a2dp->sbc_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_32000) { +		rate_list[rate_count] = 32000; +		rate_count++;  	} -	return -EINVAL; -} - -static int bluetooth_a2dp_init(struct bluetooth_data *data, -				struct ipc_codec_sbc *sbc) -{ -	struct bluetooth_a2dp *a2dp = &data->a2dp; -	struct ipc_data_cfg *cfg = &data->cfg; - -	if (cfg == NULL) { -		SNDERR("Error getting codec parameters"); -		return -1; +	if (a2dp->sbc_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_44100) { +		rate_list[rate_count] = 44100; +		rate_count++;  	} -	if (cfg->codec != CFG_CODEC_SBC) -		return -1; - -	/* FIXME: init using flags? */ -	sbc_init(&a2dp->sbc, 0); -	a2dp->sbc.rate = cfg->rate; -	a2dp->sbc.channels = cfg->mode == CFG_MODE_MONO ? 1 : 2; -	if (cfg->mode == CFG_MODE_MONO || cfg->mode == CFG_MODE_JOINT_STEREO) -		a2dp->sbc.joint = 1; -	a2dp->sbc.allocation = sbc->allocation; -	a2dp->sbc.subbands = sbc->subbands; -	a2dp->sbc.blocks = sbc->blocks; -	a2dp->sbc.bitpool = sbc->bitpool; -	a2dp->codesize = a2dp->sbc.subbands * a2dp->sbc.blocks * -						a2dp->sbc.channels * 2; -	a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); +	if (a2dp->sbc_capabilities.frequency & BT_A2DP_SAMPLING_FREQ_48000) { +		rate_list[rate_count] = 48000; +		rate_count++; +	} -	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); +	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, +							rate_count, rate_list); +	if (err < 0) +		return err;  	return 0;  } -static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream, -				snd_config_t *conf) +static int bluetooth_parse_config(snd_config_t *conf, +				struct bluetooth_alsa_config *bt_config)  { -	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;  	const char *mode, *allocation, *rate, *subbands, *blocks, *bitpool; -	switch (stream) { -	case SND_PCM_STREAM_PLAYBACK: -		cfg->fd_opt = CFG_FD_OPT_WRITE; -		break; -	case SND_PCM_STREAM_CAPTURE: -		cfg->fd_opt = CFG_FD_OPT_READ; -		break; -	} +	memset(bt_config, 0, sizeof(struct bluetooth_alsa_config));  	snd_config_for_each(i, next, conf) {  		snd_config_t *n = snd_config_iterator_entry(i); @@ -1056,7 +1095,8 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			strncpy(pkt->device, addr, 18); +			bt_config->has_device = 1; +			strncpy(bt_config->device, addr, 18);  			continue;  		} @@ -1066,14 +1106,18 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			if (strcmp(pref, "auto") == 0) -				pkt->role = PKT_ROLE_AUTO; -			else if (strcmp(pref, "voice") == 0 || +			if (strcmp(pref, "auto") == 0) { +				bt_config->transport = BT_CAPABILITIES_TRANSPORT_ANY; +				bt_config->has_transport = 1; +			} else if (strcmp(pref, "voice") == 0 ||  						strcmp(pref, "hfp") == 0) { -				pkt->role = PKT_ROLE_VOICE; +				bt_config->transport = BT_CAPABILITIES_TRANSPORT_SCO; +				bt_config->has_transport = 1;  			} else if (strcmp(pref, "hifi") == 0 || -						strcmp(pref, "a2dp") == 0) -				pkt->role = PKT_ROLE_HIFI; +						strcmp(pref, "a2dp") == 0) { +				bt_config->transport = BT_CAPABILITIES_TRANSPORT_A2DP; +				bt_config->has_transport = 1; +			}  			continue;  		} @@ -1083,7 +1127,8 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			cfg->rate = atoi(rate); +			bt_config->rate = atoi(rate); +			bt_config->has_rate = 1;  			continue;  		} @@ -1093,16 +1138,22 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			if (strcmp(pref, "auto") == 0) -				cfg->mode = CFG_MODE_AUTO; -			else if (strcmp(pref, "mono") == 0) -				cfg->mode = CFG_MODE_MONO; -			else if (strcmp(pref, "dual") == 0) -				cfg->mode = CFG_MODE_DUAL_CHANNEL; -			else if (strcmp(pref, "stereo") == 0) -				cfg->mode = CFG_MODE_STEREO; -			else if (strcmp(pref, "joint") == 0) -				cfg->mode = CFG_MODE_JOINT_STEREO; +			if (strcmp(pref, "auto") == 0) { +				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_AUTO; +				bt_config->has_channel_mode = 1; +			} else if (strcmp(pref, "mono") == 0) { +				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_MONO; +				bt_config->has_channel_mode = 1; +			} else if (strcmp(pref, "dual") == 0) { +				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; +				bt_config->has_channel_mode = 1; +			} else if (strcmp(pref, "stereo") == 0) { +				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO; +				bt_config->has_channel_mode = 1; +			} else if (strcmp(pref, "joint") == 0) { +				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO; +				bt_config->has_channel_mode = 1; +			}  			continue;  		} @@ -1112,12 +1163,16 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			if (strcmp(pref, "auto") == 0) -				sbc->allocation = CFG_ALLOCATION_AUTO; -			else if (strcmp(pref, "loudness") == 0) -				sbc->allocation = CFG_ALLOCATION_LOUDNESS; -			else if (strcmp(pref, "snr") == 0) -				sbc->allocation = CFG_ALLOCATION_SNR; +			if (strcmp(pref, "auto") == 0) { +				bt_config->allocation_method = BT_A2DP_ALLOCATION_AUTO; +				bt_config->has_allocation_method = 1; +			} else if (strcmp(pref, "loudness") == 0) { +				bt_config->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS; +				bt_config->has_allocation_method = 1; +			} else if (strcmp(pref, "snr") == 0) { +				bt_config->allocation_method = BT_A2DP_ALLOCATION_SNR; +				bt_config->has_allocation_method = 1; +			}  			continue;  		} @@ -1127,7 +1182,8 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			sbc->subbands = atoi(subbands); +			bt_config->subbands = atoi(subbands); +			bt_config->has_subbands = 1;  			continue;  		} @@ -1137,7 +1193,8 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			sbc->blocks = atoi(blocks); +			bt_config->block_length = atoi(blocks); +			bt_config->has_block_length = 1;  			continue;  		} @@ -1147,7 +1204,8 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  				return -EINVAL;  			} -			sbc->bitpool = atoi(bitpool); +			bt_config->bitpool = atoi(bitpool); +			bt_config->has_bitpool = 1;  			continue;  		} @@ -1155,139 +1213,89 @@ static int bluetooth_cfg_init(struct ipc_packet *pkt, snd_pcm_stream_t stream,  		return -EINVAL;  	} -	pkt->length = sizeof(*cfg) + sizeof(*sbc); -	pkt->type = PKT_TYPE_CFG_REQ; -	pkt->error = PKT_ERROR_NONE; -  	return 0;  } -static int bluetooth_cfg(struct bluetooth_data *data, snd_pcm_stream_t stream, -				snd_config_t *conf) +static int audioservice_send(int sk, const bt_audio_msg_header_t *msg)  { -	int ret, total; -	char buf[IPC_MTU]; -	struct ipc_packet *pkt = (void *) buf; -	struct ipc_data_cfg *cfg = (void *) pkt->data; -	struct ipc_codec_sbc *sbc = (void *) cfg->data; - -	DBG("Sending PKT_TYPE_CFG_REQ..."); - -	memset(buf, 0, sizeof(buf)); - -	ret = bluetooth_cfg_init(pkt, stream, conf); -	if (ret < 0) -		return -ret; - -	ret = send(data->server.fd, pkt, sizeof(*pkt) + pkt->length, 0); -	if (ret < 0) -		return -errno; -	else if (ret == 0) -		return -EIO; - -	DBG("OK - %d bytes sent. Waiting for response...", ret); - -	memset(buf, 0, sizeof(buf)); - -	ret = recv(data->server.fd, buf, sizeof(*pkt) + sizeof(*cfg), 0); -	if (ret < 0) -		return -errno; -	else if (ret == 0) -		return -EIO; - -	total = ret; - -	if (pkt->type != PKT_TYPE_CFG_RSP) { -		SNDERR("Unexpected packet type %d received", pkt->type); -		return -EINVAL; -	} - -	if (pkt->error != PKT_ERROR_NONE) { -		SNDERR("Error %d while configuring device", pkt->error); -		return -pkt->error; -	} - -	if (cfg->codec != CFG_CODEC_SBC) -		goto done; - -	ret = recv(data->server.fd, sbc, sizeof(*sbc), 0); -	if (ret < 0) -		return -errno; -	else if (ret == 0) -		return -EIO; - -	total += ret; - -done: -	DBG("OK - %d bytes received", total); +	int err; -	if (pkt->length != (total - sizeof(struct ipc_packet))) { -		SNDERR("Error while configuring device: packet size doesn't match"); -		return -EINVAL; +	DBG("sending %s", bt_audio_strmsg(msg->msg_type)); +	if (send(sk, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) +		err = 0; +	else { +		err = -errno; +		SNDERR("Error sending data to audio service: %s(%d)", +			strerror(errno), errno);  	} -	memcpy(&data->cfg, cfg, sizeof(*cfg)); - -	DBG("Device configuration:"); - -	DBG("\n\tfd=%d\n\tfd_opt=%u\n\tpkt_len=%u\n\tsample_size=%u\n\trate=%u", -			data->stream.fd, data->cfg.fd_opt, data->cfg.pkt_len, -			data->cfg.sample_size, data->cfg.rate); +	return err; +} -	if (data->cfg.codec == CFG_CODEC_SBC) { -		ret = bluetooth_a2dp_init(data, sbc); -		if (ret < 0) -			return ret; +static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg) +{ +	int err; +	const char *type; + +	DBG("trying to receive msg from audio service..."); +	if (recv(sk, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) { +		type = bt_audio_strmsg(inmsg->msg_type); +		if (type) { +			DBG("Received %s", type); +			err = 0; +		} else { +			err = -EINVAL; +			SNDERR("Bogus message type %d " +					"received from audio service", +					inmsg->msg_type); +		} +	} else { +		err = -errno; +		SNDERR("Error receiving data from audio service: %s(%d)", +					strerror(errno), errno);  	} -	ret = bluetooth_recvmsg_fd(data); -	if (ret < 0) -		return ret; +	return err; +} -	if (data->stream.fd == -1) { -		SNDERR("Error while configuring device: could not acquire audio socket"); -		return -EINVAL; +static int audioservice_expect(int sk, bt_audio_msg_header_t *outmsg, +				int expected_type) +{ +	int err = audioservice_recv(sk, outmsg); +	if (err == 0) { +		if (outmsg->msg_type != expected_type) { +			err = -EINVAL; +			SNDERR("Bogus message %s received while " +					"%s was expected", +					bt_audio_strmsg(outmsg->msg_type), +					bt_audio_strmsg(expected_type)); +		}  	} - -	/* It is possible there is some outstanding -	data in the pipe - we have to empty it */ -	while (recv(data->stream.fd, data->buffer, data->cfg.pkt_len, -				MSG_DONTWAIT) > 0); - -	memset(data->buffer, 0, sizeof(data->buffer)); - -	return 0; +	return err;  }  static int bluetooth_init(struct bluetooth_data *data, snd_pcm_stream_t stream,  				snd_config_t *conf)  {  	int sk, err; -	struct sockaddr_un addr = { -		AF_UNIX, IPC_SOCKET_NAME -	}; - -	if (!data) -		return -EINVAL; +	struct bluetooth_alsa_config *alsa_conf = &data->alsa_config; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_getcapabilities_req *getcaps_req = (void*) buf; +	struct bt_getcapabilities_rsp *getcaps_rsp = (void*) buf;  	memset(data, 0, sizeof(struct bluetooth_data)); +	err = bluetooth_parse_config(conf, alsa_conf); +	if (err < 0) +		return err; +  	data->server.fd = -1;  	data->stream.fd = -1; -	sk = socket(PF_LOCAL, SOCK_STREAM, 0); -	if (sk < 0) { -		err = errno; -		SNDERR("Cannot open socket: %s (%d)", strerror(err), err); -		return -err; -	} - -	DBG("Connecting to address: %s", addr.sun_path + 1); -	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -		err = errno; -		SNDERR("Connection fail", strerror(err), err); -		close(sk); -		return -err; +	sk = bt_audio_service_open(); +	if(sk <= 0) { +		err = -errno; +		goto failed;  	}  	data->server.fd = sk; @@ -1296,14 +1304,56 @@ static int bluetooth_init(struct bluetooth_data *data, snd_pcm_stream_t stream,  	data->pipefd[0] = -1;  	data->pipefd[1] = -1; -	if (pipe(data->pipefd) < 0) -		return -errno; -	if (fcntl(data->pipefd[0], F_SETFL, O_NONBLOCK) < 0) -		return -errno; -	if (fcntl(data->pipefd[1], F_SETFL, O_NONBLOCK) < 0) -		return -errno; +	if (pipe(data->pipefd) < 0) { +		err = -errno; +		goto failed; +	} +	if (fcntl(data->pipefd[0], F_SETFL, O_NONBLOCK) < 0) { +		err = -errno; +		goto failed; +	} +	if (fcntl(data->pipefd[1], F_SETFL, O_NONBLOCK) < 0) { +		err = -errno; +		goto failed; +	} + +	memset(getcaps_req, 0, BT_AUDIO_IPC_PACKET_SIZE); +	getcaps_req->h.msg_type = BT_GETCAPABILITIES_REQ; +	strncpy(getcaps_req->device, alsa_conf->device, 18); +	if (alsa_conf->has_transport) +		getcaps_req->transport = alsa_conf->transport; +	else +		getcaps_req->transport = BT_CAPABILITIES_TRANSPORT_ANY; + +	getcaps_req->access_mode = (stream == SND_PCM_STREAM_PLAYBACK ? +			BT_CAPABILITIES_ACCESS_MODE_WRITE : +			BT_CAPABILITIES_ACCESS_MODE_READ); + +	err = audioservice_send(data->server.fd, &getcaps_req->h); +	if (err < 0) +		goto failed; + +	err = audioservice_expect(data->server.fd, &getcaps_rsp->h, BT_GETCAPABILITIES_RSP); +	if (err < 0) +		goto failed; + +	if (getcaps_rsp->posix_errno != 0) { +		SNDERR("BT_GETCAPABILITIES failed : %s(%d)", +					strerror(getcaps_rsp->posix_errno), +					getcaps_rsp->posix_errno); +		return -getcaps_rsp->posix_errno; +	} + +	data->transport = getcaps_rsp->transport; +	data->link_mtu = getcaps_rsp->link_mtu; +	if (getcaps_rsp->transport == BT_CAPABILITIES_TRANSPORT_A2DP) +		data->a2dp.sbc_capabilities = getcaps_rsp->sbc_capabilities; -	return bluetooth_cfg(data, stream, conf); +	return 0; + +failed: +	bt_audio_service_close(sk); +	return err;  }  SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth) @@ -1329,7 +1379,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)  	data->io.mmap_rw = 0; /* No direct mmap communication */  	data->io.private_data = data; -	if (data->cfg.codec == CFG_CODEC_SBC) +	if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP)  		data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?  			&bluetooth_a2dp_playback :  			&bluetooth_a2dp_capture; @@ -1342,7 +1392,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)  	if (err < 0)  		goto error; -	if (data->cfg.codec == CFG_CODEC_SBC) +	if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP)  		err = bluetooth_a2dp_hw_constraint(&data->io);  	else  		err = bluetooth_hsp_hw_constraint(&data->io); diff --git a/audio/unix.c b/audio/unix.c index 71eb570a..ea96bd4f 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -79,7 +79,8 @@ struct unix_client {  		struct headset_data hs;  	} d;  	int sock; -	int fd_opt; +	int access_mode; +	int data_fd; /* To be deleted once two phase configuration is fully implemented */  	unsigned int req_id;  	unsigned int cb_id;  	gboolean (*cancel_stream) (struct device *dev, unsigned int id); @@ -89,6 +90,11 @@ static GSList *clients = NULL;  static int unix_sock = -1; +static void unix_ipc_sendmsg(struct unix_client *client, +					const bt_audio_msg_header_t *msg); + +static void send_getcapabilities_rsp_error(struct unix_client *client, int err); +  static void client_free(struct unix_client *client)  {  	struct a2dp_data *a2dp; @@ -121,7 +127,7 @@ static void client_free(struct unix_client *client)  /* Pass file descriptor through local domain sockets (AF_LOCAL, formerly AF_UNIX)  and the sendmsg() system call with the cmsg_type field of a "struct cmsghdr" set -to SCM_RIGHTS and the data being an integer value equal to the handle of the  +to SCM_RIGHTS and the data being an integer value equal to the handle of the  file descriptor to be passed.*/  static int unix_sendmsg_fd(int sock, int fd)  { @@ -193,77 +199,29 @@ static void stream_state_changed(struct avdtp_stream *stream,  	}  } -static int unix_send_cfg(int sock, struct ipc_data_cfg *cfg, int fd) -{ -	char buf[IPC_MTU]; -	struct ipc_packet *pkt = (void *) buf; -	int len, codec_len; - -	memset(buf, 0, sizeof(buf)); - -	pkt->type = PKT_TYPE_CFG_RSP; - -	if (!cfg) { -		pkt->error = EINVAL; -		len = send(sock, pkt, sizeof(struct ipc_packet), 0); -		if (len < 0) -			error("send: %s (%d)", strerror(errno), errno); -		return len; -	} - -	debug("fd=%d, fd_opt=%u, pkt_len=%u, sample_size=%u, rate=%u", -						fd, cfg->fd_opt, cfg->pkt_len, -						cfg->sample_size, cfg->rate); - -	if (cfg->codec == CFG_CODEC_SBC) -		codec_len = sizeof(struct ipc_codec_sbc); -	else -		codec_len = 0; - -	pkt->error = PKT_ERROR_NONE; -	pkt->length = sizeof(struct ipc_data_cfg) + codec_len; -	memcpy(pkt->data, cfg, pkt->length); - -	len = sizeof(struct ipc_packet) + pkt->length; -	len = send(sock, pkt, len, 0); -	if (len < 0) -		error("Error %s(%d)", strerror(errno), errno); - -	debug("%d bytes sent", len); - -	if (fd != -1) { -		len = unix_sendmsg_fd(sock, fd); -		if (len < 0) -			error("Error %s(%d)", strerror(errno), errno); -		debug("%d bytes sent", len); -	} - -	return 0; -} -  static void headset_setup_complete(struct device *dev, void *user_data)  {  	struct unix_client *client = user_data; -	struct ipc_data_cfg cfg; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_getcapabilities_rsp *rsp = (void *) buf;  	struct headset_data *hs = &client->d.hs; -	int fd;  	client->req_id = 0;  	if (!dev) { -		unix_send_cfg(client->sock, NULL, -1); +		send_getcapabilities_rsp_error(client, EIO);  		client->dev = NULL;  		return;  	} -	switch (client->fd_opt) { -	case CFG_FD_OPT_READ: +	switch (client->access_mode) { +	case BT_CAPABILITIES_ACCESS_MODE_READ:  		hs->lock = HEADSET_LOCK_READ;  		break; -	case CFG_FD_OPT_WRITE: +	case BT_CAPABILITIES_ACCESS_MODE_WRITE:  		hs->lock = HEADSET_LOCK_WRITE;  		break; -	case CFG_FD_OPT_READWRITE: +	case BT_CAPABILITIES_ACCESS_MODE_READWRITE:  		hs->lock = HEADSET_LOCK_READ | HEADSET_LOCK_WRITE;  		break;  	default: @@ -273,23 +231,22 @@ static void headset_setup_complete(struct device *dev, void *user_data)  	if (!headset_lock(dev, hs->lock)) {  		error("Unable to lock headset"); -		unix_send_cfg(client->sock, NULL, -1); +		send_getcapabilities_rsp_error(client, EIO);  		client->dev = NULL;  		return;  	} -	memset(&cfg, 0, sizeof(cfg)); +	memset(buf, 0, sizeof(buf)); -	cfg.fd_opt = client->fd_opt; -	cfg.codec = CFG_CODEC_SCO; -	cfg.mode = CFG_MODE_MONO; -	cfg.pkt_len = 48; -	cfg.sample_size = 2; -	cfg.rate = 8000; +	rsp->h.msg_type = BT_GETCAPABILITIES_RSP; +	rsp->transport  = BT_CAPABILITIES_TRANSPORT_SCO; +	rsp->access_mode = client->access_mode; +	rsp->link_mtu = 48; +	rsp->sampling_rate = 8000; -	fd = headset_get_sco_fd(dev); +	client->data_fd = headset_get_sco_fd(dev); -	unix_send_cfg(client->sock, &cfg, fd); +	unix_ipc_sendmsg(client, &rsp->h);  }  static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep, @@ -297,17 +254,16 @@ static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,  					void *user_data, struct avdtp_error *err)  {  	struct unix_client *client = user_data; -	char buf[sizeof(struct ipc_data_cfg) + sizeof(struct ipc_codec_sbc)]; -	struct ipc_data_cfg *cfg = (void *) buf; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_getcapabilities_rsp *rsp = (void *) buf;  	struct avdtp_service_capability *cap;  	struct avdtp_media_codec_capability *codec_cap;  	struct sbc_codec_cap *sbc_cap; -	struct ipc_codec_sbc *sbc = (void *) cfg->data;  	struct a2dp_data *a2dp = &client->d.a2dp; -	int fd;  	uint16_t imtu, omtu;  	GSList *caps; +	memset(buf, 0, sizeof(buf));  	client->req_id = 0;  	if (!stream) @@ -321,7 +277,7 @@ static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,  	a2dp->sep = sep;  	a2dp->stream = stream; -	if (!avdtp_stream_get_transport(stream, &fd, &imtu, &omtu, &caps)) { +	if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu, &caps)) {  		error("Unable to get stream transport");  		goto failed;  	} @@ -340,66 +296,27 @@ static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,  		goto failed;  	} +	rsp->h.msg_type = BT_GETCAPABILITIES_RSP; +	rsp->transport = BT_CAPABILITIES_TRANSPORT_A2DP; +	client->access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE; +	rsp->access_mode = client->access_mode;  	/* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */ -	cfg->pkt_len = omtu; -	cfg->fd_opt = CFG_FD_OPT_WRITE; +	rsp->link_mtu = omtu;  	sbc_cap = (void *) codec_cap; -	cfg->sample_size = 2; -	switch (sbc_cap->channel_mode) { -	case A2DP_CHANNEL_MODE_MONO: -		cfg->mode = CFG_MODE_MONO; -		break; -	case A2DP_CHANNEL_MODE_DUAL_CHANNEL: -		cfg->mode = CFG_MODE_DUAL_CHANNEL; -		break; -	case A2DP_CHANNEL_MODE_STEREO: -		cfg->mode = CFG_MODE_STEREO; -		break; -	case A2DP_CHANNEL_MODE_JOINT_STEREO: -		cfg->mode = CFG_MODE_JOINT_STEREO; -		break; -	} +	/* assignations below are ok as soon as newipc.h and a2dp.h are kept */ +	/* in sync. However it is not possible to cast a struct to another   */ +	/* dues to endianess issues */ +	rsp->sbc_capabilities.channel_mode = sbc_cap->channel_mode; +	rsp->sbc_capabilities.frequency = sbc_cap->frequency; +	rsp->sbc_capabilities.allocation_method = sbc_cap->allocation_method; +	rsp->sbc_capabilities.subbands = sbc_cap->subbands; +	rsp->sbc_capabilities.block_length = sbc_cap->block_length; +	rsp->sbc_capabilities.min_bitpool = sbc_cap->min_bitpool; +	rsp->sbc_capabilities.max_bitpool = sbc_cap->max_bitpool; -	switch (sbc_cap->frequency) { -	case A2DP_SAMPLING_FREQ_16000: -		cfg->rate = 16000; -		break; -	case A2DP_SAMPLING_FREQ_32000: -		cfg->rate = 32000; -		break; -	case A2DP_SAMPLING_FREQ_44100: -		cfg->rate = 44100; -		break; -	case A2DP_SAMPLING_FREQ_48000: -		cfg->rate = 48000; -		break; -	} - -	cfg->codec = CFG_CODEC_SBC; -	sbc->allocation = sbc_cap->allocation_method == A2DP_ALLOCATION_SNR ? -								0x01 : 0x00; -	sbc->subbands = sbc_cap->subbands == A2DP_SUBBANDS_4 ? 4 : 8; - -	switch (sbc_cap->block_length) { -	case A2DP_BLOCK_LENGTH_4: -		sbc->blocks = 4; -		break; -	case A2DP_BLOCK_LENGTH_8: -		sbc->blocks = 8; -		break; -	case A2DP_BLOCK_LENGTH_12: -		sbc->blocks = 12; -		break; -	case A2DP_BLOCK_LENGTH_16: -		sbc->blocks = 16; -		break; -	} - -	sbc->bitpool = sbc_cap->max_bitpool; - -	unix_send_cfg(client->sock, cfg, fd); +	unix_ipc_sendmsg(client, &rsp->h);  	client->cb_id = avdtp_stream_add_cb(session, stream,  						stream_state_changed, client); @@ -412,7 +329,7 @@ failed:  		a2dp_sep_unlock(a2dp->sep, a2dp->session);  		a2dp->sep = NULL;  	} -	unix_send_cfg(client->sock, NULL, -1); +	send_getcapabilities_rsp_error(client, EIO);  	avdtp_unref(a2dp->session); @@ -469,7 +386,7 @@ static void create_stream(struct device *dev, struct unix_client *client)  	return;  failed: -	unix_send_cfg(client->sock, NULL, -1); +	send_getcapabilities_rsp_error(client, EIO);  }  static void create_cb(struct device *dev, void *user_data) @@ -477,135 +394,57 @@ static void create_cb(struct device *dev, void *user_data)  	struct unix_client *client = user_data;  	if (!dev) -		unix_send_cfg(client->sock, NULL, -1); +		send_getcapabilities_rsp_error(client, EIO);  	else  		create_stream(dev, client);  } -static int cfg_to_caps(struct ipc_data_cfg *cfg, struct sbc_codec_cap *sbc_cap) +static void unix_ipc_sendmsg(struct unix_client *client, +					const bt_audio_msg_header_t *msg)  { -	struct ipc_codec_sbc *sbc = (void *) cfg->data; - -	memset(sbc_cap, 0, sizeof(struct sbc_codec_cap)); - -	sbc_cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; -	sbc_cap->cap.media_codec_type = A2DP_CODEC_SBC; - -	switch (cfg->rate) { -	case 48000: -		sbc_cap->frequency = A2DP_SAMPLING_FREQ_48000; -		break; -	case 44100: -		sbc_cap->frequency = A2DP_SAMPLING_FREQ_44100; -		break; -	case 32000: -		sbc_cap->frequency = A2DP_SAMPLING_FREQ_32000; -		break; -	case 16000: -		sbc_cap->frequency = A2DP_SAMPLING_FREQ_16000; -		break; -	default: -		sbc_cap->frequency = A2DP_SAMPLING_FREQ_44100; -		break; -	} - -	switch (cfg->mode) { -	case CFG_MODE_MONO: -		sbc_cap->channel_mode = A2DP_CHANNEL_MODE_MONO; -		break; -	case CFG_MODE_DUAL_CHANNEL: -		sbc_cap->channel_mode = A2DP_CHANNEL_MODE_DUAL_CHANNEL; -		break; -	case CFG_MODE_STEREO: -		sbc_cap->channel_mode = A2DP_CHANNEL_MODE_STEREO; -		break; -	case CFG_MODE_JOINT_STEREO: -		sbc_cap->channel_mode = A2DP_CHANNEL_MODE_JOINT_STEREO; -		break; -	default: -		sbc_cap->channel_mode = A2DP_CHANNEL_MODE_JOINT_STEREO; -		break; -	} - -	switch (sbc->allocation) { -	case CFG_ALLOCATION_LOUDNESS: -		sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS; -		break; -	case CFG_ALLOCATION_SNR: -		sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS; -		break; -	default: -		sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS; -		break; -	} - -	switch (sbc->subbands) { -	case 8: -		sbc_cap->subbands = A2DP_SUBBANDS_8; -		break; -	case 4: -		sbc_cap->subbands = A2DP_SUBBANDS_4; -		break; -	default: -		sbc_cap->subbands = A2DP_SUBBANDS_8; -		break; -	} - -	switch (sbc->blocks) { -	case 16: -		sbc_cap->block_length = A2DP_BLOCK_LENGTH_16; -		break; -	case 12: -		sbc_cap->block_length = A2DP_BLOCK_LENGTH_12; -		break; -	case 8: -		sbc_cap->block_length = A2DP_BLOCK_LENGTH_8; -		break; -	case 4: -		sbc_cap->block_length = A2DP_BLOCK_LENGTH_4; -		break; -	default: -		sbc_cap->block_length = A2DP_BLOCK_LENGTH_16; -		break; -	} +	info("Audio API: sending %s", bt_audio_strmsg(msg->msg_type)); +	if (send(client->sock, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) < 0) +		error("Error %s(%d)", strerror(errno), errno); +} -	if (sbc->bitpool != 0) { -		if (sbc->bitpool > 250) -			return -EINVAL; +static void send_getcapabilities_rsp_error(struct unix_client *client, int err) +{ +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_getcapabilities_rsp *rsp = (void *) buf; -		sbc_cap->min_bitpool = sbc->bitpool; -		sbc_cap->max_bitpool = sbc->bitpool; -	} +	memset(buf, 0, sizeof(buf)); +	rsp->h.msg_type = BT_GETCAPABILITIES_RSP; +	rsp->posix_errno = err; -	return 0; +	unix_ipc_sendmsg(client, &rsp->h);  } -static void cfg_event(struct unix_client *client, struct ipc_packet *pkt, int len) +static void handle_getcapabilities_req(struct unix_client *client, +					struct bt_getcapabilities_req *req)  {  	struct device *dev;  	bdaddr_t bdaddr; -	struct ipc_data_cfg *cfg = (void *) pkt->data; -	struct sbc_codec_cap sbc_cap; -	str2ba(pkt->device, &bdaddr); +	str2ba(req->device, &bdaddr); + +	if (!req->access_mode) { +		send_getcapabilities_rsp_error(client, EINVAL); +		return; +	} -	client->fd_opt = cfg->fd_opt; +	client->access_mode = req->access_mode;  	if (client->interface) {  		g_free(client->interface);  		client->interface = NULL;  	} -	if (pkt->role == PKT_ROLE_VOICE) +	if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)  		client->interface = g_strdup(AUDIO_HEADSET_INTERFACE); -	else if (pkt->role == PKT_ROLE_HIFI) +	else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)  		client->interface = g_strdup(AUDIO_SINK_INTERFACE); -	if (cfg_to_caps(cfg, &sbc_cap) < 0) -		goto failed; - -	client->media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, -						&sbc_cap, sizeof(sbc_cap)); +	client->media_codec = 0;  	if (!manager_find_device(&bdaddr, NULL, FALSE)) {  		if (!bacmp(&bdaddr, BDADDR_ANY)) @@ -627,59 +466,83 @@ static void cfg_event(struct unix_client *client, struct ipc_packet *pkt, int le  	return;  failed: -	unix_send_cfg(client->sock, NULL, -1); +	send_getcapabilities_rsp_error(client, EIO);  } -static void ctl_event(struct unix_client *client, -					struct ipc_packet *pkt, int len) +static void handle_setconfiguration_req(struct unix_client *client, +					struct bt_setconfiguration_req *req)  { +	/* FIXME: for now we just blindly assume that we receive is the +	   only valid configuration sent.*/ +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_setconfiguration_rsp *rsp = (void *) buf; + +	memset(buf, 0, sizeof(buf)); +	rsp->h.msg_type = BT_SETCONFIGURATION_RSP; +	rsp->posix_errno = 0; + +	unix_ipc_sendmsg(client, &rsp->h);  } -static int reply_state(int sock, struct ipc_packet *pkt) +static void handle_streamstart_req(struct unix_client *client, +					struct bt_streamstart_req *req)  { -	struct ipc_data_state *state = (struct ipc_data_state *) pkt->data; -	int len; +	/* FIXME : to be really implemented */ +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_streamstart_rsp *rsp = (void *) buf; +	struct bt_datafd_ind *ind = (void *) buf; -	info("status=%u", state->state); +	memset(buf, 0, sizeof(buf)); +	rsp->h.msg_type = BT_STREAMSTART_RSP; +	rsp->posix_errno = 0; +	unix_ipc_sendmsg(client, &rsp->h); -	pkt->type = PKT_TYPE_STATE_RSP; -	pkt->length = sizeof(struct ipc_data_state); -	pkt->error = PKT_ERROR_NONE; +	memset(buf, 0, sizeof(buf)); +	ind->h.msg_type = BT_STREAMFD_IND; +	unix_ipc_sendmsg(client, &ind->h); -	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_state); -	len = send(sock, pkt, len, 0); -	if (len < 0) -		error("Error %s(%d)", strerror(errno), errno); +	if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) +		error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno); + +} -	debug("%d bytes sent", len); +static void handle_streamstop_req(struct unix_client *client, +					struct bt_streamstop_req *req) +{ +	/* FIXME : to be implemented */ +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_streamstop_rsp *rsp = (void *) buf; -	return 0; +	memset(buf, 0, sizeof(buf)); +	rsp->h.msg_type = BT_STREAMSTOP_RSP; +	rsp->posix_errno = 0; + +	unix_ipc_sendmsg(client, &rsp->h);  } -static void state_event(struct unix_client *client, -					struct ipc_packet *pkt, int len) +static void handle_control_req(struct unix_client *client, +					struct bt_control_req *req)  { -#if 0 -	struct ipc_data_state *state = (struct ipc_data_state *) pkt->data; -	struct device *dev = client->dev; +	/* FIXME: really implement that */ +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	struct bt_setconfiguration_rsp *rsp = (void *) buf; -	if (len > sizeof(struct ipc_packet)) -		device_set_state(dev, state->state); -	else -		state->state = device_get_state(dev); -#endif +	memset(buf, 0, sizeof(buf)); +	rsp->h.msg_type = BT_CONTROL_RSP; +	rsp->posix_errno = 0; -	reply_state(client->sock, pkt); +	unix_ipc_sendmsg(client, &rsp->h);  }  static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)  { -	char buf[IPC_MTU]; -	struct ipc_packet *pkt = (void *) buf; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	bt_audio_msg_header_t *msghdr = (void *) buf;  	struct unix_client *client = data; -	int len, len_check; +	int len;  	struct a2dp_data *a2dp = &client->d.a2dp;  	struct headset_data *hs = &client->d.hs; +	const char *type;  	if (cond & G_IO_NVAL)  		return FALSE; @@ -709,31 +572,39 @@ static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)  	memset(buf, 0, sizeof(buf)); -	len = recv(client->sock, buf, sizeof(buf), 0); +	len = recv(client->sock, buf, sizeof(buf), MSG_WAITALL);  	if (len < 0) {  		error("recv: %s (%d)", strerror(errno), errno);  		goto failed;  	} -	len_check = pkt->length + sizeof(struct ipc_packet); -	if (len != len_check) { -		error("Packet lenght doesn't match"); -		goto failed; -	} +	if ((type = bt_audio_strmsg(msghdr->msg_type))) +		info("Audio API: received %s", type); -	switch (pkt->type) { -	case PKT_TYPE_CFG_REQ: -		info("Package PKT_TYPE_CFG_REQ:%u", pkt->role); -		cfg_event(client, pkt, len); +	switch (msghdr->msg_type) { +	case BT_GETCAPABILITIES_REQ: +		handle_getcapabilities_req(client, +				(struct bt_getcapabilities_req *) msghdr);  		break; -	case PKT_TYPE_STATE_REQ: -		info("Package PKT_TYPE_STATE_REQ"); -		state_event(client, pkt, len); +	case BT_SETCONFIGURATION_REQ: +		handle_setconfiguration_req(client, +				(struct bt_setconfiguration_req *) msghdr);  		break; -	case PKT_TYPE_CTL_REQ: -		info("Package PKT_TYPE_CTL_REQ"); -		ctl_event(client, pkt, len); +	case BT_STREAMSTART_REQ: +		handle_streamstart_req(client, +				(struct bt_streamstart_req *) msghdr);  		break; +	case BT_STREAMSTOP_REQ: +		handle_streamstop_req(client, +				(struct bt_streamstop_req *) msghdr); +		break; +	case BT_CONTROL_REQ: +		handle_control_req(client, +				(struct bt_control_req *) msghdr); +		break; +	default: +		error("Audio API: received unexpected packet type %d", +				msghdr->msg_type);  	}  	return TRUE; @@ -789,7 +660,7 @@ int unix_init(void)  {  	GIOChannel *io;  	struct sockaddr_un addr = { -		AF_UNIX, IPC_SOCKET_NAME +		AF_UNIX, BT_IPC_SOCKET_NAME  	};  	int sk, err; | 
