Re: [PATCH v2] audio/avrcp: Add GetFolderItems support

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

 



Hi Bharat,

On Tue, Sep 1, 2015 at 3:27 PM, Bharat Panda <bharat.panda@xxxxxxxxxxx> 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
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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