All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection
@ 2013-07-23 12:52 Luiz Augusto von Dentz
  2013-07-23 12:52 ` [PATCH BlueZ 2/4] audio/AVRCP: Fix registration of VOLUME_CHANGED Luiz Augusto von Dentz
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2013-07-23 12:52 UTC (permalink / raw)
  To: linux-bluetooth

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

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


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 2/4] audio/AVRCP: Fix registration of VOLUME_CHANGED
  2013-07-23 12:52 [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Luiz Augusto von Dentz
@ 2013-07-23 12:52 ` Luiz Augusto von Dentz
  2013-07-23 12:52 ` [PATCH BlueZ 3/4] audio/media: Fix not updating position Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2013-07-23 12:52 UTC (permalink / raw)
  To: linux-bluetooth

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

First check with GetCapabilities if the event is really support before
registering.
---
 profiles/audio/avrcp.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index ad7742d..9baf0d3 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -3205,6 +3205,7 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
 		case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
 		case AVRCP_EVENT_UIDS_CHANGED:
 		case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+		case AVRCP_EVENT_VOLUME_CHANGED:
 			avrcp_register_notification(session, event);
 			break;
 		}
@@ -3336,7 +3337,9 @@ static void target_init(struct avrcp *session)
 	if (target->version < 0x0104)
 		return;
 
-	avrcp_register_notification(session, AVRCP_EVENT_VOLUME_CHANGED);
+	/* Only check capabilities if controller is not supported */
+	if (session->controller == NULL)
+		avrcp_get_capabilities(session);
 
 	/* Auto-connect browsing channel only if initiator */
 	if (old_state == BTD_SERVICE_STATE_CONNECTING &&
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 3/4] audio/media: Fix not updating position
  2013-07-23 12:52 [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Luiz Augusto von Dentz
  2013-07-23 12:52 ` [PATCH BlueZ 2/4] audio/AVRCP: Fix registration of VOLUME_CHANGED Luiz Augusto von Dentz
@ 2013-07-23 12:52 ` Luiz Augusto von Dentz
  2013-07-23 12:52 ` [PATCH BlueZ 4/4] audio/player: Fix attempting to set the same setting value Luiz Augusto von Dentz
  2013-07-24  4:45 ` [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Johan Hedberg
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2013-07-23 12:52 UTC (permalink / raw)
  To: linux-bluetooth

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

The status may not be 'playing' as MPRIS documents it as 'Playing'
instead, to make this less prone to typos like this the code now
uses strcasecmp.
---
 profiles/audio/media.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/profiles/audio/media.c b/profiles/audio/media.c
index f1ad439..715d49c 100644
--- a/profiles/audio/media.c
+++ b/profiles/audio/media.c
@@ -1131,7 +1131,7 @@ static uint32_t get_position(void *user_data)
 	double timedelta;
 	uint32_t sec, msec;
 
-	if (g_strcmp0(mp->status, "playing") != 0)
+	if (mp->status == NULL || strcasecmp(mp->status, "Playing") != 0)
 		return mp->position;
 
 	timedelta = g_timer_elapsed(mp->timer, NULL);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 4/4] audio/player: Fix attempting to set the same setting value
  2013-07-23 12:52 [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Luiz Augusto von Dentz
  2013-07-23 12:52 ` [PATCH BlueZ 2/4] audio/AVRCP: Fix registration of VOLUME_CHANGED Luiz Augusto von Dentz
  2013-07-23 12:52 ` [PATCH BlueZ 3/4] audio/media: Fix not updating position Luiz Augusto von Dentz
@ 2013-07-23 12:52 ` Luiz Augusto von Dentz
  2013-07-24  4:45 ` [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Johan Hedberg
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2013-07-23 12:52 UTC (permalink / raw)
  To: linux-bluetooth

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

This cause unnecessary commands to be sent over the air so instead the
code should just return success as nothing should be changed.
---
 profiles/audio/player.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 917c66e..a817b54 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -263,7 +263,7 @@ static void set_setting(const GDBusPropertyTable *property,
 			void *data)
 {
 	struct media_player *mp = data;
-	const char *value;
+	const char *value, *current;
 
 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
 		g_dbus_pending_property_error(id,
@@ -274,6 +274,12 @@ static void set_setting(const GDBusPropertyTable *property,
 
 	dbus_message_iter_get_basic(iter, &value);
 
+	current = g_hash_table_lookup(mp->settings, property->name);
+	if (g_strcmp0(current, value) == 0) {
+		g_dbus_pending_property_success(id);
+		return;
+	}
+
 	player_set_setting(mp, id, property->name, value);
 }
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection
  2013-07-23 12:52 [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2013-07-23 12:52 ` [PATCH BlueZ 4/4] audio/player: Fix attempting to set the same setting value Luiz Augusto von Dentz
@ 2013-07-24  4:45 ` Johan Hedberg
  3 siblings, 0 replies; 5+ messages in thread
From: Johan Hedberg @ 2013-07-24  4:45 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

On Tue, Jul 23, 2013, Luiz Augusto von Dentz wrote:
> 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(-)

All four patches have been applied. Thanks.

Johan

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-07-24  4:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-23 12:52 [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Luiz Augusto von Dentz
2013-07-23 12:52 ` [PATCH BlueZ 2/4] audio/AVRCP: Fix registration of VOLUME_CHANGED Luiz Augusto von Dentz
2013-07-23 12:52 ` [PATCH BlueZ 3/4] audio/media: Fix not updating position Luiz Augusto von Dentz
2013-07-23 12:52 ` [PATCH BlueZ 4/4] audio/player: Fix attempting to set the same setting value Luiz Augusto von Dentz
2013-07-24  4:45 ` [PATCH BlueZ 1/4] audio/AVRCP: Rework role detection Johan Hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.