Re: [PATCH v2] audio/avrcp: Add Set Addressed Player support

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

 



Hi Bharat,

On Fri, Aug 14, 2015 at 4:36 PM, Bharat Panda <bharat.panda@xxxxxxxxxxx> wrote:
> Support added to handle Set Addressed Player PDU in TG role.
> Send EVENT_ADDRESSED_PLAYER_CHANGED on SetAddressedPlayer
> SUCCESS and follow procedure to reject all player specific events
> currently registered with the player.
>
>       Channel: 64 len 15 [PSM 23 mode 0] {chan 0}
>       AVCTP Control: Command: type 0x00 label 0 PID 0x110e
>         AV/C: Control: address 0x48 opcode 0x00
>           Subunit: Panel
>           Opcode: Vendor Dependent
>           Company ID: 0x001958
>           AVRCP: SetAddressedPlayer pt Single len 0x0002
>             PlayerID: 0x0000 (0)
>
>       Channel: 64 len 15 [PSM 23 mode 0] {chan 0}
>       AVCTP Control: Response: type 0x00 label 0 PID 0x110e
>         AV/C: Accepted: address 0x48 opcode 0x00
>           Subunit: Panel
>           Opcode: Vendor Dependent
>           Company ID: 0x001958
>           AVRCP: SetAddressedPlayer pt Single len 0x0002
>             Status: 0x04 (Success)
>
>       Channel: 64 len 18 [PSM 23 mode 0] {chan 0}
>       AVCTP Control: Response: type 0x00 label 0 PID 0x110e
>         AV/C: Changed: address 0x48 opcode 0x00
>           Subunit: Panel
>           Opcode: Vendor Dependent
>           Company ID: 0x001958
>           AVRCP: RegisterNotification pt Single len 0x0005
>             EventID: 0x0b (EVENT_ADDRESSED_PLAYER_CHANGED)
>             PlayerID: 0x0000 (0)
>             UIDCounter: 0x0000 (0)
> ---

I went ahead and made some changes to make the code look simpler and
reuse avrcp_player_event, please check if it still work as before.

-- 
Luiz Augusto von Dentz
From d2cddd0a6d919649d1d396d249f306e931ea609b Mon Sep 17 00:00:00 2001
From: Bharat Panda <bharat.panda@xxxxxxxxxxx>
Date: Fri, 14 Aug 2015 19:06:36 +0530
Subject: [PATCH BlueZ] audio/avrcp: Add Set Addressed Player support

Support added to handle Set Addressed Player PDU in TG role.
Send EVENT_ADDRESSED_PLAYER_CHANGED on SetAddressedPlayer
SUCCESS and follow procedure to reject all player specific events
currently registered with the player.

      Channel: 64 len 15 [PSM 23 mode 0] {chan 0}
      AVCTP Control: Command: type 0x00 label 0 PID 0x110e
        AV/C: Control: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: SetAddressedPlayer pt Single len 0x0002
            PlayerID: 0x0000 (0)

      Channel: 64 len 15 [PSM 23 mode 0] {chan 0}
      AVCTP Control: Response: type 0x00 label 0 PID 0x110e
        AV/C: Accepted: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: SetAddressedPlayer pt Single len 0x0002
            Status: 0x04 (Success)

      Channel: 64 len 18 [PSM 23 mode 0] {chan 0}
      AVCTP Control: Response: type 0x00 label 0 PID 0x110e
        AV/C: Changed: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: RegisterNotification pt Single len 0x0005
            EventID: 0x0b (EVENT_ADDRESSED_PLAYER_CHANGED)
            PlayerID: 0x0000 (0)
            UIDCounter: 0x0000 (0)
---
 profiles/audio/avrcp.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 117 insertions(+), 2 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index d66f670..76e89af 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -103,6 +103,7 @@
 #define AVRCP_REQUEST_CONTINUING	0x40
 #define AVRCP_ABORT_CONTINUING		0x41
 #define AVRCP_SET_ABSOLUTE_VOLUME	0x50
+#define AVRCP_SET_ADDRESSED_PLAYER	0x60
 #define AVRCP_SET_BROWSED_PLAYER	0x70
 #define AVRCP_GET_FOLDER_ITEMS		0x71
 #define AVRCP_CHANGE_PATH		0x72
@@ -204,8 +205,10 @@ struct avrcp_player {
 	uint64_t uid;
 	uint16_t uid_counter;
 	bool browsed;
+	bool addressed;
 	uint8_t *features;
 	char *path;
+	guint changed_id;
 
 	struct pending_list_items *p;
 	char *change_path;
@@ -627,6 +630,7 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
 {
 	uint8_t buf[AVRCP_HEADER_LENGTH + 9];
 	struct avrcp_header *pdu = (void *) buf;
+	uint8_t code;
 	uint16_t size;
 	GSList *l;
 	int attr;
@@ -640,10 +644,19 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
 	set_company_id(pdu->company_id, IEEEID_BTSIG);
 
 	pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
-	pdu->params[0] = id;
 
 	DBG("id=%u", id);
 
+	if (id != AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED && player->changed_id) {
+		code = AVC_CTYPE_REJECTED;
+		size = 1;
+		pdu->params[0] = AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED;
+		goto done;
+	}
+
+	code = AVC_CTYPE_CHANGED;
+	pdu->params[0] = id;
+
 	switch (id) {
 	case AVRCP_EVENT_STATUS_CHANGED:
 		size = 2;
@@ -674,6 +687,11 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
 		pdu->params[size++] = attr;
 		pdu->params[size++] = val;
 		break;
+	case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+		size = 5;
+		memcpy(&pdu->params[1], &player->id, sizeof(uint16_t));
+		memcpy(&pdu->params[3], &player->uid_counter, sizeof(uint16_t));
+		break;
 	case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
 		size = 1;
 		break;
@@ -682,6 +700,7 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
 		return;
 	}
 
+done:
 	pdu->params_len = htons(size);
 
 	for (l = player->sessions; l; l = l->next) {
@@ -693,8 +712,9 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
 
 		err = avctp_send_vendordep(session->conn,
 					session->transaction_events[id],
-					AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
+					code, AVC_SUBUNIT_PANEL,
 					buf, size + AVRCP_HEADER_LENGTH);
+
 		if (err < 0)
 			continue;
 
@@ -1494,6 +1514,11 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
 		}
 
 		break;
+	case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+		len = 5;
+		memcpy(&pdu->params[1], &player->id, sizeof(uint16_t));
+		memcpy(&pdu->params[3], &player->uid_counter, sizeof(uint16_t));
+		break;
 	case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
 		len = 1;
 		break;
@@ -1617,6 +1642,90 @@ err:
 	return AVC_CTYPE_REJECTED;
 }
 
+static struct avrcp_player *find_tg_player(struct avrcp *session, uint16_t id)
+{
+	struct avrcp_server *server = session->server;
+	GSList *l;
+
+	for (l = server->players; l; l = l->next) {
+		struct avrcp_player *player = l->data;
+
+		if (player->id == id)
+			return player;
+	}
+
+	return NULL;
+}
+
+static gboolean notify_addressed_player_changed(gpointer user_data)
+{
+	struct avrcp_player *player = user_data;
+	uint8_t events[6] = { AVRCP_EVENT_STATUS_CHANGED,
+					AVRCP_EVENT_TRACK_CHANGED,
+					AVRCP_EVENT_TRACK_REACHED_START,
+					AVRCP_EVENT_TRACK_REACHED_END,
+					AVRCP_EVENT_SETTINGS_CHANGED,
+					AVRCP_EVENT_PLAYBACK_POS_CHANGED
+				};
+	uint8_t i;
+
+	avrcp_player_event(player, AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED, NULL);
+
+	/*
+	 * TG shall complete all player specific
+	 * notifications with AV/C C-Type REJECTED
+	 * with error code as Addressed Player Changed.
+	 */
+	for (i = 0; i < sizeof(events); i++)
+		avrcp_player_event(player, events[i], NULL);
+
+	player->changed_id = 0;
+
+	return FALSE;
+}
+
+static uint8_t avrcp_handle_set_addressed_player(struct avrcp *session,
+						struct avrcp_header *pdu,
+						uint8_t transaction)
+{
+	struct avrcp_player *player;
+	uint16_t len = ntohs(pdu->params_len);
+	uint16_t player_id = 0;
+	uint8_t status;
+
+	if (len < 1) {
+		status = AVRCP_STATUS_INVALID_PARAM;
+		goto err;
+	}
+
+	player_id = bt_get_be16(&pdu->params[0]);
+	player = find_tg_player(session, player_id);
+	pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+	if (player) {
+		player->addressed = true;
+		status = AVRCP_STATUS_SUCCESS;
+		pdu->params_len = htons(len);
+		pdu->params[0] = status;
+	} else {
+		status = AVRCP_STATUS_INVALID_PLAYER_ID;
+		goto err;
+	}
+
+	/* Don't emit player changed immediately since PTS expect the
+	 * response of SetAddressedPlayer before the event.
+	 */
+	player->changed_id = g_idle_add(notify_addressed_player_changed,
+								player);
+
+	return AVC_CTYPE_ACCEPTED;
+
+err:
+	pdu->params_len = htons(sizeof(status));
+	pdu->params[0] = status;
+	return AVC_CTYPE_REJECTED;
+}
+
 static const struct control_pdu_handler control_handlers[] = {
 		{ AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
 					avrcp_handle_get_capabilities },
@@ -1648,6 +1757,8 @@ static const struct control_pdu_handler control_handlers[] = {
 					avrcp_handle_request_continuing },
 		{ AVRCP_ABORT_CONTINUING, AVC_CTYPE_CONTROL,
 					avrcp_handle_abort_continuing },
+		{ AVRCP_SET_ADDRESSED_PLAYER, AVC_CTYPE_CONTROL,
+					avrcp_handle_set_addressed_player },
 		{ },
 };
 
@@ -3029,6 +3140,9 @@ static void player_destroy(gpointer data)
 	if (player->destroy)
 		player->destroy(player->user_data);
 
+	if (player->changed_id > 0)
+		g_source_remove(player->changed_id);
+
 	g_slist_free(player->sessions);
 	g_free(player->path);
 	g_free(player->change_path);
@@ -3521,6 +3635,7 @@ static void target_init(struct avrcp *session)
 		return;
 
 	session->supported_events |=
+				(1 << AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED) |
 				(1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED);
 
 	/* Only check capabilities if controller is not supported */
-- 
2.4.3


[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