Beispiel #1
0
static void gateway_resume_complete(struct audio_device *dev, GError *err, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_start_stream_rsp *rsp = (void *) buf;
	struct bt_new_stream_ind *ind = (void *) buf;

	if (err) {
		unix_ipc_error(client, BT_START_STREAM, err->code);
		return;
	}

	memset(buf, 0, sizeof(buf));
	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_START_STREAM;
	rsp->h.length = sizeof(*rsp);

	unix_ipc_sendmsg(client, &rsp->h);

	memset(buf, 0, sizeof(buf));
	ind->h.type = BT_INDICATION;
	ind->h.name = BT_NEW_STREAM;
	ind->h.length = sizeof(*ind);

	unix_ipc_sendmsg(client, &ind->h);

	client->data_fd = gateway_get_sco_fd(dev);
	if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
		error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
		unix_ipc_error(client, BT_START_STREAM, EIO);
	}

	client->req_id = 0;
}
Beispiel #2
0
static void headset_setup_complete(struct audio_device *dev, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_set_configuration_rsp *rsp = (void *) buf;

	client->req_id = 0;

	if (!dev)
		goto failed;

	memset(buf, 0, sizeof(buf));

	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_SET_CONFIGURATION;
	rsp->h.length = sizeof(*rsp);

	rsp->link_mtu = 48;

	client->data_fd = headset_get_sco_fd(dev);

	unix_ipc_sendmsg(client, &rsp->h);

	return;

failed:
	error("config failed");
	unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
Beispiel #3
0
static void a2dp_suspend_complete(struct avdtp *session,
				struct avdtp_error *err, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_stop_stream_rsp *rsp = (void *) buf;
	struct a2dp_data *a2dp = &client->d.a2dp;

	if (err)
		goto failed;

	memset(buf, 0, sizeof(buf));
	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_STOP_STREAM;
	rsp->h.length = sizeof(*rsp);

	unix_ipc_sendmsg(client, &rsp->h);

	return;

failed:
	error("suspend failed");

	unix_ipc_error(client, BT_STOP_STREAM, EIO);

	if (a2dp->sep) {
		a2dp_sep_unlock(a2dp->sep, a2dp->session);
		a2dp->sep = NULL;
	}

	avdtp_unref(a2dp->session);
	a2dp->session = NULL;
	a2dp->stream = NULL;
}
Beispiel #4
0
static void headset_discovery_complete(struct audio_device *dev, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_get_capabilities_rsp *rsp = (void *) buf;
	uint8_t length;

	client->req_id = 0;

	if (!dev)
		goto failed;

	memset(buf, 0, sizeof(buf));

	length = headset_generate_capability(dev, (void *) rsp->data);

	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_GET_CAPABILITIES;
	rsp->h.length = sizeof(*rsp) + length;

	ba2str(&dev->src, rsp->source);
	ba2str(&dev->dst, rsp->destination);
	strncpy(rsp->object, dev->path, sizeof(rsp->object));

	unix_ipc_sendmsg(client, &rsp->h);

	return;

failed:
	error("discovery failed");
	unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
Beispiel #5
0
static void gateway_setup_complete(struct audio_device *dev, GError *err, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_set_configuration_rsp *rsp = (void *) buf;

	if (err) {
		unix_ipc_error(client, BT_SET_CONFIGURATION, err->code);
		return;
	}

	client->req_id = 0;

	memset(buf, 0, sizeof(buf));

	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_SET_CONFIGURATION;
	rsp->h.length = sizeof(*rsp);

	rsp->link_mtu = 48;

	client->data_fd = gateway_get_sco_fd(dev);

	unix_ipc_sendmsg(client, &rsp->h);
}
Beispiel #6
0
static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
					struct avdtp_stream *stream,
					struct avdtp_error *err,
					void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_set_configuration_rsp *rsp = (void *) buf;
	struct a2dp_data *a2dp = &client->d.a2dp;
	uint16_t imtu, omtu;
	GSList *caps;

	client->req_id = 0;

	if (err)
		goto failed;

	memset(buf, 0, sizeof(buf));

	if (!stream)
		goto failed;

	if (client->cb_id > 0)
		avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
								client->cb_id);

	a2dp->sep = sep;
	a2dp->stream = stream;

	if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu,
					&caps)) {
		error("Unable to get stream transport");
		goto failed;
	}

	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_SET_CONFIGURATION;
	rsp->h.length = sizeof(*rsp);

	/* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */
	rsp->link_mtu = omtu;

	unix_ipc_sendmsg(client, &rsp->h);

	client->cb_id = avdtp_stream_add_cb(session, stream,
						stream_state_changed, client);

	return;

failed:
	error("config failed");

	unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);

	avdtp_unref(a2dp->session);

	a2dp->session = NULL;
	a2dp->stream = NULL;
	a2dp->sep = NULL;
}
Beispiel #7
0
static void start_close(struct audio_device *dev, struct unix_client *client,
			gboolean reply)
{
	struct a2dp_data *a2dp;
	struct headset_data *hs;

	if (!client->dev)
		goto failed;

	switch (client->type) {
	case TYPE_HEADSET:
		hs = &client->d.hs;

		if (client->dev && hs->locked) {
			headset_unlock(client->dev, client->lock);
			hs->locked = FALSE;
		}
		break;
        case TYPE_GATEWAY:
                break;
	case TYPE_SOURCE:
	case TYPE_SINK:
		a2dp = &client->d.a2dp;

		if (client->cb_id > 0) {
			avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
								client->cb_id);
			client->cb_id = 0;
		}
		if (a2dp->sep) {
			a2dp_sep_unlock(a2dp->sep, a2dp->session);
			a2dp->sep = NULL;
		}
		if (a2dp->session) {
			avdtp_unref(a2dp->session);
			a2dp->session = NULL;
		}
		a2dp->stream = NULL;
		break;
	default:
		error("No known services for device");
		goto failed;
	}

	if (!reply)
		return;

	close_complete(dev, client);
	client->dev = NULL;

	return;

failed:
	if (reply)
		unix_ipc_error(client, BT_STOP_STREAM, EINVAL);
}
Beispiel #8
0
static void a2dp_resume_complete(struct avdtp *session,
				struct avdtp_error *err, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_start_stream_rsp *rsp = (void *) buf;
	struct bt_new_stream_ind *ind = (void *) buf;
	struct a2dp_data *a2dp = &client->d.a2dp;

	if (err)
		goto failed;

	memset(buf, 0, sizeof(buf));
	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_START_STREAM;
	rsp->h.length = sizeof(*rsp);

	unix_ipc_sendmsg(client, &rsp->h);

	memset(buf, 0, sizeof(buf));
	ind->h.type = BT_RESPONSE;
	ind->h.name = BT_NEW_STREAM;
	rsp->h.length = sizeof(*ind);

	unix_ipc_sendmsg(client, &ind->h);

	if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
		error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
		goto failed;
	}

	return;

failed:
	error("resume failed");

	unix_ipc_error(client, BT_START_STREAM, EIO);

	if (client->cb_id > 0) {
		avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
					client->cb_id);
		client->cb_id = 0;
	}

	if (a2dp->sep) {
		a2dp_sep_unlock(a2dp->sep, a2dp->session);
		a2dp->sep = NULL;
	}

	avdtp_unref(a2dp->session);
	a2dp->session = NULL;
	a2dp->stream = NULL;
}
Beispiel #9
0
static void handle_close_req(struct unix_client *client,
				struct bt_close_req *req)
{
	if (!client->dev)
		goto failed;

	start_close(client->dev, client, TRUE);

	return;

failed:
	unix_ipc_error(client, BT_CLOSE, EIO);
}
Beispiel #10
0
static void handle_streamstop_req(struct unix_client *client,
					struct bt_stop_stream_req *req)
{
	if (!client->dev)
		goto failed;

	start_suspend(client->dev, client);

	return;

failed:
	unix_ipc_error(client, BT_STOP_STREAM, EIO);
}
Beispiel #11
0
static void handle_delay_report_req(struct unix_client *client,
					struct bt_delay_report_req *req)
{
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_set_configuration_rsp *rsp = (void *) buf;
	struct a2dp_data *a2dp;
	int err;

	if (!client->dev) {
		err = -ENODEV;
		goto failed;
	}

	switch (client->type) {
	case TYPE_HEADSET:
        case TYPE_GATEWAY:
		err = -EINVAL;
		goto failed;
	case TYPE_SOURCE:
	case TYPE_SINK:
		a2dp = &client->d.a2dp;
		if (a2dp->session && a2dp->stream) {
			err = avdtp_delay_report(a2dp->session, a2dp->stream,
								req->delay);
			if (err < 0)
				goto failed;
		} else {
			err = -EINVAL;
			goto failed;
		}
		break;
	default:
		error("No known services for device");
		err = -EINVAL;
		goto failed;
	}

	memset(buf, 0, sizeof(buf));
	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_DELAY_REPORT;
	rsp->h.length = sizeof(*rsp);

	unix_ipc_sendmsg(client, &rsp->h);

	return;

failed:
	unix_ipc_error(client, BT_DELAY_REPORT, -err);
}
Beispiel #12
0
static void headset_resume_complete(struct audio_device *dev, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_start_stream_rsp *rsp = (void *) buf;
	struct bt_new_stream_ind *ind = (void *) buf;

	client->req_id = 0;

	if (!dev)
		goto failed;

	client->data_fd = headset_get_sco_fd(dev);
	if (client->data_fd < 0) {
		error("Unable to get a SCO fd");
		goto failed;
	}

	memset(buf, 0, sizeof(buf));
	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_START_STREAM;
	rsp->h.length = sizeof(*rsp);

	unix_ipc_sendmsg(client, &rsp->h);

	memset(buf, 0, sizeof(buf));
	ind->h.type = BT_INDICATION;
	ind->h.name = BT_NEW_STREAM;
	ind->h.length = sizeof(*ind);

	unix_ipc_sendmsg(client, &ind->h);

	if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
		error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
		goto failed;
	}

	return;

failed:
	error("headset_resume_complete: resume failed");
	unix_ipc_error(client, BT_START_STREAM, EIO);
}
Beispiel #13
0
static void headset_suspend_complete(struct audio_device *dev, void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_stop_stream_rsp *rsp = (void *) buf;

	if (!dev)
		goto failed;

	memset(buf, 0, sizeof(buf));
	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_STOP_STREAM;
	rsp->h.length = sizeof(*rsp);

	unix_ipc_sendmsg(client, &rsp->h);

	return;

failed:
	error("suspend failed");
	unix_ipc_error(client, BT_STOP_STREAM, EIO);
}
Beispiel #14
0
static void a2dp_discovery_complete(struct avdtp *session, GSList *seps,
					struct avdtp_error *err,
					void *user_data)
{
	struct unix_client *client = user_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_get_capabilities_rsp *rsp = (void *) buf;
	struct a2dp_data *a2dp = &client->d.a2dp;
	GSList *l;

	if (!g_slist_find(clients, client)) {
		DBG("Client disconnected during discovery");
		return;
	}

	if (err)
		goto failed;

	memset(buf, 0, sizeof(buf));
	client->req_id = 0;

	rsp->h.type = BT_RESPONSE;
	rsp->h.name = BT_GET_CAPABILITIES;
	rsp->h.length = sizeof(*rsp);
	ba2str(&client->dev->src, rsp->source);
	ba2str(&client->dev->dst, rsp->destination);
	strncpy(rsp->object, client->dev->path, sizeof(rsp->object));

	for (l = seps; l; l = g_slist_next(l)) {
		struct avdtp_remote_sep *rsep = l->data;
		struct a2dp_sep *sep;
		struct avdtp_service_capability *cap;
		struct avdtp_stream *stream;
		uint8_t type, seid, configured = 0, lock = 0;
		GSList *cl;

		type = avdtp_get_type(rsep);

		if (type != AVDTP_SEP_TYPE_SINK &&
						type != AVDTP_SEP_TYPE_SOURCE)
			continue;

		cap = avdtp_get_codec(rsep);

		if (cap->category != AVDTP_MEDIA_CODEC)
			continue;

		seid = avdtp_get_seid(rsep);

		if (client->seid != 0 && client->seid != seid)
			continue;

		stream = avdtp_get_stream(rsep);
		if (stream) {
			configured = 1;
			if (client->seid == seid)
				cap = avdtp_stream_get_codec(stream);
		}

		for (cl = clients; cl; cl = cl->next) {
			struct unix_client *c = cl->data;
			struct a2dp_data *ca2dp = &c->d.a2dp;

			if (ca2dp->session == session && c->seid == seid) {
				lock = c->lock;
				break;
			}
		}

		sep = a2dp_get_sep(session, stream);
		if (sep && a2dp_sep_get_lock(sep))
			lock = BT_WRITE_LOCK;

		a2dp_append_codec(rsp, cap, seid, type, configured, lock);
	}

	unix_ipc_sendmsg(client, &rsp->h);

	return;

failed:
	error("discovery failed");
	unix_ipc_error(client, BT_GET_CAPABILITIES, EIO);

	if (a2dp->sep) {
		a2dp_sep_unlock(a2dp->sep, a2dp->session);
		a2dp->sep = NULL;
	}

	avdtp_unref(a2dp->session);
	a2dp->session = NULL;
	a2dp->stream = NULL;
}
Beispiel #15
0
static void start_resume(struct audio_device *dev, struct unix_client *client)
{
	struct a2dp_data *a2dp = NULL;
	struct headset_data *hs;
	unsigned int id;
	struct avdtp *session = NULL;

	switch (client->type) {
	case TYPE_SINK:
	case TYPE_SOURCE:
		a2dp = &client->d.a2dp;

		if (!a2dp->sep) {
			error("seid not opened");
			goto failed;
		}

		if (!a2dp->session) {
			session = avdtp_get(&dev->src, &dev->dst);
			if (!session) {
				error("Unable to get a session");
				goto failed;
			}
			a2dp->session = session;
		}

		id = a2dp_resume(a2dp->session, a2dp->sep, a2dp_resume_complete,
					client);
		client->cancel = a2dp_cancel;

		break;

	case TYPE_HEADSET:
		hs = &client->d.hs;

		if (!hs->locked) {
			error("seid not opened");
			goto failed;
		}

		id = headset_request_stream(dev, headset_resume_complete,
						client);
		client->cancel = headset_cancel_stream;
		break;

	case TYPE_GATEWAY:
		id = gateway_request_stream(dev, gateway_resume_complete,
						client);
		client->cancel = gateway_cancel_stream;
		break;

	default:
		error("No known services for device");
		goto failed;
	}

	if (id == 0) {
		error("start_resume: resume failed");
		goto failed;
	}

	client->req_id = id;

	return;

failed:
	if (session) {
		avdtp_unref(session);
		a2dp->session = NULL;
	}

	unix_ipc_error(client, BT_START_STREAM, EIO);
}
Beispiel #16
0
static void start_open(struct audio_device *dev, struct unix_client *client)
{
	struct a2dp_data *a2dp;
	struct headset_data *hs;
	struct avdtp_remote_sep *rsep;
	gboolean unref_avdtp_on_fail = FALSE;

	switch (client->type) {
	case TYPE_SINK:
	case TYPE_SOURCE:
		a2dp = &client->d.a2dp;

		if (!a2dp->session) {
			a2dp->session = avdtp_get(&dev->src, &dev->dst);
			unref_avdtp_on_fail = TRUE;
		}

		if (!a2dp->session) {
			error("Unable to get a session");
			goto failed;
		}

		if (a2dp->sep) {
			error("Client already has an opened session");
			goto failed;
		}

		rsep = avdtp_get_remote_sep(a2dp->session, client->seid);
		if (!rsep) {
			error("Invalid seid %d", client->seid);
			goto failed;
		}

		a2dp->sep = a2dp_get(a2dp->session, rsep);
		if (!a2dp->sep) {
			error("seid %d not available or locked", client->seid);
			goto failed;
		}

		if (!a2dp_sep_lock(a2dp->sep, a2dp->session)) {
			error("Unable to open seid %d", client->seid);
			a2dp->sep = NULL;
			goto failed;
		}

		break;

	case TYPE_HEADSET:
		hs = &client->d.hs;

		if (hs->locked) {
			error("Client already has an opened session");
			goto failed;
		}

		hs->locked = headset_lock(dev, client->lock);
		if (!hs->locked) {
			error("Unable to open seid %d", client->seid);
			goto failed;
		}
		break;

        case TYPE_GATEWAY:
                break;
	default:
		error("No known services for device");
		goto failed;
	}

	client->dev = dev;

	open_complete(dev, client);

	return;

failed:
	if (unref_avdtp_on_fail && a2dp->session) {
		avdtp_unref(a2dp->session);
		a2dp->session = NULL;
	}
	unix_ipc_error(client, BT_OPEN, EINVAL);
}
Beispiel #17
0
static void handle_getcapabilities_req(struct unix_client *client,
					struct bt_get_capabilities_req *req)
{
	struct audio_device *dev;
	bdaddr_t src, dst;
	int err = EIO;
	const char *interface;

	if (!check_nul(req->source) || !check_nul(req->destination) ||
			!check_nul(req->object)) {
		err = EINVAL;
		goto failed;
	}

	str2ba(req->source, &src);
	str2ba(req->destination, &dst);

	if (!manager_find_device(req->object, &src, &dst, NULL, FALSE))
		goto failed;

	if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
		interface = AUDIO_HEADSET_INTERFACE;
	else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
		interface = AUDIO_SINK_INTERFACE;
	else
		interface = client->interface;

	dev = manager_find_device(req->object, &src, &dst, interface, TRUE);
	if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
		dev = manager_find_device(req->object, &src, &dst,
							interface, FALSE);

	if (!dev) {
		if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
			interface = AUDIO_GATEWAY_INTERFACE;
		else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
			interface = AUDIO_SOURCE_INTERFACE;
		else
			interface = NULL;
		dev = manager_find_device(req->object, &src, &dst,
							interface, TRUE);
		if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
			dev = manager_find_device(req->object, &src, &dst,
							interface, FALSE);
	}

	if (!dev) {
		error("Unable to find a matching device");
		goto failed;
	}

	client->type = select_service(dev, interface);
	if (client->type == TYPE_NONE) {
		error("No matching service found");
		goto failed;
	}

	if (g_strcmp0(interface, client->interface) != 0) {
		g_free(client->interface);
		client->interface = g_strdup(interface);
	}

	client->seid = req->seid;

	start_discovery(dev, client);

	return;

failed:
	unix_ipc_error(client, BT_GET_CAPABILITIES, err);
}
Beispiel #18
0
static void start_suspend(struct audio_device *dev, struct unix_client *client)
{
	struct a2dp_data *a2dp;
	struct headset_data *hs;
	unsigned int id;
	gboolean unref_avdtp_on_fail = FALSE;

	switch (client->type) {
	case TYPE_SINK:
	case TYPE_SOURCE:
		a2dp = &client->d.a2dp;

		if (!a2dp->session) {
			a2dp->session = avdtp_get(&dev->src, &dev->dst);
			unref_avdtp_on_fail = TRUE;
		}

		if (!a2dp->session) {
			error("Unable to get a session");
			goto failed;
		}

		if (!a2dp->sep) {
			error("Unable to get a sep");
			goto failed;
		}

		id = a2dp_suspend(a2dp->session, a2dp->sep,
					a2dp_suspend_complete, client);
		client->cancel = a2dp_cancel;
		break;

	case TYPE_HEADSET:
		hs = &client->d.hs;

		if (!hs->locked) {
			error("seid not opened");
			goto failed;
		}

		id = headset_suspend_stream(dev, headset_suspend_complete,
						client);
		client->cancel = headset_cancel_stream;
		break;

	case TYPE_GATEWAY:
		gateway_suspend_stream(dev);
		client->cancel = gateway_cancel_stream;
		headset_suspend_complete(dev, client);
		id = 1;
		break;

	default:
		error("No known services for device");
		goto failed;
	}

	if (id == 0) {
		error("suspend failed");
		goto failed;
	}

	return;

failed:
	if (unref_avdtp_on_fail && a2dp->session) {
		avdtp_unref(a2dp->session);
		a2dp->session = NULL;
	}
	unix_ipc_error(client, BT_STOP_STREAM, EIO);
}
Beispiel #19
0
static void start_config(struct audio_device *dev, struct unix_client *client)
{
	struct a2dp_data *a2dp;
	struct headset_data *hs;
	unsigned int id;

	switch (client->type) {
	case TYPE_SINK:
	case TYPE_SOURCE:
		a2dp = &client->d.a2dp;

		if (!a2dp->session)
			a2dp->session = avdtp_get(&dev->src, &dev->dst);

		if (!a2dp->session) {
			error("Unable to get a session");
			goto failed;
		}

		if (!a2dp->sep) {
			error("seid %d not opened", client->seid);
			goto failed;
		}

		id = a2dp_config(a2dp->session, a2dp->sep, a2dp_config_complete,
					client->caps, client);
		client->cancel = a2dp_cancel;
		break;

	case TYPE_HEADSET:
		hs = &client->d.hs;

		if (!hs->locked) {
			error("seid %d not opened", client->seid);
			goto failed;
		}

		id = headset_config_stream(dev, TRUE, headset_setup_complete,
						client);
		client->cancel = headset_cancel_stream;
		break;
	case TYPE_GATEWAY:
		if (gateway_config_stream(dev, gateway_setup_complete, client) >= 0) {
			client->cancel = gateway_cancel_stream;
			id = 1;
		} else
			id = 0;
		break;

	default:
		error("No known services for device");
		goto failed;
	}

	if (id == 0) {
		error("config failed");
		goto failed;
	}

	client->req_id = id;

	return;

failed:
	unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
static void start_config(struct audio_device *dev, struct unix_client *client)
{
	struct a2dp_data *a2dp;
	struct headset_data *hs;
	struct avdtp_remote_sep *rsep;
	struct avdtp_service_capability *media_scms_t;
	struct avdtp_content_protection_capability scms_t_cap = {0x02, 0x00};
	unsigned int id;

	switch (client->type) {
	case TYPE_SINK:
	case TYPE_SOURCE:
		a2dp = &client->d.a2dp;

		if (!a2dp->session)
			a2dp->session = avdtp_get(&dev->src, &dev->dst);

		if (!a2dp->session) {
			error("Unable to get a session");
			goto failed;
		}

		if (!a2dp->sep) {
			error("seid %d not opened", client->seid);
			goto failed;
		}

		rsep = avdtp_get_remote_sep(a2dp->session, client->seid);
		media_scms_t = avdtp_get_remote_sep_protection(rsep);

		if (media_scms_t &&
			(memcmp(media_scms_t->data, &scms_t_cap, sizeof(scms_t_cap)) == 0)) {
			media_scms_t = avdtp_service_cap_new(AVDTP_CONTENT_PROTECTION,
						&scms_t_cap, 2);
			client->caps = g_slist_append(client->caps, media_scms_t);
		}
		id = a2dp_config(a2dp->session, a2dp->sep, a2dp_config_complete,
					client->caps, client);
		client->cancel = a2dp_cancel;
		break;

	case TYPE_HEADSET:
		hs = &client->d.hs;

		if (!hs->locked) {
			error("seid %d not opened", client->seid);
			goto failed;
		}

		id = headset_config_stream(dev, TRUE, headset_setup_complete,
						client);
		client->cancel = headset_cancel_stream;
		break;
	case TYPE_GATEWAY:
		if (gateway_config_stream(dev, gateway_setup_complete, client) >= 0) {
			client->cancel = gateway_cancel_stream;
			id = 1;
		} else
			id = 0;
		break;

	default:
		error("No known services for device");
		goto failed;
	}

	if (id == 0) {
		error("config failed");
		goto failed;
	}

	client->req_id = id;
	g_slist_free(client->caps);
	client->caps = NULL;

	return;

failed:
	if (client->caps) {
		g_slist_free(client->caps);
		client->caps = NULL;
	}
	unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}