Return-Path: MIME-Version: 1.0 In-Reply-To: <1441110447-27181-1-git-send-email-bharat.panda@samsung.com> References: <1441110447-27181-1-git-send-email-bharat.panda@samsung.com> Date: Wed, 2 Sep 2015 14:40:43 +0300 Message-ID: Subject: Re: [PATCH v2] audio/avrcp: Add GetFolderItems support From: Luiz Augusto von Dentz To: Bharat Panda Cc: "linux-bluetooth@vger.kernel.org" , cpgs@samsung.com Content-Type: text/plain; charset=UTF-8 Sender: linux-bluetooth-owner@vger.kernel.org List-ID: Hi Bharat, On Tue, Sep 1, 2015 at 3:27 PM, Bharat Panda wrote: > Support added to handle Get Folder Items browsing PDU > for media player scope in TG role. > > e.g. > AVCTP Browsing: Response: type 0x00 label 0 PID 0x110e > AVRCP: GetFolderItems: len 0x0030 > Status: 0x04 (Success) > UIDCounter: 0x0000 (0) > NumOfItems: 0x0001 (1) > Item: 0x01 (Media Player) > Length: 0x0028 (40) > PlayerID: 0x0000 (0) > PlayerType: 0x0001 (Audio) > PlayerSubType: 0x00000001 (Audio Book) > PlayStatus: 0x01 (PLAYING) > Features: 0x0000000000000007FFF0007000000000 > CharsetID: 0x006a (UTF-8) > NameLength: 0x000c (12) > Name: SimplePlayer > --- > profiles/audio/avrcp.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++ > profiles/audio/avrcp.h | 1 + > profiles/audio/media.c | 8 +++ > 3 files changed, 161 insertions(+) > > diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c > index d2b0065..e39b31a 100644 > --- a/profiles/audio/avrcp.c > +++ b/profiles/audio/avrcp.c > @@ -140,6 +140,11 @@ > #define AVRCP_CT_VERSION 0x0106 > #define AVRCP_TG_VERSION 0x0105 > > +#define AVRCP_SCOPE_MEDIA_PLAYER_LIST 0x00 > +#define AVRCP_SCOPE_MEDIA_PLAYER_VFS 0x01 > +#define AVRCP_SCOPE_SEARCH 0x02 > +#define AVRCP_SCOPE_NOW_PLAYING 0x03 > + > #if __BYTE_ORDER == __LITTLE_ENDIAN > > struct avrcp_header { > @@ -178,6 +183,30 @@ struct avrcp_browsing_header { > } __attribute__ ((packed)); > #define AVRCP_BROWSING_HEADER_LENGTH 3 > > +struct get_folder_items_rsp { > + uint8_t status; > + uint16_t uid_counter; > + uint16_t num_items; > + uint8_t data[0]; > +} __attribute__ ((packed)); > + > +struct folder_item { > + uint8_t type; > + uint16_t len; > + uint8_t data[0]; > +} __attribute__ ((packed)); > + > +struct player_item { > + uint16_t player_id; > + uint8_t type; > + uint32_t subtype; > + uint8_t status; > + uint8_t features[16]; > + uint16_t charset; > + uint16_t namelen; > + char name[0]; > +} __attribute__ ((packed)); > + > struct avrcp_server { > struct btd_adapter *adapter; > uint32_t tg_record_id; > @@ -263,6 +292,18 @@ struct control_pdu_handler { > static GSList *servers = NULL; > static unsigned int avctp_id = 0; > > +/* Default feature bit mask for media player > + * supporting Play, Stop, Pause, Rewind, Record, > + * fast forward, Forward, Backward, channel up/down/prev, > + * volume up/down, help, power, exit, menu, Vendor Unique, > + * Advanced Control Player, etc. > + */ > +static const uint8_t features[16] = { > + 0x00, 0x00, 0x00, 0x00, 0x00, > + 0x00, 0x00, 0x07, 0xFF, 0xF0, > + 0x00, 0x70, 0x00, 0x00, 0x00, > + 0x00 }; > + > /* Company IDs supported by this device */ > static uint32_t company_ids[] = { > IEEEID_BTSIG, > @@ -1841,11 +1882,122 @@ err_metadata: > return AVRCP_HEADER_LENGTH + 1; > } > > +static void avrcp_handle_media_player_list(struct avrcp *session, > + struct avrcp_browsing_header *pdu, > + uint32_t start_item, uint32_t end_item) > +{ > + struct avrcp_player *player = session->target->player; > + struct get_folder_items_rsp *rsp; > + const char *name = NULL; > + GSList *l; > + > + rsp = (void *)pdu->params; > + rsp->status = AVRCP_STATUS_SUCCESS; > + rsp->uid_counter = htons(player_get_uid_counter(player)); > + rsp->num_items = 0; > + pdu->param_len = sizeof(*rsp); > + > + for (l = g_slist_nth(session->server->players, start_item); > + l; l = g_slist_next(l)) { > + struct avrcp_player *player = l->data; > + struct folder_item *folder; > + struct player_item *item; > + uint16_t namelen; > + > + if (rsp->num_items == (end_item - start_item) + 1) > + break; > + > + folder = (void *)&pdu->params[pdu->param_len]; > + folder->type = 0x01; /* Media Player */ > + > + pdu->param_len += sizeof(*folder); > + > + item = (void *)folder->data; > + item->player_id = htons(player->id); > + item->type = 0x01; /* Audio */ > + item->subtype = htonl(0x01); /* Audio Book */ > + item->status = player_get_status(player); > + /* Assign Default Feature Bit Mask */ > + memcpy(&item->features, &features, sizeof(features)); > + > + item->charset = htons(AVRCP_CHARSET_UTF8); > + > + name = player->cb->get_sender(player->user_data); > + namelen = strlen(name); > + item->namelen = htons(namelen); > + memcpy(item->name, name, namelen); > + > + folder->len = htons(sizeof(*item) + namelen); > + pdu->param_len += sizeof(*item) + namelen; > + rsp->num_items++; > + } > + > + /* If no player could be found respond with an error */ > + if (!rsp->num_items) > + goto failed; > + > + rsp->num_items = htons(rsp->num_items); > + pdu->param_len = htons(pdu->param_len); > + > + return; > + > +failed: > + pdu->params[0] = AVRCP_STATUS_OUT_OF_BOUNDS; > + pdu->param_len = htons(1); > +} > + > +static void avrcp_handle_get_folder_items(struct avrcp *session, > + struct avrcp_browsing_header *pdu, > + uint8_t transaction) > +{ > + uint32_t start_item = 0; > + uint32_t end_item = 0; > + uint8_t scope; > + uint8_t status = AVRCP_STATUS_SUCCESS; > + > + if (!pdu || ntohs(pdu->param_len) < 10) { > + status = AVRCP_STATUS_INVALID_PARAM; > + goto failed; > + } > + > + scope = pdu->params[0]; > + start_item = bt_get_be32(&pdu->params[1]); > + end_item = bt_get_be32(&pdu->params[5]); > + > + DBG("scope 0x%02x start_item 0x%08x end_item 0x%08x", scope, > + start_item, end_item); > + > + if (end_item < start_item) { > + status = AVRCP_STATUS_INVALID_PARAM; > + goto failed; > + } > + > + switch (scope) { > + case AVRCP_SCOPE_MEDIA_PLAYER_LIST: > + avrcp_handle_media_player_list(session, pdu, > + start_item, end_item); > + break; > + case AVRCP_SCOPE_MEDIA_PLAYER_VFS: > + case AVRCP_SCOPE_SEARCH: > + case AVRCP_SCOPE_NOW_PLAYING: > + default: > + status = AVRCP_STATUS_INVALID_PARAM; > + goto failed; > + } > + > + return; > + > +failed: > + pdu->params[0] = status; > + pdu->param_len = htons(1); > +} > + > static struct browsing_pdu_handler { > uint8_t pdu_id; > void (*func) (struct avrcp *session, struct avrcp_browsing_header *pdu, > uint8_t transaction); > } browsing_handlers[] = { > + { AVRCP_GET_FOLDER_ITEMS, avrcp_handle_get_folder_items }, > { }, > }; > > diff --git a/profiles/audio/avrcp.h b/profiles/audio/avrcp.h > index a9aeb1a..be54026 100644 > --- a/profiles/audio/avrcp.h > +++ b/profiles/audio/avrcp.h > @@ -93,6 +93,7 @@ struct avrcp_player_cb { > const char *(*get_status) (void *user_data); > uint32_t (*get_position) (void *user_data); > uint32_t (*get_duration) (void *user_data); > + const char *(*get_sender) (void *user_data); > void (*set_volume) (uint8_t volume, struct btd_device *dev, > void *user_data); > bool (*play) (void *user_data); > diff --git a/profiles/audio/media.c b/profiles/audio/media.c > index 6c25363..5819d42 100644 > --- a/profiles/audio/media.c > +++ b/profiles/audio/media.c > @@ -1014,6 +1014,13 @@ static const char *get_setting(const char *key, void *user_data) > return g_hash_table_lookup(mp->settings, key); > } > > +static const char *get_sender(void *user_data) > +{ > + struct media_player *mp = user_data; > + > + return mp->name; > +} > + > static void set_shuffle_setting(DBusMessageIter *iter, const char *value) > { > const char *key = "Shuffle"; > @@ -1274,6 +1281,7 @@ static struct avrcp_player_cb player_cb = { > .get_position = get_position, > .get_duration = get_duration, > .get_status = get_status, > + .get_sender = get_sender, > .set_volume = set_volume, > .play = play, > .stop = stop, > -- > 1.9.1 Applied, thanks. -- Luiz Augusto von Dentz