Linux bluetooth development
 help / color / mirror / Atom feed
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ 13/16] AVRCP: Add proper role init procedure
Date: Mon, 15 Oct 2012 16:05:33 +0200	[thread overview]
Message-ID: <1350309936-31588-13-git-send-email-luiz.dentz@gmail.com> (raw)
In-Reply-To: <1350309936-31588-1-git-send-email-luiz.dentz@gmail.com>

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

---
 audio/avrcp.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 103 insertions(+), 10 deletions(-)

diff --git a/audio/avrcp.c b/audio/avrcp.c
index 85dd241..8336831 100644
--- a/audio/avrcp.c
+++ b/audio/avrcp.c
@@ -104,6 +104,7 @@
 #define CAP_EVENTS_SUPPORTED	0x03
 
 #define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH 5
+#define AVRCP_GET_CAPABILITIES_PARAM_LENGTH 1
 
 #define AVRCP_FEATURE_CATEGORY_1	0x0001
 #define AVRCP_FEATURE_CATEGORY_2	0x0002
@@ -215,7 +216,7 @@ static uint32_t company_ids[] = {
 	IEEEID_BTSIG,
 };
 
-static void register_volume_notification(struct avrcp *session);
+static void register_notification(struct avrcp *session, uint8_t event);
 
 static sdp_record_t *avrcp_ct_record(void)
 {
@@ -1306,7 +1307,7 @@ static struct avrcp_server *find_server(GSList *list, const bdaddr_t *src)
 	return NULL;
 }
 
-static gboolean avrcp_handle_volume_changed(struct avctp *conn,
+static gboolean avrcp_handle_event(struct avctp *conn,
 					uint8_t code, uint8_t subunit,
 					uint8_t *operands, size_t operand_count,
 					void *user_data)
@@ -1314,26 +1315,34 @@ static gboolean avrcp_handle_volume_changed(struct avctp *conn,
 	struct avrcp *session = user_data;
 	struct avrcp_player *player = session->player;
 	struct avrcp_header *pdu = (void *) operands;
+	uint8_t event;
 	uint8_t volume;
 
 	if (code != AVC_CTYPE_INTERIM && code != AVC_CTYPE_CHANGED)
 		return FALSE;
 
-	volume = pdu->params[1] & 0x7F;
+	event = pdu->params[0];
 
-	if (player)
-		player->cb->set_volume(volume, session->dev,
+	switch (event) {
+	case AVRCP_EVENT_VOLUME_CHANGED:
+		volume = pdu->params[1] & 0x7F;
+
+		if (player)
+			player->cb->set_volume(volume, session->dev,
 							player->user_data);
 
+		break;
+	}
+
 	if (code == AVC_CTYPE_CHANGED) {
-		register_volume_notification(session);
+		register_notification(session, event);
 		return FALSE;
 	}
 
 	return TRUE;
 }
 
-static void register_volume_notification(struct avrcp *session)
+static void register_notification(struct avrcp *session, uint8_t event)
 {
 	uint8_t buf[AVRCP_HEADER_LENGTH + AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH];
 	struct avrcp_header *pdu = (void *) buf;
@@ -1344,14 +1353,89 @@ static void register_volume_notification(struct avrcp *session)
 	set_company_id(pdu->company_id, IEEEID_BTSIG);
 	pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
 	pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
-	pdu->params[0] = AVRCP_EVENT_VOLUME_CHANGED;
+	pdu->params[0] = event;
 	pdu->params_len = htons(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH);
 
 	length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
 
 	avctp_send_vendordep_req(session->conn, AVC_CTYPE_NOTIFY,
 					AVC_SUBUNIT_PANEL, buf, length,
-					avrcp_handle_volume_changed, session);
+					avrcp_handle_event, session);
+}
+
+static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_header *pdu = (void *) operands;
+	uint8_t count;
+
+	if (pdu->params[0] != CAP_EVENTS_SUPPORTED)
+		return FALSE;
+
+	count = pdu->params[1];
+
+	for (; count > 0; count--) {
+		uint8_t event = pdu->params[1 + count];
+
+		switch (event) {
+		case AVRCP_EVENT_STATUS_CHANGED:
+		case AVRCP_EVENT_TRACK_CHANGED:
+			register_notification(session, event);
+			break;
+		}
+	}
+
+	return FALSE;
+}
+
+static void avrcp_get_capabilities(struct avrcp *session)
+{
+	uint8_t buf[AVRCP_HEADER_LENGTH + AVRCP_GET_CAPABILITIES_PARAM_LENGTH];
+	struct avrcp_header *pdu = (void *) buf;
+	uint8_t length;
+
+	memset(buf, 0, sizeof(buf));
+
+	set_company_id(pdu->company_id, IEEEID_BTSIG);
+	pdu->pdu_id = AVRCP_GET_CAPABILITIES;
+	pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+	pdu->params[0] = CAP_EVENTS_SUPPORTED;
+	pdu->params_len = htons(AVRCP_GET_CAPABILITIES_PARAM_LENGTH);
+
+	length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+	avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+					AVC_SUBUNIT_PANEL, buf, length,
+					avrcp_get_capabilities_resp,
+					session);
+}
+
+static gboolean avrcp_get_play_status_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	return FALSE;
+}
+
+static void avrcp_get_play_status(struct avrcp *session)
+{
+	uint8_t buf[AVRCP_HEADER_LENGTH];
+	struct avrcp_header *pdu = (void *) buf;
+
+	memset(buf, 0, sizeof(buf));
+
+	set_company_id(pdu->company_id, IEEEID_BTSIG);
+	pdu->pdu_id = AVRCP_GET_PLAY_STATUS;
+	pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+	avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+					AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+					avrcp_get_play_status_rsp,
+					session);
 }
 
 static struct avrcp *find_session(GSList *list, struct audio_device *dev)
@@ -1370,11 +1454,13 @@ static void session_tg_init(struct avrcp *session)
 {
 	struct avrcp_server *server = session->server;
 
+	DBG("%p version 0x%04x", session, session->version);
+
 	session->player = g_slist_nth_data(server->players, 0);
 	session->control_handlers = tg_control_handlers;
 
 	if (session->version >= 0x0104) {
-		register_volume_notification(session);
+		register_notification(session, AVRCP_EVENT_VOLUME_CHANGED);
 		if (session->features & AVRCP_FEATURE_BROWSING)
 			avctp_connect_browsing(session->conn);
 	}
@@ -1393,6 +1479,13 @@ static void session_ct_init(struct avrcp *session)
 {
 	session->control_handlers = ct_control_handlers;
 
+	DBG("%p version 0x%04x", session, session->version);
+
+	if (session->version >= 0x0103) {
+		avrcp_get_capabilities(session);
+		avrcp_get_play_status(session);
+	}
+
 	session->control_id = avctp_register_pdu_handler(session->conn,
 							AVC_OP_VENDORDEP,
 							handle_vendordep_pdu,
-- 
1.7.11.4


  parent reply	other threads:[~2012-10-15 14:05 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-15 14:05 [PATCH BlueZ 01/16] AVCTP: Simplify channel handling Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 02/16] AVCTP: Allocate memory to hold incoming/outgoing PDUs Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 03/16] AVRCP: Register to AVCTP state changes without depending on player Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 04/16] AVRCP: Don't respond with errors when no player is registered Luiz Augusto von Dentz
2012-10-15 14:37   ` Johan Hedberg
2012-10-15 14:05 ` [PATCH BlueZ 05/16] AVRCP: Fix crash on disconnect Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 06/16] AVRCP: Simplify state_changed callback Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 07/16] AVCTP: Make use of allocate buffer to send data Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 08/16] AVCTP: Wait confirmation to send button release Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 09/16] AVCTP: Add proper prefix to AVC passthrough codes Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 10/16] AVCTP: Add proper queueing for channels Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 11/16] AVRCP: Fix reading wrong profile when acting as a controller Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 12/16] AVRCP: Fix handling TG PDUs as they were CT PDUs Luiz Augusto von Dentz
2012-10-15 14:05 ` Luiz Augusto von Dentz [this message]
2012-10-15 14:05 ` [PATCH BlueZ 14/16] control: Add basic support for AVRCP 1.0 controller Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 15/16] control: Add Control.Connect API Luiz Augusto von Dentz
2012-10-15 14:05 ` [PATCH BlueZ 16/16] control: Add Control.Disconnect method Luiz Augusto von Dentz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1350309936-31588-13-git-send-email-luiz.dentz@gmail.com \
    --to=luiz.dentz@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox