summaryrefslogtreecommitdiff
path: root/profiles
diff options
context:
space:
mode:
authorBharat Panda <bharat.panda@samsung.com>2015-11-16 15:01:07 +0530
committerBharat Panda <bharat.panda@samsung.com>2015-11-16 15:01:07 +0530
commit04f98a67853d66bfeba0e9436f8f5e01c29dc51b (patch)
treed54b55aab09cc0f378f26806f7d7dd1ab7dcd886 /profiles
parent45dc9f0e65df9f5a7b9c9bbca4b706718906d230 (diff)
downloadbluez-04f98a67853d66bfeba0e9436f8f5e01c29dc51b.tar.gz
bluez-04f98a67853d66bfeba0e9436f8f5e01c29dc51b.tar.bz2
bluez-04f98a67853d66bfeba0e9436f8f5e01c29dc51b.zip
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. git repo link: http://git.kernel.org/cgit/bluetooth/bluez.git/commit/?id=4827d6b61fd4fae4d0ba2fe46c42e5021b97ca56 Change-Id: I0463a1875f2bf920985feaed3ff764c1a75bf083
Diffstat (limited to 'profiles')
-rw-r--r--profiles/audio/avrcp.c118
1 files changed, 116 insertions, 2 deletions
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 5d65d7ef..e09ed27e 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;
@@ -680,6 +683,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;
@@ -697,10 +701,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;
@@ -761,6 +774,11 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
memcpy(&pdu->params[1], position_val, sizeof(uint32_t));
break;
#endif
+ 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;
@@ -769,6 +787,7 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
return;
}
+done:
pdu->params_len = htons(size);
#ifdef __TIZEN_PATCH__
if (id == AVRCP_EVENT_PLAYBACK_POS_CHANGED &&
@@ -791,7 +810,7 @@ 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;
@@ -1679,6 +1698,11 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
break;
#endif
+ 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;
@@ -1790,6 +1814,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 },
@@ -1821,6 +1929,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 },
{ },
};
@@ -3206,6 +3316,9 @@ static void player_destroy(gpointer data)
avrcp_stop_position_timer();
#endif
+ 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);
@@ -3677,6 +3790,7 @@ static void target_init(struct avrcp *session)
return;
session->supported_events |=
+ (1 << AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED) |
(1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED) |
(1 << AVRCP_EVENT_VOLUME_CHANGED);