[PATCH BlueZ 1/4] audio/AVRCP: Rework role detection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>

This makes AVRCP agnostic to any roles so the same session can be used
both for controller and target role.
---
 profiles/audio/avrcp.c | 427 +++++++++++++++++++++++++------------------------
 1 file changed, 219 insertions(+), 208 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index cd0a736..ad7742d 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -209,19 +209,19 @@ struct avrcp_player {
 	GDestroyNotify destroy;
 };
 
-struct avrcp {
-	struct avrcp_server *server;
-	struct avctp *conn;
-	struct btd_device *dev;
+struct avrcp_data {
 	struct avrcp_player *player;
-	gboolean target;
 	uint16_t version;
 	int features;
 	GSList *players;
+};
 
-	void (*init_control) (struct avrcp *session);
-	void (*init_browsing) (struct avrcp *session);
-	void (*destroy) (struct avrcp *sesion);
+struct avrcp {
+	struct avrcp_server *server;
+	struct avctp *conn;
+	struct btd_device *dev;
+	struct avrcp_data *target;
+	struct avrcp_data *controller;
 
 	const struct passthrough_handler *passthrough_handlers;
 	const struct control_pdu_handler *control_handlers;
@@ -937,7 +937,7 @@ static uint8_t avrcp_handle_list_player_attributes(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	unsigned int i;
 
@@ -969,7 +969,7 @@ static uint8_t avrcp_handle_list_player_values(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	unsigned int i;
 
@@ -1038,7 +1038,7 @@ static uint8_t avrcp_handle_get_element_attributes(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	uint64_t identifier = bt_get_le64(&pdu->params[0]);
 	uint16_t pos;
@@ -1110,7 +1110,7 @@ static uint8_t avrcp_handle_get_current_player_value(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	uint8_t *settings;
 	unsigned int i;
@@ -1169,7 +1169,7 @@ static uint8_t avrcp_handle_set_player_value(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	unsigned int i;
 	uint8_t *param;
@@ -1288,7 +1288,7 @@ static uint8_t avrcp_handle_get_play_status(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	uint32_t position;
 	uint32_t duration;
@@ -1332,9 +1332,9 @@ static GList *player_list_settings(struct avrcp_player *player)
 
 static bool avrcp_handle_play(struct avrcp *session)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 
-	if (session->player == NULL)
+	if (player == NULL)
 		return false;
 
 	return player->cb->play(player->user_data);
@@ -1342,9 +1342,9 @@ static bool avrcp_handle_play(struct avrcp *session)
 
 static bool avrcp_handle_stop(struct avrcp *session)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 
-	if (session->player == NULL)
+	if (player == NULL)
 		return false;
 
 	return player->cb->stop(player->user_data);
@@ -1352,9 +1352,9 @@ static bool avrcp_handle_stop(struct avrcp *session)
 
 static bool avrcp_handle_pause(struct avrcp *session)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 
-	if (session->player == NULL)
+	if (player == NULL)
 		return false;
 
 	return player->cb->pause(player->user_data);
@@ -1362,9 +1362,9 @@ static bool avrcp_handle_pause(struct avrcp *session)
 
 static bool avrcp_handle_next(struct avrcp *session)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 
-	if (session->player == NULL)
+	if (player == NULL)
 		return false;
 
 	return player->cb->next(player->user_data);
@@ -1372,15 +1372,15 @@ static bool avrcp_handle_next(struct avrcp *session)
 
 static bool avrcp_handle_previous(struct avrcp *session)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 
-	if (session->player == NULL)
+	if (player == NULL)
 		return false;
 
 	return player->cb->previous(player->user_data);
 }
 
-static const struct passthrough_handler tg_passthrough_handlers[] = {
+static const struct passthrough_handler passthrough_handlers[] = {
 		{ AVC_PLAY, avrcp_handle_play },
 		{ AVC_STOP, avrcp_handle_stop },
 		{ AVC_PAUSE, avrcp_handle_pause },
@@ -1415,7 +1415,7 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	struct btd_device *dev = session->dev;
 	uint16_t len = ntohs(pdu->params_len);
 	uint64_t uid;
@@ -1441,7 +1441,7 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
 		break;
 	case AVRCP_EVENT_TRACK_CHANGED:
 		len = 9;
-		uid = player_get_uid(player);
+		uid = player_get_uid(session->target->player);
 		memcpy(&pdu->params[1], &uid, sizeof(uint64_t));
 
 		break;
@@ -1473,9 +1473,6 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
 
 		break;
 	case AVRCP_EVENT_VOLUME_CHANGED:
-		if (session->version < 0x0104)
-			goto err;
-
 		pdu->params[1] = media_transport_get_device_volume(dev);
 		if (pdu->params[1] > 127)
 			goto err;
@@ -1506,7 +1503,7 @@ static uint8_t avrcp_handle_request_continuing(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint16_t len = ntohs(pdu->params_len);
 	struct pending_pdu *pending;
 
@@ -1573,7 +1570,7 @@ static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
 						struct avrcp_header *pdu,
 						uint8_t transaction)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	uint16_t len = ntohs(pdu->params_len);
 	uint8_t volume;
 
@@ -1597,7 +1594,7 @@ err:
 	return AVC_CTYPE_REJECTED;
 }
 
-static const struct control_pdu_handler tg_control_handlers[] = {
+static const struct control_pdu_handler control_handlers[] = {
 		{ AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
 					avrcp_handle_get_capabilities },
 		{ AVRCP_LIST_PLAYER_ATTRIBUTES, AVC_CTYPE_STATUS,
@@ -1622,6 +1619,8 @@ static const struct control_pdu_handler tg_control_handlers[] = {
 					avrcp_handle_get_play_status },
 		{ AVRCP_REGISTER_NOTIFICATION, AVC_CTYPE_NOTIFY,
 					avrcp_handle_register_notification },
+		{ AVRCP_SET_ABSOLUTE_VOLUME, AVC_CTYPE_CONTROL,
+					avrcp_handle_set_absolute_volume },
 		{ AVRCP_REQUEST_CONTINUING, AVC_CTYPE_CONTROL,
 					avrcp_handle_request_continuing },
 		{ AVRCP_ABORT_CONTINUING, AVC_CTYPE_CONTROL,
@@ -1629,16 +1628,6 @@ static const struct control_pdu_handler tg_control_handlers[] = {
 		{ },
 };
 
-static const struct control_pdu_handler ct_control_handlers[] = {
-		{ AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
-					avrcp_handle_get_capabilities },
-		{ AVRCP_REGISTER_NOTIFICATION, AVC_CTYPE_NOTIFY,
-					avrcp_handle_register_notification },
-		{ AVRCP_SET_ABSOLUTE_VOLUME, AVC_CTYPE_CONTROL,
-					avrcp_handle_set_absolute_volume },
-		{ },
-};
-
 /* handle vendordep pdu inside an avctp packet */
 static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
 					uint8_t *code, uint8_t *subunit,
@@ -1796,7 +1785,7 @@ static gboolean avrcp_get_play_status_rsp(struct avctp *conn,
 					void *user_data)
 {
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	struct avrcp_header *pdu = (void *) operands;
 	uint32_t duration;
@@ -1860,7 +1849,7 @@ static gboolean avrcp_player_value_rsp(struct avctp *conn,
 					void *user_data)
 {
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	struct avrcp_header *pdu = (void *) operands;
 	uint8_t count;
@@ -2007,7 +1996,7 @@ static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn,
 						void *user_data)
 {
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct avrcp_header *pdu = (void *) operands;
 	uint8_t count;
 
@@ -2122,7 +2111,7 @@ static struct media_item *parse_media_element(struct avrcp *session,
 		name[namelen] = '\0';
 	}
 
-	player = session->player;
+	player = session->controller->player;
 	mp = player->user_data;
 
 	item = media_player_create_item(mp, name, PLAYER_ITEM_TYPE_AUDIO, uid);
@@ -2137,7 +2126,7 @@ static struct media_item *parse_media_element(struct avrcp *session,
 static struct media_item *parse_media_folder(struct avrcp *session,
 					uint8_t *operands, uint16_t len)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	uint16_t namelen;
 	char name[255];
@@ -2166,7 +2155,7 @@ static gboolean avrcp_list_items_rsp(struct avctp *conn, uint8_t *operands,
 {
 	struct avrcp_browsing_header *pdu = (void *) operands;
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct pending_list_items *p = player->p;
 	uint16_t count;
 	uint32_t items, total;
@@ -2250,7 +2239,7 @@ static void avrcp_list_items(struct avrcp *session, uint32_t start,
 {
 	uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 10 +
 			AVRCP_MEDIA_ATTRIBUTE_LAST * sizeof(uint32_t)];
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct avrcp_browsing_header *pdu = (void *) buf;
 	uint16_t length = AVRCP_BROWSING_HEADER_LENGTH + 10;
 	uint32_t attribute;
@@ -2284,7 +2273,7 @@ static gboolean avrcp_change_path_rsp(struct avctp *conn,
 {
 	struct avrcp_browsing_header *pdu = (void *) operands;
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	int ret;
 
@@ -2321,7 +2310,7 @@ static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
 						void *user_data)
 {
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	struct avrcp_browsing_header *pdu = (void *) operands;
 	uint32_t items;
@@ -2390,7 +2379,7 @@ static gboolean avrcp_get_item_attributes_rsp(struct avctp *conn,
 						void *user_data)
 {
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct avrcp_browsing_header *pdu = (void *) operands;
 	uint8_t count;
 
@@ -2420,6 +2409,7 @@ static gboolean avrcp_get_item_attributes_rsp(struct avctp *conn,
 
 static void avrcp_get_item_attributes(struct avrcp *session, uint64_t uid)
 {
+	struct avrcp_player *player = session->controller->player;
 	uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 12];
 	struct avrcp_browsing_header *pdu = (void *) buf;
 
@@ -2428,7 +2418,7 @@ static void avrcp_get_item_attributes(struct avrcp *session, uint64_t uid)
 	pdu->pdu_id = AVRCP_GET_ITEM_ATTRIBUTES;
 	pdu->params[0] = 0x03;
 	bt_put_be64(uid, &pdu->params[1]);
-	bt_put_be16(session->player->uid_counter, &pdu->params[9]);
+	bt_put_be16(player->uid_counter, &pdu->params[9]);
 	pdu->param_len = htons(12);
 
 	avctp_send_browsing_req(session->conn, buf, sizeof(buf),
@@ -2494,7 +2484,7 @@ static bool ct_set_setting(struct media_player *mp, const char *key,
 	if (session == NULL)
 		return false;
 
-	if (session->version < 0x0103)
+	if (session->controller->version < 0x0103)
 		return false;
 
 	attr = attr_to_val(key);
@@ -2607,7 +2597,7 @@ static int ct_list_items(struct media_player *mp, const char *name,
 static void avrcp_change_path(struct avrcp *session, uint8_t direction,
 								uint64_t uid)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 11];
 	struct avrcp_browsing_header *pdu = (void *) buf;
 
@@ -2644,7 +2634,7 @@ static gboolean avrcp_search_rsp(struct avctp *conn, uint8_t *operands,
 {
 	struct avrcp_browsing_header *pdu = (void *) operands;
 	struct avrcp *session = (void *) user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	int ret;
 
@@ -2704,7 +2694,7 @@ static int ct_search(struct media_player *mp, const char *string,
 static void avrcp_play_item(struct avrcp *session, uint64_t uid)
 {
 	uint8_t buf[AVRCP_HEADER_LENGTH + 11];
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct avrcp_header *pdu = (void *) buf;
 	uint16_t length;
 
@@ -2750,7 +2740,7 @@ static int ct_play_item(struct media_player *mp, const char *name,
 static void avrcp_add_to_nowplaying(struct avrcp *session, uint64_t uid)
 {
 	uint8_t buf[AVRCP_HEADER_LENGTH + 11];
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct avrcp_header *pdu = (void *) buf;
 	uint16_t length;
 
@@ -2829,10 +2819,12 @@ static struct avrcp_player *create_ct_player(struct avrcp *session,
 	player->user_data = mp;
 	player->destroy = (GDestroyNotify) media_player_destroy;
 
-	if (session->player == NULL)
-		session->player = player;
+	if (session->controller->player == NULL)
+		session->controller->player = player;
 
-	session->players = g_slist_prepend(session->players, player);
+	session->controller->players = g_slist_prepend(
+						session->controller->players,
+						player);
 
 	return player;
 }
@@ -2841,7 +2833,7 @@ static struct avrcp_player *find_ct_player(struct avrcp *session, uint16_t id)
 {
 	GSList *l;
 
-	for (l = session->players; l; l = l->next) {
+	for (l = session->controller->players; l; l = l->next) {
 		struct avrcp_player *player = l->data;
 
 		if (player->id == 0) {
@@ -2905,7 +2897,7 @@ avrcp_parse_media_player_item(struct avrcp *session, uint8_t *operands,
 		media_player_set_name(mp, name);
 	}
 
-	if (session->player == player && !player->browsed)
+	if (session->controller->player == player && !player->browsed)
 		avrcp_set_browsed_player(session, player);
 
 	return player;
@@ -2933,7 +2925,9 @@ static void player_remove(gpointer data)
 	for (l = player->sessions; l; l = l->next) {
 		struct avrcp *session = l->data;
 
-		session->players = g_slist_remove(session->players, player);
+		session->controller->players = g_slist_remove(
+						session->controller->players,
+						player);
 	}
 
 	player_destroy(player);
@@ -2954,7 +2948,7 @@ static gboolean avrcp_get_media_player_list_rsp(struct avctp *conn,
 							operand_count < 5)
 		return FALSE;
 
-	removed = g_slist_copy(session->players);
+	removed = g_slist_copy(session->controller->players);
 	count = bt_get_be16(&operands[6]);
 
 	for (i = 8; count && i < operand_count; count--) {
@@ -2984,8 +2978,8 @@ static gboolean avrcp_get_media_player_list_rsp(struct avctp *conn,
 		i += len;
 	}
 
-	if (g_slist_find(removed, session->player))
-		session->player = NULL;
+	if (g_slist_find(removed, session->controller->player))
+		session->controller->player = NULL;
 
 	g_slist_free_full(removed, player_remove);
 
@@ -3009,7 +3003,7 @@ static void avrcp_get_media_player_list(struct avrcp *session)
 static void avrcp_volume_changed(struct avrcp *session,
 						struct avrcp_header *pdu)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	uint8_t volume;
 
 	if (player == NULL)
@@ -3023,7 +3017,7 @@ static void avrcp_volume_changed(struct avrcp *session,
 static void avrcp_status_changed(struct avrcp *session,
 						struct avrcp_header *pdu)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	uint8_t value;
 	const char *curval, *strval;
@@ -3044,7 +3038,7 @@ static void avrcp_track_changed(struct avrcp *session,
 						struct avrcp_header *pdu)
 {
 	if (session->browsing_id) {
-		struct avrcp_player *player = session->player;
+		struct avrcp_player *player = session->controller->player;
 		player->uid = bt_get_be64(&pdu->params[1]);
 		avrcp_get_item_attributes(session, player->uid);
 	} else
@@ -3054,7 +3048,7 @@ static void avrcp_track_changed(struct avrcp *session,
 static void avrcp_setting_changed(struct avrcp *session,
 						struct avrcp_header *pdu)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	struct media_player *mp = player->user_data;
 	uint8_t count = pdu->params[1];
 	int i;
@@ -3084,7 +3078,7 @@ static void avrcp_available_players_changed(struct avrcp *session,
 static void avrcp_addressed_player_changed(struct avrcp *session,
 						struct avrcp_header *pdu)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 	uint16_t id = bt_get_be16(&pdu->params[1]);
 
 	if (player != NULL && player->id == id)
@@ -3098,7 +3092,7 @@ static void avrcp_addressed_player_changed(struct avrcp *session,
 	}
 
 	player->uid_counter = bt_get_be16(&pdu->params[3]);
-	session->player = player;
+	session->controller->player = player;
 
 	if (player->features != NULL)
 		return;
@@ -3108,7 +3102,7 @@ static void avrcp_addressed_player_changed(struct avrcp *session,
 
 static void avrcp_uids_changed(struct avrcp *session, struct avrcp_header *pdu)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->controller->player;
 
 	player->uid_counter = bt_get_be16(&pdu->params[1]);
 }
@@ -3269,7 +3263,7 @@ static void destroy_browsing(void *data)
 	session->browsing_id = 0;
 }
 
-static void session_tg_init_browsing(struct avrcp *session)
+static void session_init_browsing(struct avrcp *session)
 {
 	session->browsing_id = avctp_register_browsing_pdu_handler(
 							session->conn,
@@ -3278,154 +3272,212 @@ static void session_tg_init_browsing(struct avrcp *session)
 							destroy_browsing);
 }
 
-static void session_tg_init_control(struct avrcp *session)
+static struct avrcp_data *data_init(struct avrcp *session, const char *uuid)
+{
+	struct avrcp_data *data;
+	const sdp_record_t *rec;
+	sdp_list_t *list;
+	sdp_profile_desc_t *desc;
+
+	data = g_new0(struct avrcp_data, 1);
+
+	rec = btd_device_get_record(session->dev, uuid);
+	if (rec == NULL)
+		return data;
+
+	if (sdp_get_profile_descs(rec, &list) == 0) {
+		desc = list->data;
+		data->version = desc->version;
+	}
+
+	sdp_get_int_attr(rec, SDP_ATTR_SUPPORTED_FEATURES, &data->features);
+	sdp_list_free(list, free);
+
+	return data;
+}
+
+static void target_init(struct avrcp *session)
 {
 	struct avrcp_server *server = session->server;
+	struct avrcp_data *target;
 	struct avrcp_player *player;
 	struct btd_service *service;
+	btd_service_state_t old_state = BTD_SERVICE_STATE_UNAVAILABLE;
 
-	if (session->version < 0x0103)
+	if (session->target != NULL)
 		return;
 
-	DBG("%p version 0x%04x", session, session->version);
+	target = data_init(session, AVRCP_REMOTE_UUID);
+	session->target = target;
+
+	DBG("%p version 0x%04x", target, target->version);
+
+	service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
+	if (service != NULL) {
+		old_state = btd_service_get_state(service);
+		btd_service_connecting_complete(service, 0);
+	}
+
+	if (target->version < 0x0103)
+		return;
 
 	player = g_slist_nth_data(server->players, 0);
 	if (player != NULL) {
-		session->player = player;
+		target->player = player;
 		player->sessions = g_slist_prepend(player->sessions, session);
 	}
 
-	session->passthrough_id = avctp_register_passthrough_handler(
-							session->conn,
-							handle_passthrough,
-							session);
-	session->passthrough_handlers = tg_passthrough_handlers;
-	session->control_id = avctp_register_pdu_handler(session->conn,
-							AVC_OP_VENDORDEP,
-							handle_vendordep_pdu,
-							session);
-	session->control_handlers = tg_control_handlers;
-	session->supported_events = (1 << AVRCP_EVENT_STATUS_CHANGED) |
+	session->supported_events |= (1 << AVRCP_EVENT_STATUS_CHANGED) |
 				(1 << AVRCP_EVENT_TRACK_CHANGED) |
 				(1 << AVRCP_EVENT_TRACK_REACHED_START) |
 				(1 << AVRCP_EVENT_TRACK_REACHED_END) |
 				(1 << AVRCP_EVENT_SETTINGS_CHANGED);
 
-	if (session->version >= 0x0104)
-		avrcp_register_notification(session,
-						AVRCP_EVENT_VOLUME_CHANGED);
+	if (target->version < 0x0104)
+		return;
 
-	service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
-	if (service != NULL)
-		btd_service_connecting_complete(service, 0);
-}
+	avrcp_register_notification(session, AVRCP_EVENT_VOLUME_CHANGED);
 
-static void session_ct_init_browsing(struct avrcp *session)
-{
-	session->browsing_id = avctp_register_browsing_pdu_handler(
-							session->conn,
-							handle_browsing_pdu,
-							session,
-							destroy_browsing);
+	/* Auto-connect browsing channel only if initiator */
+	if (old_state == BTD_SERVICE_STATE_CONNECTING &&
+				target->features & AVRCP_FEATURE_BROWSING)
+		avctp_connect_browsing(session->conn);
 }
 
-static void session_ct_init_control(struct avrcp *session)
+static void controller_init(struct avrcp *session)
 {
 	struct avrcp_player *player;
 	struct btd_service *service;
+	struct avrcp_data *controller;
+	btd_service_state_t old_state = BTD_SERVICE_STATE_UNAVAILABLE;
 
-	DBG("%p version 0x%04x", session, session->version);
+	if (session->controller != NULL)
+		return;
 
-	session->control_id = avctp_register_pdu_handler(session->conn,
-							AVC_OP_VENDORDEP,
-							handle_vendordep_pdu,
-							session);
-	session->control_handlers = ct_control_handlers;
-	if (session->version >= 0x0104)
-		session->supported_events = (1 << AVRCP_EVENT_VOLUME_CHANGED);
+	controller = data_init(session, AVRCP_TARGET_UUID);
+	session->controller = controller;
+
+	DBG("%p version 0x%04x", controller, controller->version);
+
+	if (controller->version >= 0x0104)
+		session->supported_events |= (1 << AVRCP_EVENT_VOLUME_CHANGED);
 
 	service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
-	if (service != NULL)
+	if (service != NULL) {
+		old_state = btd_service_get_state(service);
 		btd_service_connecting_complete(service, 0);
+	}
+
+	/* Only create player if category 1 is supported */
+	if (!(controller->features & AVRCP_FEATURE_CATEGORY_1))
+		return;
 
 	player = create_ct_player(session, 0);
 	if (player == NULL)
 		return;
 
-	if (session->version < 0x0103)
+	if (controller->version < 0x0103)
 		return;
 
 	avrcp_get_capabilities(session);
+
+	if (controller->version < 0x0104)
+		return;
+
+	/* Auto-connect browsing channel only if initiator */
+	if (old_state == BTD_SERVICE_STATE_CONNECTING &&
+				controller->features & AVRCP_FEATURE_BROWSING)
+		avctp_connect_browsing(session->conn);
 }
 
-static void session_destroy(struct avrcp *session)
+static void session_init_control(struct avrcp *session)
 {
-	struct avrcp_server *server = session->server;
+	session->passthrough_id = avctp_register_passthrough_handler(
+							session->conn,
+							handle_passthrough,
+							session);
+	session->passthrough_handlers = passthrough_handlers;
+	session->control_id = avctp_register_pdu_handler(session->conn,
+							AVC_OP_VENDORDEP,
+							handle_vendordep_pdu,
+							session);
+	session->control_handlers = control_handlers;
 
-	server->sessions = g_slist_remove(server->sessions, session);
+	if (btd_device_get_service(session->dev, AVRCP_TARGET_UUID) != NULL)
+		controller_init(session);
 
-	if (session->passthrough_id > 0)
-		avctp_unregister_passthrough_handler(session->passthrough_id);
+	if (btd_device_get_service(session->dev, AVRCP_REMOTE_UUID) != NULL)
+		target_init(session);
+}
 
-	if (session->control_id > 0)
-		avctp_unregister_pdu_handler(session->control_id);
+static void controller_destroy(struct avrcp *session)
+{
+	struct avrcp_data *controller = session->controller;
+	struct btd_service *service;
 
-	if (session->browsing_id > 0)
-		avctp_unregister_browsing_pdu_handler(session->browsing_id);
+	DBG("%p", controller);
 
-	g_free(session);
+	g_slist_free_full(controller->players, player_destroy);
+
+	service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
+
+	if (session->control_id == 0)
+		btd_service_connecting_complete(service, -EIO);
+	else
+		btd_service_disconnecting_complete(service, 0);
+
+	g_free(controller);
 }
 
-static void session_tg_destroy(struct avrcp *session)
+static void target_destroy(struct avrcp *session)
 {
-	struct avrcp_player *player = session->player;
+	struct avrcp_data *target = session->target;
+	struct avrcp_player *player = target->player;
 	struct btd_service *service;
 
-	DBG("%p", session);
+	DBG("%p", target);
 
 	if (player != NULL)
 		player->sessions = g_slist_remove(player->sessions, session);
 
 	service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
-	if (service == NULL)
-		return session_destroy(session);
 
 	if (session->control_id == 0)
 		btd_service_connecting_complete(service, -EIO);
 	else
 		btd_service_disconnecting_complete(service, 0);
 
-	session_destroy(session);
+	g_free(target);
 }
 
-static void session_ct_destroy(struct avrcp *session)
+static void session_destroy(struct avrcp *session)
 {
-	struct btd_service *service;
+	struct avrcp_server *server = session->server;
 
-	DBG("%p", session);
+	server->sessions = g_slist_remove(server->sessions, session);
 
-	g_slist_free_full(session->players, player_destroy);
+	if (session->controller != NULL)
+		controller_destroy(session);
 
-	service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
-	if (service == NULL)
-		return session_destroy(session);
+	if (session->target != NULL)
+		target_destroy(session);
 
-	if (session->control_id == 0)
-		btd_service_connecting_complete(service, -EIO);
-	else
-		btd_service_disconnecting_complete(service, 0);
+	if (session->passthrough_id > 0)
+		avctp_unregister_passthrough_handler(session->passthrough_id);
 
-	session_destroy(session);
+	if (session->control_id > 0)
+		avctp_unregister_pdu_handler(session->control_id);
+
+	if (session->browsing_id > 0)
+		avctp_unregister_browsing_pdu_handler(session->browsing_id);
+
+	g_free(session);
 }
 
 static struct avrcp *session_create(struct avrcp_server *server,
 						struct btd_device *device)
 {
 	struct avrcp *session;
-	const sdp_record_t *rec;
-	sdp_list_t *list;
-	sdp_profile_desc_t *desc;
-	struct btd_service *sink, *source;
 
 	session = g_new0(struct avrcp, 1);
 	session->server = server;
@@ -3434,52 +3486,6 @@ static struct avrcp *session_create(struct avrcp_server *server,
 
 	server->sessions = g_slist_append(server->sessions, session);
 
-	sink = btd_device_get_service(device, A2DP_SINK_UUID);
-	source = btd_device_get_service(device, A2DP_SOURCE_UUID);
-
-	/* If sink and source are not supported assume the controller must
-	 * be the initiator
-	 */
-	if (sink == NULL && source == NULL)
-		session->target = !avctp_is_initiator(session->conn);
-	else if (sink && !source)
-		session->target = TRUE;
-	else if (source && !sink)
-		session->target = FALSE;
-	else if (sink && sink_is_active(sink))
-		session->target = TRUE;
-	else
-		session->target = FALSE;
-
-	if (session->target) {
-		session->init_control = session_tg_init_control;
-		session->init_browsing = session_tg_init_browsing;
-		session->destroy = session_tg_destroy;
-
-		rec = btd_device_get_record(device, AVRCP_REMOTE_UUID);
-		if (rec == NULL)
-			btd_device_add_uuid(device, AVRCP_REMOTE_UUID);
-	} else {
-		session->init_control = session_ct_init_control;
-		session->init_browsing = session_ct_init_browsing;
-		session->destroy = session_ct_destroy;
-		rec = btd_device_get_record(device, AVRCP_TARGET_UUID);
-		if (rec == NULL)
-			btd_device_add_uuid(device, AVRCP_TARGET_UUID);
-	}
-
-	if (rec == NULL)
-		return session;
-
-	if (sdp_get_profile_descs(rec, &list) < 0)
-		return session;
-
-	desc = list->data;
-	session->version = desc->version;
-	sdp_get_int_attr(rec, SDP_ATTR_SUPPORTED_FEATURES, &session->features);
-
-	sdp_list_free(list, free);
-
 	return session;
 }
 
@@ -3500,7 +3506,7 @@ static void state_changed(struct btd_device *device, avctp_state_t old_state,
 		if (session == NULL)
 			break;
 
-		session->destroy(session);
+		session_destroy(session);
 
 		break;
 	case AVCTP_STATE_CONNECTING:
@@ -3514,18 +3520,15 @@ static void state_changed(struct btd_device *device, avctp_state_t old_state,
 		if (session == NULL || session->control_id > 0)
 			break;
 
-		session->init_control(session);
-
-		if (session->version >= 0x0104 &&
-				session->features & AVRCP_FEATURE_BROWSING)
-			avctp_connect_browsing(session->conn);
+		session_init_control(session);
 
 		break;
 	case AVCTP_STATE_BROWSING_CONNECTED:
 		if (session == NULL || session->browsing_id > 0)
 			break;
 
-		session->init_browsing(session);
+		session_init_browsing(session);
+
 		break;
 	default:
 		return;
@@ -3727,9 +3730,13 @@ struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
 	/* Assign player to session without current player */
 	for (l = server->sessions; l; l = l->next) {
 		struct avrcp *session = l->data;
+		struct avrcp_data *target = session->target;
 
-		if (session->player == NULL) {
-			session->player = player;
+		if (target == NULL)
+			continue;
+
+		if (target->player == NULL) {
+			target->player = player;
 			player->sessions = g_slist_append(player->sessions,
 								session);
 		}
@@ -3748,9 +3755,13 @@ void avrcp_unregister_player(struct avrcp_player *player)
 	/* Remove player from sessions using it */
 	for (l = player->sessions; l; l = l->next) {
 		struct avrcp *session = l->data;
+		struct avrcp_data *target = session->target;
+
+		if (target == NULL)
+			continue;
 
-		if (session->player == player)
-			session->player = g_slist_nth_data(server->players, 0);
+		if (target->player == player)
+			target->player = g_slist_nth_data(server->players, 0);
 	}
 
 	player_destroy(player);
@@ -3762,7 +3773,7 @@ static gboolean avrcp_handle_set_volume(struct avctp *conn,
 					void *user_data)
 {
 	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
+	struct avrcp_player *player = session->target->player;
 	struct avrcp_header *pdu = (void *) operands;
 	uint8_t volume;
 
@@ -3790,10 +3801,10 @@ int avrcp_set_volume(struct btd_device *dev, uint8_t volume)
 		return -EINVAL;
 
 	session = find_session(server->sessions, dev);
-	if (session == NULL)
+	if (session == NULL || session->target == NULL)
 		return -ENOTCONN;
 
-	if (session->version < 0x0104)
+	if (session->target->version < 0x0104)
 		return -ENOTSUP;
 
 	memset(buf, 0, sizeof(buf));
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux