mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-26 05:34:23 +08:00
android/avrcp: Add avrcp_set_browsed_player() function
This commit is contained in:
parent
6114561af4
commit
007909a842
@ -74,6 +74,13 @@ struct avrcp_header {
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
struct avrcp_browsing_header {
|
||||
uint8_t pdu_id;
|
||||
uint16_t params_len;
|
||||
uint8_t params[0];
|
||||
} __attribute__ ((packed));
|
||||
#define AVRCP_BROWSING_HEADER_LENGTH 3
|
||||
|
||||
struct avrcp {
|
||||
struct avctp *conn;
|
||||
struct avrcp_player *player;
|
||||
@ -156,6 +163,28 @@ static struct avrcp_header *parse_pdu(uint8_t *operands, size_t operand_count)
|
||||
return pdu;
|
||||
}
|
||||
|
||||
static struct avrcp_browsing_header *parse_browsing_pdu(uint8_t *operands,
|
||||
size_t operand_count)
|
||||
{
|
||||
struct avrcp_browsing_header *pdu;
|
||||
|
||||
if (!operands || operand_count < sizeof(*pdu)) {
|
||||
error("AVRCP: packet too small (%zu bytes)", operand_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdu = (void *) operands;
|
||||
pdu->params_len = ntohs(pdu->params_len);
|
||||
|
||||
if (operand_count != pdu->params_len + sizeof(*pdu)) {
|
||||
error("AVRCP: invalid parameter length (%u bytes)",
|
||||
pdu->params_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
|
||||
uint8_t *code, uint8_t *subunit,
|
||||
uint8_t *operands, size_t operand_count,
|
||||
@ -698,12 +727,9 @@ int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
|
||||
session->tx_buf, len);
|
||||
}
|
||||
|
||||
static int parse_status(struct avrcp_header *pdu)
|
||||
static int status2errno(uint8_t status)
|
||||
{
|
||||
if (pdu->params_len < 1)
|
||||
return -EPROTO;
|
||||
|
||||
switch (pdu->params[0]) {
|
||||
switch (status) {
|
||||
case AVRCP_STATUS_INVALID_COMMAND:
|
||||
return -ENOSYS;
|
||||
case AVRCP_STATUS_INVALID_PARAM:
|
||||
@ -723,6 +749,22 @@ static int parse_status(struct avrcp_header *pdu)
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_status(struct avrcp_header *pdu)
|
||||
{
|
||||
if (pdu->params_len < 1)
|
||||
return -EPROTO;
|
||||
|
||||
return status2errno(pdu->params[0]);
|
||||
}
|
||||
|
||||
static int parse_browsing_status(struct avrcp_browsing_header *pdu)
|
||||
{
|
||||
if (pdu->params_len < 1)
|
||||
return -EPROTO;
|
||||
|
||||
return status2errno(pdu->params[0]);
|
||||
}
|
||||
|
||||
static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
|
||||
uint8_t pdu_id, uint8_t *params,
|
||||
size_t params_len, avctp_rsp_cb func,
|
||||
@ -751,6 +793,32 @@ static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
|
||||
session->tx_buf, len, func, user_data);
|
||||
}
|
||||
|
||||
static int avrcp_send_browsing_req(struct avrcp *session, uint8_t pdu_id,
|
||||
uint8_t *params, size_t params_len,
|
||||
avctp_browsing_rsp_cb func,
|
||||
void *user_data)
|
||||
{
|
||||
struct avrcp_browsing_header *pdu = (void *) session->tx_buf;
|
||||
size_t len = sizeof(*pdu);
|
||||
|
||||
memset(pdu, 0, len);
|
||||
|
||||
pdu->pdu_id = pdu_id;
|
||||
|
||||
if (params_len > 0) {
|
||||
len += params_len;
|
||||
|
||||
if (len > session->tx_mtu)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(pdu->params, params, params_len);
|
||||
pdu->params_len = htons(params_len);
|
||||
}
|
||||
|
||||
return avctp_send_browsing_req(session->conn, session->tx_buf, len,
|
||||
func, user_data);
|
||||
}
|
||||
|
||||
static gboolean get_capabilities_rsp(struct avctp *conn,
|
||||
uint8_t code, uint8_t subunit,
|
||||
uint8_t *operands, size_t operand_count,
|
||||
@ -1510,6 +1578,83 @@ int avrcp_set_addressed_player(struct avrcp *session, uint16_t player_id)
|
||||
session);
|
||||
}
|
||||
|
||||
static gboolean set_browsed_rsp(struct avctp *conn, uint8_t *operands,
|
||||
size_t operand_count, void *user_data)
|
||||
{
|
||||
struct avrcp *session = user_data;
|
||||
struct avrcp_player *player = session->player;
|
||||
struct avrcp_browsing_header *pdu;
|
||||
uint16_t counter = 0;
|
||||
uint32_t items = 0;
|
||||
uint8_t depth = 0, count;
|
||||
char **folders, *path = NULL;
|
||||
int err;
|
||||
size_t i;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!player || !player->cfm || !player->cfm->set_browsed)
|
||||
return FALSE;
|
||||
|
||||
pdu = parse_browsing_pdu(operands, operand_count);
|
||||
if (!pdu) {
|
||||
err = -EPROTO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = parse_browsing_status(pdu);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
if (pdu->params_len < 10) {
|
||||
err = -EPROTO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
counter = bt_get_be16(&pdu->params[1]);
|
||||
items = bt_get_be32(&pdu->params[3]);
|
||||
depth = pdu->params[9];
|
||||
|
||||
folders = g_new0(char *, depth + 2);
|
||||
folders[0] = g_strdup("/Filesystem");
|
||||
|
||||
for (i = 10, count = 1; count - 1 < depth && i < pdu->params_len;
|
||||
count++) {
|
||||
uint8_t len;
|
||||
|
||||
len = pdu->params[i++];
|
||||
|
||||
if (i + len > pdu->params_len || len == 0) {
|
||||
g_strfreev(folders);
|
||||
err = -EPROTO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
folders[count] = g_memdup(&pdu->params[i], len);
|
||||
i += len;
|
||||
}
|
||||
|
||||
path = g_build_pathv("/", folders);
|
||||
g_strfreev(folders);
|
||||
|
||||
done:
|
||||
player->cfm->set_browsed(session, err, counter, items, path,
|
||||
player->user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id)
|
||||
{
|
||||
uint8_t pdu[2];
|
||||
|
||||
put_be16(player_id, pdu);
|
||||
|
||||
return avrcp_send_browsing_req(session, AVRCP_SET_BROWSED_PLAYER,
|
||||
pdu, sizeof(pdu), set_browsed_rsp,
|
||||
session);
|
||||
}
|
||||
|
||||
int avrcp_get_capabilities_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *events)
|
||||
{
|
||||
|
@ -196,6 +196,9 @@ struct avrcp_control_cfm {
|
||||
uint8_t *params, void *user_data);
|
||||
void (*set_addressed) (struct avrcp *session, int err,
|
||||
void *user_data);
|
||||
void (*set_browsed) (struct avrcp *session, int err,
|
||||
uint16_t counter, uint32_t items,
|
||||
char *path, void *user_data);
|
||||
};
|
||||
|
||||
struct avrcp_passthrough_handler {
|
||||
@ -242,6 +245,7 @@ int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
|
||||
void *user_data);
|
||||
int avrcp_get_element_attributes(struct avrcp *session);
|
||||
int avrcp_set_addressed_player(struct avrcp *session, uint16_t player_id);
|
||||
int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id);
|
||||
|
||||
int avrcp_get_capabilities_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *events);
|
||||
|
Loading…
Reference in New Issue
Block a user