diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
index e65594d..02bee2b 100644
--- a/profiles/audio/avctp.c
+++ b/profiles/audio/avctp.c
void *user_data;
};
+struct avctp_browsing_req {
+ struct avctp_pending_req *p;
+ uint8_t *operands;
+ uint16_t operand_count;
+ avctp_browsing_rsp_cb func;
+ void *user_data;
+};
+
typedef int (*avctp_process_cb) (void *data);
struct avctp_pending_req {
return err;
}
+static int avctp_browsing_send(struct avctp_channel *browsing,
+ uint8_t transaction, uint8_t cr,
+ uint8_t *operands, size_t operand_count)
+{
+ struct avctp_header *avctp;
+ struct msghdr msg;
+ struct iovec iov[2];
+ int sk, err = 0;
+
+ iov[0].iov_base = browsing->buffer;
+ iov[0].iov_len = sizeof(*avctp);
+ iov[1].iov_base = operands;
+ iov[1].iov_len = operand_count;
+
+ if (browsing->omtu < (iov[0].iov_len + iov[1].iov_len))
+ return -EOVERFLOW;
+
+ sk = g_io_channel_unix_get_fd(browsing->io);
+
+ memset(browsing->buffer, 0, iov[0].iov_len);
+
+ avctp = (void *) browsing->buffer;
+
+ avctp->transaction = transaction;
+ avctp->packet_type = AVCTP_PACKET_SINGLE;
+ avctp->cr = cr;
+ avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ if (sendmsg(sk, &msg, 0) < 0)
+ err = -errno;
+
+ return err;
+}
+
static void control_req_destroy(void *data)
{
struct avctp_control_req *req = data;
g_free(req);
}
+static void browsing_req_destroy(void *data)
+{
+ struct avctp_browsing_req *req = data;
+
+ g_free(req->operands);
+ g_free(req);
+}
+
static gboolean req_timeout(gpointer user_data)
{
struct avctp_channel *chan = user_data;
req->operands, req->operand_count);
}
+static int process_browsing(void *data)
+{
+ struct avctp_browsing_req *req = data;
+ struct avctp_pending_req *p = req->p;
+
+ return avctp_browsing_send(p->chan, p->transaction, AVCTP_COMMAND,
+ req->operands, req->operand_count);
+}
+
static gboolean process_queue(void *user_data)
{
struct avctp_channel *chan = user_data;
}
}
+static void browsing_response(struct avctp_channel *browsing,
+ struct avctp_header *avctp,
+ uint8_t *operands,
+ size_t operand_count)
+{
+ struct avctp_pending_req *p = browsing->p;
+ struct avctp_browsing_req *req;
+ GSList *l;
+
+ if (p && p->transaction == avctp->transaction) {
+ browsing->processed = g_slist_prepend(browsing->processed, p);
+
+ if (p->timeout > 0) {
+ g_source_remove(p->timeout);
+ p->timeout = 0;
+ }
+
+ browsing->p = NULL;
+
+ if (browsing->process_id == 0)
+ browsing->process_id = g_idle_add(process_queue,
+ browsing);
+ }
+
+ for (l = browsing->processed; l; l = l->next) {
+ p = l->data;
+ req = p->data;
+
+ if (p->transaction != avctp->transaction)
+ continue;
+
+ if (req->func && req->func(browsing->session,
+ operands, operand_count,
+ req->user_data))
+ return;
+
+ browsing->processed = g_slist_remove(browsing->processed, p);
+
+ return;
+ }
+}
+
static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
ret -= AVCTP_HEADER_LENGTH;
operand_count = ret;
+ if (avctp->cr == AVCTP_RESPONSE) {
+ browsing_response(browsing, avctp, operands, operand_count);
+ return TRUE;
+ }
+
packet_size = AVCTP_HEADER_LENGTH;
avctp->cr = AVCTP_RESPONSE;
return 0;
}
+int avctp_send_browsing_req(struct avctp *session,
+ uint8_t *operands, size_t operand_count,
+ avctp_browsing_rsp_cb func, void *user_data)
+{
+ struct avctp_channel *browsing = session->browsing;
+ struct avctp_pending_req *p;
+ struct avctp_browsing_req *req;
+
+ if (browsing == NULL)
+ return -ENOTCONN;
+
+ req = g_new0(struct avctp_browsing_req, 1);
+ req->func = func;
+ req->operands = g_memdup(operands, operand_count);
+ req->operand_count = operand_count;
+ req->user_data = user_data;
+
+ p = pending_create(browsing, process_browsing, req,
+ browsing_req_destroy);
+
+ req->p = p;
+
+ g_queue_push_tail(browsing->queue, p);
+
+ if (browsing->process_id == 0)
+ browsing->process_id = g_idle_add(process_queue, browsing);
+
+ return 0;
+}
+
static char *op2str(uint8_t op)
{
switch (op & 0x7f) {
diff --git a/profiles/audio/avctp.h b/profiles/audio/avctp.h
index c25a3b3..b9107bd 100644
--- a/profiles/audio/avctp.h
+++ b/profiles/audio/avctp.h
typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code,
uint8_t subunit, uint8_t *operands,
size_t operand_count, void *user_data);
+typedef gboolean (*avctp_browsing_rsp_cb) (struct avctp *session,
+ uint8_t *operands, size_t operand_count,
+ void *user_data);
typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session,
uint8_t transaction,
uint8_t *operands, size_t operand_count,
uint8_t subunit, uint8_t *operands,
size_t operand_count,
avctp_rsp_cb func, void *user_data);
+int avctp_send_browsing_req(struct avctp *session,
+ uint8_t *operands, size_t operand_count,
+ avctp_browsing_rsp_cb func, void *user_data);