Re: [PATCH v4 18/22] avrcp: send response for registered events

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

 



Hi Lucas,

On Thu, Aug 11, 2011 at 6:53 PM, Lucas De Marchi
<lucas.demarchi@xxxxxxxxxxxxxx> wrote:
> When a certain event occur, check if CT registered to receive that
> notification and send a response.
>
> Example event for PTS test TC_TG_NFY_BV_02_C:
>
>> ACL data: handle 11 flags 0x02 dlen 22
>    L2CAP(d): cid 0x0043 len 18 [psm 23]
>      AVCTP: Command : pt 0x00 transaction 2 pid 0x110e
>        AV/C: Notify: address 0x48 opcode 0x00
>          Subunit: Panel
>          Opcode: Vendor Dependent
>          Company ID: 0x001958
>          AVRCP: RegisterNotification: pt 0x00 len 0x0005
>            EventID: 0x02 (EVENT_TRACK_CHANGED)
>            Interval: 0x00000000 (0 seconds)
> < ACL data: handle 11 flags 0x02 dlen 26
>    L2CAP(d): cid 0x0043 len 22 [psm 23]
>      AVCTP: Response : pt 0x00 transaction 2 pid 0x110e
>        AV/C: Interim: address 0x48 opcode 0x00
>          Subunit: Panel
>          Opcode: Vendor Dependent
>          Company ID: 0x001958
>          AVRCP: RegisterNotification: pt 0x00 len 0x0009
>            EventID: 0x02 (EVENT_TRACK_CHANGED)
>            Identifier: 0x0 (PLAYING)
>
> [...]
>
> < ACL data: handle 11 flags 0x02 dlen 26
>    L2CAP(d): cid 0x0043 len 22 [psm 23]
>      AVCTP: Response : pt 0x00 transaction 2 pid 0x110e
>        AV/C: Changed: address 0x48 opcode 0x00
>          Subunit: Panel
>          Opcode: Vendor Dependent
>          Company ID: 0x001958
>          AVRCP: RegisterNotification: pt 0x00 len 0x0009
>            EventID: 0x02 (EVENT_TRACK_CHANGED)
>            Identifier: 0x0 (PLAYING)
> ---
>  audio/control.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 files changed, 91 insertions(+), 4 deletions(-)
>
> diff --git a/audio/control.c b/audio/control.c
> index a29a392..2070e10 100644
> --- a/audio/control.c
> +++ b/audio/control.c
> @@ -79,6 +79,7 @@
>  #define CTYPE_ACCEPTED         0x9
>  #define CTYPE_REJECTED         0xA
>  #define CTYPE_STABLE           0xC
> +#define CTYPE_CHANGED          0xD
>  #define CTYPE_INTERIM          0xF
>
>  /* opcodes */
> @@ -313,6 +314,7 @@ struct control {
>        uint8_t key_quirks[256];
>
>        uint16_t registered_events;
> +       uint8_t transaction_events[AVRCP_EVENT_TRACK_CHANGED + 1];
>  };
>
>  static struct {
> @@ -716,6 +718,73 @@ static const char *battery_status_to_str(enum battery_status status)
>        return NULL;
>  }
>
> +static int avctp_send_event(struct control *control, uint8_t id, void *data)
> +{
> +       uint8_t buf[AVCTP_HEADER_LENGTH + AVRCP_HEADER_LENGTH +
> +                                       AVRCP_SPECAVCPDU_HEADER_LENGTH + 9];
> +       struct avctp_header *avctp = (void *) buf;
> +       struct avrcp_header *avrcp = (void *) &buf[AVCTP_HEADER_LENGTH];
> +       struct avrcp_spec_avc_pdu *pdu = (void *) &buf[AVCTP_HEADER_LENGTH +
> +                                                       AVRCP_HEADER_LENGTH];
> +       int sk = g_io_channel_unix_get_fd(control->io);
> +       uint16_t size;
> +
> +       memset(buf, 0, sizeof(buf));
> +
> +       avctp->transaction = control->transaction_events[id];
> +       avctp->packet_type = AVCTP_PACKET_SINGLE;
> +       avctp->cr = AVCTP_RESPONSE;
> +       avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
> +
> +       avrcp->code = CTYPE_CHANGED;
> +       avrcp->subunit_type = SUBUNIT_PANEL;
> +       avrcp->opcode = OP_VENDORDEP;
> +
> +       pdu->company_id[0] = IEEEID_BTSIG >> 16;
> +       pdu->company_id[1] = (IEEEID_BTSIG >> 8) & 0xFF;
> +       pdu->company_id[2] = IEEEID_BTSIG & 0xFF;
> +
> +       pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
> +       pdu->params[0] = id;
> +
> +       DBG("id=%u", id);
> +
> +       switch (id) {
> +       case AVRCP_EVENT_PLAYBACK_STATUS_CHANGED:
> +               size = 2;
> +               pdu->params[1] = *((uint8_t *)data);
> +
> +               break;
> +       case AVRCP_EVENT_TRACK_CHANGED: {
> +               size = 9;
> +
> +               /*
> +                * AVRCP 1.3 supports only one track identifier: PLAYING
> +                * (0x0). When 1.4 version is added, this shall be changed to
> +                * contain the identifier of the track.
> +                */
> +               memset(&pdu->params[1], 0, 8);
> +
> +               break;
> +       }
> +       default:
> +               error("Unknown event %u", id);
> +               return -EINVAL;
> +       }
> +
> +       pdu->params_len = htons(size);
> +       size += AVCTP_HEADER_LENGTH + AVRCP_HEADER_LENGTH +
> +                                       AVRCP_SPECAVCPDU_HEADER_LENGTH;
> +
> +       if (write(sk, buf, size) < 0)
> +               return -errno;
> +
> +       /* Unregister event as per AVRCP 1.3 spec, section 5.4.2 */
> +       control->registered_events ^= 1 << id;
> +
> +       return 0;
> +}
> +
>  static void mp_get_playback_status(struct media_player *mp, uint8_t *status,
>                                        uint32_t *elapsed, uint32_t *track_len)
>  {
> @@ -754,6 +823,13 @@ static void mp_set_playback_status(struct control *control, uint8_t status,
>                return;
>
>        mp->status = status;
> +
> +       if (control->state == AVCTP_STATE_CONNECTED &&
> +                               (control->registered_events &
> +                               (1 << AVRCP_EVENT_PLAYBACK_STATUS_CHANGED))) {
> +               avctp_send_event(control, AVRCP_EVENT_PLAYBACK_STATUS_CHANGED,
> +                                                               &status);
> +       }
>  }
>
>  /*
> @@ -901,6 +977,12 @@ static void mp_set_media_attributes(struct control *control,
>                           "\tTrack number: %u\n\tTrack duration: %u",
>                           mi->title, mi->artist, mi->album, mi->genre,
>                           mi->ntracks, mi->track, mi->track_len);
> +
> +       if (control->state == AVCTP_STATE_CONNECTED &&
> +                                       (control->registered_events &
> +                                        (1 << AVRCP_EVENT_TRACK_CHANGED))) {
> +               avctp_send_event(control, AVRCP_EVENT_TRACK_CHANGED, NULL);
> +       }
>  }
>
>  static int avrcp_handle_get_capabilities(struct control *control,
> @@ -1241,7 +1323,8 @@ static int avrcp_handle_get_play_status(struct control *control,
>  }
>
>  static int avrcp_handle_register_notification(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        uint8_t status;
> @@ -1280,8 +1363,9 @@ static int avrcp_handle_register_notification(struct control *control,
>                goto err;
>        }
>
> -       /* Register event */
> +       /* Register event and save the transaction used */
>        control->registered_events |= (1 << pdu->params[0]);
> +       control->transaction_events[pdu->params[0]] = transaction;
>
>        pdu->params_len = htons(len);
>
> @@ -1294,6 +1378,7 @@ err:
>
>  /* handle vendordep pdu inside an avctp packet */
>  static int handle_vendordep_pdu(struct control *control,
> +                                       struct avctp_header *avctp,
>                                        struct avrcp_header *avrcp,
>                                        int operand_count)
>  {
> @@ -1464,7 +1549,8 @@ static int handle_vendordep_pdu(struct control *control,
>                        goto err_metadata;
>                }
>
> -               len = avrcp_handle_register_notification(control, pdu);
> +               len = avrcp_handle_register_notification(control, pdu,
> +                                                       avctp->transaction);
>                if (len < 0)
>                        goto err_metadata;
>
> @@ -1662,7 +1748,8 @@ static gboolean control_cb(GIOChannel *chan, GIOCondition cond,
>                int r_size;
>                operand_count -= 3;
>                avctp->cr = AVCTP_RESPONSE;
> -               r_size = handle_vendordep_pdu(control, avrcp, operand_count);
> +               r_size = handle_vendordep_pdu(control, avctp, avrcp,
> +                                                               operand_count);
>                packet_size = AVCTP_HEADER_LENGTH + r_size;
>        } else {
>                avctp->cr = AVCTP_RESPONSE;
> --
> 1.7.6

Looks good now, thanks for the quick update.

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