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

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

 



Hi Bharat,

On Thu, Aug 13, 2015 at 6:20 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)
> ---
>  profiles/audio/avrcp.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 131 insertions(+)
>
> diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
> index d66f670..61d91ea 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 notify_id;
>
>         struct pending_list_items *p;
>         char *change_path;
> @@ -631,6 +634,7 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
>         GSList *l;
>         int attr;
>         int val;
> +       bool player_changed = false;
>
>         if (player->sessions == NULL)
>                 return;
> @@ -674,6 +678,12 @@ 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));
> +               player_changed = true;
> +               break;
>         case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
>                 size = 1;
>                 break;
> @@ -695,6 +705,7 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
>                                         session->transaction_events[id],
>                                         AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
>                                         buf, size + AVRCP_HEADER_LENGTH);
> +
>                 if (err < 0)
>                         continue;
>
> @@ -702,6 +713,52 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id,
>                 session->registered_events ^= 1 << id;
>         }
>
> +       if (player_changed) {
> +               uint8_t player_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
> +                                       };
> +
> +               for (l = player->sessions; l; l = l->next) {
> +                       struct avrcp *session = l->data;
> +                       int err;
> +                       int i;
> +
> +                       for (i = 0; i < 6; i++) {

Check with i < sizeof(player_events) so in case we need to add some
new event we don't need to always keep changing this.

> +                               if (!(session->registered_events &
> +                                               (1 << player_events[i])))
> +                                       continue;
> +
> +                               if (session->registered_events &
> +                                               (1 << player_events[i])) {
> +                                       session->registered_events &=
> +                                               ~(1 << player_events[i]);
> +                               /*
> +                                * TG shall complete all player specific
> +                                * notifications with AV/C C-Type REJECTED
> +                                * with error code as Addressed Player Changed.
> +                                */
> +
> +                               pdu->params[0] =
> +                                       AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED;
> +                               pdu->params_len = htons(1);
> +                               err = avctp_send_vendordep(session->conn,
> +                                       session->transaction_events[player_events[i]],
> +                                       AVC_CTYPE_REJECTED, AVC_SUBUNIT_PANEL,
> +                                       buf, 1 + AVRCP_HEADER_LENGTH);
> +                               }
> +                       }
> +
> +                       if (err < 0)
> +                               continue;
> +
> +               }
> +       }
> +
>         return;
>  }
>
> @@ -1494,6 +1551,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 +1679,72 @@ 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;
> +
> +       avrcp_player_event(player,
> +                               AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED, NULL);
> +       g_source_remove(player->notify_id);

Removing the source wouldn't be necessary if you return FALSE or
G_SOURCE_REMOVE if we want to more gnomish, furthermore notify_id
shall be set to 0 either way and the call to g_source_remove shall be
move to where the player freed so we stop the callback to be called if
the player is unregistered.

> +
> +       return TRUE;
> +}
> +
> +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;
> +       }
> +
> +       player->notify_id =
> +                       g_idle_add((GSourceFunc)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 +1776,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 },
>                 { },
>  };
>
> @@ -3521,6 +3651,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 */
> --
> 1.9.1
>
> --
> 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



-- 
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