diff options
| -rw-r--r-- | audio/a2dp.c | 118 | ||||
| -rw-r--r-- | audio/a2dp.h | 4 | ||||
| -rw-r--r-- | audio/avdtp.c | 133 | ||||
| -rw-r--r-- | audio/avdtp.h | 7 | ||||
| -rw-r--r-- | audio/control.c | 87 | ||||
| -rw-r--r-- | audio/control.h | 4 | ||||
| -rw-r--r-- | audio/manager.c | 34 | ||||
| -rw-r--r-- | src/sdpd-database.c | 2 | ||||
| -rw-r--r-- | src/sdpd-service.c | 2 | ||||
| -rw-r--r-- | src/sdpd.h | 4 | 
10 files changed, 274 insertions, 121 deletions
| diff --git a/audio/a2dp.c b/audio/a2dp.c index 5e8cfd85..de15a42a 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -92,12 +92,15 @@ struct a2dp_setup {  static DBusConnection *connection = NULL; -static GSList *sinks = NULL; -static GSList *sources = NULL; - -static uint32_t source_record_id = 0; -static uint32_t sink_record_id = 0; +struct a2dp_server { +	bdaddr_t src; +	GSList *sinks; +	GSList *sources; +	uint32_t source_record_id; +	uint32_t sink_record_id; +}; +static GSList *servers = NULL;  static GSList *setups = NULL;  static unsigned int cb_id = 0; @@ -981,7 +984,7 @@ static sdp_record_t *a2dp_sink_record()  	return NULL;  } -static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type, +static struct a2dp_sep *a2dp_add_sep(struct a2dp_server *server, uint8_t type,  					uint8_t codec)  {  	struct a2dp_sep *sep; @@ -994,8 +997,9 @@ static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,  	sep = g_new0(struct a2dp_sep, 1);  	ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind; -	sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO, codec, -					ind, &cfm, sep); +	sep->sep = avdtp_register_sep(&server->src, type, +					AVDTP_MEDIA_TYPE_AUDIO, codec, ind, +					&cfm, sep);  	if (sep->sep == NULL) {  		g_free(sep);  		return NULL; @@ -1005,13 +1009,13 @@ static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,  	sep->type = type;  	if (type == AVDTP_SEP_TYPE_SOURCE) { -		l = &sources; +		l = &server->sources;  		create_record = a2dp_source_record; -		record_id = &source_record_id; +		record_id = &server->source_record_id;  	} else { -		l = &sinks; +		l = &server->sinks;  		create_record = a2dp_sink_record; -		record_id = &sink_record_id; +		record_id = &server->sink_record_id;  	}  	if (*record_id != 0) @@ -1025,7 +1029,7 @@ static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,  		return NULL;  	} -	if (add_record_to_server(BDADDR_ANY, record) < 0) { +	if (add_record_to_server(&server->src, record) < 0) {  		error("Unable to register A2DP service record");\  		sdp_record_free(record);  		avdtp_unregister_sep(sep->sep); @@ -1040,7 +1044,21 @@ add:  	return sep;  } -int a2dp_init(DBusConnection *conn, GKeyFile *config) +static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src) +{ +	GSList *l; + +	for (l = list; l; l = l->next) { +		struct a2dp_server *server = l->data; + +		if (bacmp(&server->src, src) == 0) +			return server; +	} + +	return NULL; +} + +int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)  {  	int sbc_srcs = 1, sbc_sinks = 0;  	int mpeg12_srcs = 0, mpeg12_sinks = 0; @@ -1048,6 +1066,7 @@ int a2dp_init(DBusConnection *conn, GKeyFile *config)  	char *str;  	GError *err = NULL;  	int i; +	struct a2dp_server *server;  	if (!config)  		goto proceed; @@ -1107,27 +1126,36 @@ int a2dp_init(DBusConnection *conn, GKeyFile *config)  	}  proceed: -	connection = dbus_connection_ref(conn); - -	avdtp_init(config); +	if (!connection) +		connection = dbus_connection_ref(conn); + +	server = find_server(servers, src); +	if (!server) { +		server = g_new0(struct a2dp_server, 1); +		if (!server) +			return -ENOMEM; +		avdtp_init(src, config); +		bacpy(&server->src, src); +		servers = g_slist_append(servers, server); +	}  	if (source) {  		for (i = 0; i < sbc_srcs; i++) -			a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE, +			a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,  					A2DP_CODEC_SBC);  		for (i = 0; i < mpeg12_srcs; i++) -			a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE, +			a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,  					A2DP_CODEC_MPEG12);  	}  	if (sink) {  		for (i = 0; i < sbc_sinks; i++) -			a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK, +			a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,  					A2DP_CODEC_SBC);  		for (i = 0; i < mpeg12_sinks; i++) -			a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK, +			a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,  					A2DP_CODEC_MPEG12);  	} @@ -1140,27 +1168,34 @@ static void a2dp_unregister_sep(struct a2dp_sep *sep)  	g_free(sep);  } -void a2dp_exit() +void a2dp_unregister(const bdaddr_t *src)  { -	g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL); -	g_slist_free(sinks); -	sinks = NULL; +	struct a2dp_server *server; -	g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL); -	g_slist_free(sources); -	sources = NULL; +	server = find_server(servers, src); +	if (!server) +		return; -	if (source_record_id) { -		remove_record_from_server(source_record_id); -		source_record_id = 0; -	} +	g_slist_foreach(server->sinks, (GFunc) a2dp_unregister_sep, NULL); +	g_slist_free(server->sinks); -	if (sink_record_id) { -		remove_record_from_server(sink_record_id); -		sink_record_id = 0; -	} +	g_slist_foreach(server->sources, (GFunc) a2dp_unregister_sep, NULL); +	g_slist_free(server->sources); + +	if (server->source_record_id) +		remove_record_from_server(server->source_record_id); + +	if (server->sink_record_id) +		remove_record_from_server(server->sink_record_id); + +	servers = g_slist_remove(servers, server); +	g_free(server); + +	if (servers) +		return;  	dbus_connection_unref(connection); +	connection = NULL;  }  gboolean a2dp_source_cancel(struct audio_device *dev, unsigned int id) @@ -1201,6 +1236,7 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,  {  	struct a2dp_setup_cb *cb_data;  	GSList *l; +	struct a2dp_server *server;  	struct a2dp_setup *setup;  	struct a2dp_sep *sep = NULL, *tmp;  	struct avdtp_local_sep *lsep; @@ -1208,6 +1244,12 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,  	struct avdtp_service_capability *cap;  	struct avdtp_media_codec_capability *codec_cap = NULL;  	int posix_err; +	bdaddr_t src; + +	avdtp_get_peers(session, &src, NULL); +	server = find_server(servers, &src); +	if (!server) +		return 0;  	for (l = caps; l != NULL; l = l->next) {  		cap = l->data; @@ -1222,7 +1264,7 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,  	if (!codec_cap)  		return 0; -	for (l = sources; l != NULL; l = l->next) { +	for (l = server->sources; l != NULL; l = l->next) {  		tmp = l->data;  		if (tmp->locked) @@ -1264,7 +1306,7 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,  	switch (avdtp_sep_get_state(sep->sep)) {  	case AVDTP_STATE_IDLE: -		for (l = sources; l != NULL; l = l->next) { +		for (l = server->sources; l != NULL; l = l->next) {  			tmp = l->data;  			if (avdtp_has_stream(session, tmp->stream)) diff --git a/audio/a2dp.h b/audio/a2dp.h index 6ec3ebc8..daa8f344 100644 --- a/audio/a2dp.h +++ b/audio/a2dp.h @@ -129,8 +129,8 @@ typedef void (*a2dp_stream_cb_t) (struct avdtp *session,  					struct avdtp_error *err,  					void *user_data); -int a2dp_init(DBusConnection *conn, GKeyFile *config); -void a2dp_exit(void); +int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config); +void a2dp_unregister(const bdaddr_t *src);  unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,  				GSList *caps, void *user_data); diff --git a/audio/avdtp.c b/audio/avdtp.c index c3286bfc..b052b927 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -291,6 +291,12 @@ struct avdtp_remote_sep {  	struct avdtp_stream *stream;  }; +struct avdtp_server { +	bdaddr_t src; +	GIOChannel *io; +	GSList *seps; +}; +  struct avdtp_local_sep {  	avdtp_state_t state;  	struct avdtp_stream *stream; @@ -300,6 +306,7 @@ struct avdtp_local_sep {  	struct avdtp_sep_ind *ind;  	struct avdtp_sep_cfm *cfm;  	void *user_data; +	struct avdtp_server *server;  };  struct stream_callback { @@ -327,11 +334,12 @@ struct avdtp_stream {  };  /* Structure describing an AVDTP connection between two devices */ +  struct avdtp {  	int ref;  	int free_lock; -	bdaddr_t src; +	struct avdtp_server *server;  	bdaddr_t dst;  	avdtp_session_state_t last_state; @@ -362,11 +370,7 @@ struct avdtp {  	DBusPendingCall *pending_auth;  }; -static uint8_t free_seid = 1; -static GSList *local_seps = NULL; - -static GIOChannel *avdtp_server = NULL; - +static GSList *servers = NULL;  static GSList *sessions = NULL;  static int send_request(struct avdtp *session, gboolean priority, @@ -383,6 +387,20 @@ static void avdtp_sep_set_state(struct avdtp *session,  				struct avdtp_local_sep *sep,  				avdtp_state_t state); +static struct avdtp_server *find_server(GSList *list, const bdaddr_t *src) +{ +	GSList *l; + +	for (l = list; l; l = l->next) { +		struct avdtp_server *server = l->data; + +		if (bacmp(&server->src, src) == 0) +			return server; +	} + +	return NULL; +} +  static const char *avdtp_statestr(avdtp_state_t state)  {  	switch (state) { @@ -834,11 +852,12 @@ struct avdtp *avdtp_ref(struct avdtp *session)  	return session;  } -static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid) +static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp_server *server, +							uint8_t seid)  {  	GSList *l; -	for (l = local_seps; l != NULL; l = g_slist_next(l)) { +	for (l = server->seps; l != NULL; l = g_slist_next(l)) {  		struct avdtp_local_sep *sep = l->data;  		if (sep->info.seid == seid) @@ -848,12 +867,14 @@ static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)  	return NULL;  } -static struct avdtp_local_sep *find_local_sep(uint8_t type, uint8_t media_type, +static struct avdtp_local_sep *find_local_sep(struct avdtp_server *server, +						uint8_t type, +						uint8_t media_type,  						uint8_t codec)  {  	GSList *l; -	for (l = local_seps; l != NULL; l = g_slist_next(l)) { +	for (l = server->seps; l != NULL; l = g_slist_next(l)) {  		struct avdtp_local_sep *sep = l->data;  		if (sep->info.inuse) @@ -941,7 +962,7 @@ static gboolean avdtp_discover_cmd(struct avdtp *session,  	rsp_size = sizeof(struct discover_resp);  	info = rsp->seps; -	for (l = local_seps; l != NULL; l = l->next) { +	for (l = session->server->seps; l != NULL; l = l->next) {  		struct avdtp_local_sep *sep = l->data;  		if (rsp_size + sizeof(struct seid_info) > session->mtu) @@ -971,7 +992,7 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session,  		return FALSE;  	} -	sep = find_local_sep_by_seid(req->acp_seid); +	sep = find_local_sep_by_seid(session->server, req->acp_seid);  	if (!sep) {  		err = AVDTP_BAD_ACP_SEID;  		goto failed; @@ -1022,7 +1043,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session,  		return FALSE;  	} -	sep = find_local_sep_by_seid(req->acp_seid); +	sep = find_local_sep_by_seid(session->server, req->acp_seid);  	if (!sep) {  		err = AVDTP_BAD_ACP_SEID;  		goto failed; @@ -1099,7 +1120,7 @@ static gboolean avdtp_open_cmd(struct avdtp *session, struct seid_req *req,  		return FALSE;  	} -	sep = find_local_sep_by_seid(req->acp_seid); +	sep = find_local_sep_by_seid(session->server, req->acp_seid);  	if (!sep) {  		err = AVDTP_BAD_ACP_SEID;  		goto failed; @@ -1160,7 +1181,8 @@ static gboolean avdtp_start_cmd(struct avdtp *session, struct start_req *req,  	for (i = 0; i < seid_count; i++, seid++) {  		failed_seid = seid->seid; -		sep = find_local_sep_by_seid(req->first_seid.seid); +		sep = find_local_sep_by_seid(session->server, +					req->first_seid.seid);  		if (!sep || !sep->stream) {  			err = AVDTP_BAD_ACP_SEID;  			goto failed; @@ -1208,7 +1230,7 @@ static gboolean avdtp_close_cmd(struct avdtp *session, struct seid_req *req,  		return FALSE;  	} -	sep = find_local_sep_by_seid(req->acp_seid); +	sep = find_local_sep_by_seid(session->server, req->acp_seid);  	if (!sep || !sep->stream) {  		err = AVDTP_BAD_ACP_SEID;  		goto failed; @@ -1269,7 +1291,8 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session,  	for (i = 0; i < seid_count; i++, seid++) {  		failed_seid = seid->seid; -		sep = find_local_sep_by_seid(req->first_seid.seid); +		sep = find_local_sep_by_seid(session->server, +					req->first_seid.seid);  		if (!sep || !sep->stream) {  			err = AVDTP_BAD_ACP_SEID;  			goto failed; @@ -1317,7 +1340,7 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, struct seid_req *req,  		return FALSE;  	} -	sep = find_local_sep_by_seid(req->acp_seid); +	sep = find_local_sep_by_seid(session->server, req->acp_seid);  	if (!sep || !sep->stream) {  		err = AVDTP_BAD_ACP_SEID;  		goto failed; @@ -1584,8 +1607,8 @@ static int l2cap_connect(struct avdtp *session)  {  	int err; -	err = bt_l2cap_connect(&session->src, &session->dst, AVDTP_PSM, 0, -				l2cap_connect_cb, session); +	err = bt_l2cap_connect(&session->server->src, &session->dst, AVDTP_PSM, +				0, l2cap_connect_cb, session);  	if (err < 0) {  		error("Connect failed. %s(%d)", strerror(-err), -err);  		return err; @@ -2130,7 +2153,7 @@ static struct avdtp *find_session(const bdaddr_t *src, const bdaddr_t *dst)  	for (l = sessions; l != NULL; l = g_slist_next(l)) {  		struct avdtp *s = l->data; -		if (bacmp(src, &s->src) || bacmp(dst, &s->dst)) +		if (bacmp(src, &s->server->src) || bacmp(dst, &s->dst))  			continue;  		return s; @@ -2157,7 +2180,7 @@ static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst  	session = g_new0(struct avdtp, 1);  	session->sock = -1; -	bacpy(&session->src, src); +	session->server = find_server(servers, src);  	bacpy(&session->dst, dst);  	session->ref = 1;  	session->state = AVDTP_SESSION_STATE_DISCONNECTED; @@ -2330,7 +2353,7 @@ int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type,  	int_type = acp_type == AVDTP_SEP_TYPE_SINK ?  				AVDTP_SEP_TYPE_SOURCE : AVDTP_SEP_TYPE_SINK; -	*lsep = find_local_sep(int_type, media_type, codec); +	*lsep = find_local_sep(session->server, int_type, media_type, codec);  	if (!*lsep)  		return -EINVAL; @@ -2630,44 +2653,54 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)  	return 0;  } -struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type, +struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type, +						uint8_t media_type,  						uint8_t codec_type,  						struct avdtp_sep_ind *ind,  						struct avdtp_sep_cfm *cfm,  						void *user_data)  { +	struct avdtp_server *server;  	struct avdtp_local_sep *sep; -	if (free_seid > MAX_SEID) +	server = find_server(servers, src); +	if (!server) +		return NULL; + +	if (g_slist_length(server->seps) > MAX_SEID)  		return NULL;  	sep = g_new0(struct avdtp_local_sep, 1);  	sep->state = AVDTP_STATE_IDLE; -	sep->info.seid = free_seid++; +	sep->info.seid = g_slist_length(server->seps) + 1;  	sep->info.type = type;  	sep->info.media_type = media_type;  	sep->codec = codec_type;  	sep->ind = ind;  	sep->cfm = cfm;  	sep->user_data = user_data; +	sep->server = server;  	debug("SEP %p registered: type:%d codec:%d seid:%d", sep,  			sep->info.type, sep->codec, sep->info.seid); -	local_seps = g_slist_append(local_seps, sep); +	server->seps = g_slist_append(server->seps, sep);  	return sep;  }  int avdtp_unregister_sep(struct avdtp_local_sep *sep)  { +	struct avdtp_server *server; +  	if (!sep)  		return -EINVAL;  	if (sep->info.inuse)  		return -EBUSY; -	local_seps = g_slist_remove(local_seps, sep); +	server = sep->server; +	server->seps = g_slist_remove(server->seps, sep);  	g_free(sep); @@ -2684,7 +2717,8 @@ static void auth_cb(DBusError *derr, void *user_data)  		error("Access denied: %s", derr->message);  		if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {  			debug("Canceling authorization request"); -			btd_cancel_authorization(&session->src, &session->dst); +			btd_cancel_authorization(&session->server->src, +						&session->dst);  		}  		connection_lost(session, -EACCES); @@ -2771,14 +2805,14 @@ drop:  	g_io_channel_unref(chan);  } -static GIOChannel *avdtp_server_socket(gboolean master) +static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)  {  	int lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;  	if (master)  		lm |= L2CAP_LM_MASTER; -	return bt_l2cap_listen(BDADDR_ANY, AVDTP_PSM, 0, lm, avdtp_server_cb, +	return bt_l2cap_listen(src, AVDTP_PSM, 0, lm, avdtp_server_cb,  			NULL);  } @@ -2835,18 +2869,16 @@ avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)  void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst)  {  	if (src) -		bacpy(src, &session->src); +		bacpy(src, &session->server->src);  	if (dst)  		bacpy(dst, &session->dst);  } -int avdtp_init(GKeyFile *config) +int avdtp_init(const bdaddr_t *src, GKeyFile *config)  {  	GError *err = NULL;  	gboolean tmp, master = TRUE; - -	if (avdtp_server) -		return 0; +	struct avdtp_server *server;  	if (config) {  		tmp = g_key_file_get_boolean(config, "General", @@ -2858,21 +2890,36 @@ int avdtp_init(GKeyFile *config)  			master = tmp;  	} -	avdtp_server = avdtp_server_socket(master); -	if (!avdtp_server) +	server = g_new0(struct avdtp_server, 1); +	if (!server) +		return -ENOMEM; + +	server->io = avdtp_server_socket(src, master); +	if (!server->io) { +		g_free(server);  		return -1; +	} + +	bacpy(&server->src, src); + +	servers = g_slist_append(servers, server);  	return 0;  } -void avdtp_exit(void) +void avdtp_exit(const bdaddr_t *src)  { -	if (!avdtp_server) +	struct avdtp_server *server; + +	server = find_server(servers, src); +	if (!server)  		return; -	g_io_channel_close(avdtp_server); -	g_io_channel_unref(avdtp_server); -	avdtp_server = NULL; +	servers = g_slist_remove(servers, server); + +	g_io_channel_close(server->io); +	g_io_channel_unref(server->io); +	g_free(server);  }  gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream) diff --git a/audio/avdtp.h b/audio/avdtp.h index de7e6e3d..0b06bd00 100644 --- a/audio/avdtp.h +++ b/audio/avdtp.h @@ -241,7 +241,8 @@ int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);  int avdtp_close(struct avdtp *session, struct avdtp_stream *stream);  int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream); -struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type, +struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type, +						uint8_t media_type,  						uint8_t codec_type,  						struct avdtp_sep_ind *ind,  						struct avdtp_sep_cfm *cfm, @@ -264,5 +265,5 @@ int avdtp_error_posix_errno(struct avdtp_error *err);  void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst); -int avdtp_init(GKeyFile *config); -void avdtp_exit(void); +int avdtp_init(const bdaddr_t *src, GKeyFile *config); +void avdtp_exit(const bdaddr_t *src); diff --git a/audio/control.c b/audio/control.c index a1014d48..15e38c99 100644 --- a/audio/control.c +++ b/audio/control.c @@ -97,11 +97,7 @@  static DBusConnection *connection = NULL; -static uint32_t tg_record_id = 0; -static uint32_t ct_record_id = 0; - -static GIOChannel *avctp_server = NULL; - +static GSList *servers = NULL;  static GSList *sessions = NULL;  typedef enum { @@ -150,6 +146,13 @@ struct avrcp_header {  #error "Unknown byte order"  #endif +struct avctp_server { +	bdaddr_t src; +	GIOChannel *io; +	uint32_t tg_record_id; +	uint32_t ct_record_id; +}; +  struct avctp {  	struct audio_device *dev; @@ -703,7 +706,7 @@ drop:  	close(session->sock);  } -static GIOChannel *avctp_server_socket(gboolean master) +static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)  {  	GIOChannel *io;  	int lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; @@ -711,7 +714,7 @@ static GIOChannel *avctp_server_socket(gboolean master)  	if (master)  		lm |= L2CAP_LM_MASTER; -	io = bt_l2cap_listen(BDADDR_ANY, AVCTP_PSM, 0, lm, avctp_server_cb, +	io = bt_l2cap_listen(src, AVCTP_PSM, 0, lm, avctp_server_cb,  				NULL);  	if (!io) {  		error("Unable to allocate new io channel"); @@ -810,14 +813,12 @@ void avrcp_disconnect(struct audio_device *dev)  	control->session = NULL;  } -int avrcp_init(DBusConnection *conn, GKeyFile *config) +int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)  {  	sdp_record_t *record;  	gboolean tmp, master = TRUE;  	GError *err = NULL; - -	if (avctp_server) -		return 0; +	struct avctp_server *server;  	if (config) {  		tmp = g_key_file_get_boolean(config, "General", @@ -829,7 +830,12 @@ int avrcp_init(DBusConnection *conn, GKeyFile *config)  			master = tmp;  	} -	connection = dbus_connection_ref(conn); +	server = g_new0(struct avctp_server, 1); +	if (!server) +		return -ENOMEM; + +	if (!connection) +		connection = dbus_connection_ref(conn);  	record = avrcp_tg_record();  	if (!record) { @@ -837,12 +843,12 @@ int avrcp_init(DBusConnection *conn, GKeyFile *config)  		return -1;  	} -	if (add_record_to_server(BDADDR_ANY, record) < 0) { +	if (add_record_to_server(src, record) < 0) {  		error("Unable to register AVRCP target service record");  		sdp_record_free(record);  		return -1;  	} -	tg_record_id = record->handle; +	server->tg_record_id = record->handle;  	record = avrcp_ct_record();  	if (!record) { @@ -850,34 +856,61 @@ int avrcp_init(DBusConnection *conn, GKeyFile *config)  		return -1;  	} -	if (add_record_to_server(BDADDR_ANY, record) < 0) { +	if (add_record_to_server(src, record) < 0) {  		error("Unable to register AVRCP controller service record");  		sdp_record_free(record);  		return -1;  	} -	ct_record_id = record->handle; +	server->ct_record_id = record->handle; -	avctp_server = avctp_server_socket(master); -	if (!avctp_server) +	server->io = avctp_server_socket(src, master); +	if (!server->io) { +		remove_record_from_server(server->ct_record_id); +		remove_record_from_server(server->tg_record_id); +		g_free(server);  		return -1; +	} + +	bacpy(&server->src, src); + +	servers = g_slist_append(servers, server);  	return 0;  } -void avrcp_exit(void) +static struct avctp_server *find_server(GSList *list, const bdaddr_t *src)  { -	if (!avctp_server) +	GSList *l; + +	for (l = list; l; l = l->next) { +		struct avctp_server *server = l->data; + +		if (bacmp(&server->src, src) == 0) +			return server; +	} + +	return NULL; +} + +void avrcp_unregister(const bdaddr_t *src) +{ +	struct avctp_server *server; + +	server = find_server(servers, src); +	if (!server)  		return; -	g_io_channel_close(avctp_server); -	g_io_channel_unref(avctp_server); -	avctp_server = NULL; +	servers = g_slist_remove(servers, server); -	remove_record_from_server(ct_record_id); -	ct_record_id = 0; +	remove_record_from_server(server->ct_record_id); +	remove_record_from_server(server->tg_record_id); -	remove_record_from_server(tg_record_id); -	tg_record_id = 0; +	g_io_channel_close(server->io); +	g_io_channel_unref(server->io); +	g_free(server); + +	if (servers) +		return;  	dbus_connection_unref(connection);  	connection = NULL; diff --git a/audio/control.h b/audio/control.h index 6475df51..163caa56 100644 --- a/audio/control.h +++ b/audio/control.h @@ -24,8 +24,8 @@  #define AUDIO_CONTROL_INTERFACE "org.bluez.Control" -int avrcp_init(DBusConnection *conn, GKeyFile *config); -void avrcp_exit(void); +int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config); +void avrcp_unregister(const bdaddr_t *src);  gboolean avrcp_connect(struct audio_device *dev);  void avrcp_disconnect(struct audio_device *dev); diff --git a/audio/manager.c b/audio/manager.c index 3aa1a5dd..deeb375c 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -831,7 +831,21 @@ static int a2dp_server_probe(struct btd_adapter *adapter)  	if (!adp)  		return -EINVAL; -	return a2dp_init(connection, config); +	return a2dp_register(connection, &adp->src, config); +} + +static void a2dp_server_remove(struct btd_adapter *adapter) +{ +	struct audio_adapter *adp; +	const gchar *path = adapter_get_path(adapter); + +	DBG("path %s", path); + +	adp = find_adapter(adapters, path); +	if (!adp) +		return; + +	return a2dp_unregister(&adp->src);  }  static int avrcp_server_probe(struct btd_adapter *adapter) @@ -845,7 +859,21 @@ static int avrcp_server_probe(struct btd_adapter *adapter)  	if (!adp)  		return -EINVAL; -	return avrcp_init(connection, config); +	return avrcp_register(connection, &adp->src, config); +} + +static void avrcp_server_remove(struct btd_adapter *adapter) +{ +	struct audio_adapter *adp; +	const gchar *path = adapter_get_path(adapter); + +	DBG("path %s", path); + +	adp = find_adapter(adapters, path); +	if (!adp) +		return; + +	return avrcp_unregister(&adp->src);  }  static struct btd_device_driver audio_driver = { @@ -872,11 +900,13 @@ static struct btd_adapter_driver gateway_server_driver = {  static struct btd_adapter_driver a2dp_server_driver = {  	.name	= "audio-a2dp",  	.probe	= a2dp_server_probe, +	.remove	= a2dp_server_remove,  };  static struct btd_adapter_driver avrcp_server_driver = {  	.name	= "audio-control",  	.probe	= avrcp_server_probe, +	.remove	= avrcp_server_remove,  };  int audio_manager_init(DBusConnection *conn, GKeyFile *conf) diff --git a/src/sdpd-database.c b/src/sdpd-database.c index 6cc34bd3..3642ae18 100644 --- a/src/sdpd-database.c +++ b/src/sdpd-database.c @@ -166,7 +166,7 @@ void sdp_svcdb_set_collectable(sdp_record_t *record, int sock)  /*   * Add a service record to the repository   */ -void sdp_record_add(bdaddr_t *device, sdp_record_t *rec) +void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec)  {  	sdp_access_t *dev; diff --git a/src/sdpd-service.c b/src/sdpd-service.c index cf120b89..713e12ef 100644 --- a/src/sdpd-service.c +++ b/src/sdpd-service.c @@ -377,7 +377,7 @@ void register_device_id(const uint16_t vendor, const uint16_t product,  	update_svclass_list();  } -int add_record_to_server(bdaddr_t *src, sdp_record_t *rec) +int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)  {  	sdp_data_t *data; @@ -68,7 +68,7 @@ void sdp_svcdb_collect_all(int sock);  void sdp_svcdb_set_collectable(sdp_record_t *rec, int sock);  void sdp_svcdb_collect(sdp_record_t *rec);  sdp_record_t *sdp_record_find(uint32_t handle); -void sdp_record_add(bdaddr_t *device, sdp_record_t *rec); +void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec);  int sdp_record_remove(uint32_t handle);  sdp_list_t *sdp_get_record_list(void);  sdp_list_t *sdp_get_access_list(void); @@ -83,7 +83,7 @@ uint32_t sdp_get_time();  int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);  void stop_sdp_server(void); -int add_record_to_server(bdaddr_t *src, sdp_record_t *rec); +int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);  int remove_record_from_server(uint32_t handle);  typedef void (*service_classes_callback_t) (const bdaddr_t *bdaddr, uint8_t value); | 
