diff --git a/audio/avrcp.c b/audio/avrcp.c
index 2f96f27..131490f 100644
--- a/audio/avrcp.c
+++ b/audio/avrcp.c
#define AVRCP_REGISTER_NOTIFICATION 0x31
#define AVRCP_REQUEST_CONTINUING 0x40
#define AVRCP_ABORT_CONTINUING 0x41
+#define AVRCP_SET_ABSOLUTE_VOLUME 0x50
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
#define CAP_COMPANY_ID 0x02
player_destroy(player);
}
+
+static gboolean avrcp_handle_set_volume(struct avctp *session,
+ uint8_t code, uint8_t subunit,
+ uint8_t *operands, size_t operand_count,
+ void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct avrcp_header *pdu = (void *) operands;
+ uint8_t volume;
+
+ if (code == AVC_CTYPE_REJECTED || code == AVC_CTYPE_NOT_IMPLEMENTED)
+ return FALSE;
+
+ volume = pdu->params[0] & 0x7F;
+
+ player->cb->set_volume(volume, player->dev, player->user_data);
+
+ return FALSE;
+}
+
+int avrcp_set_volume(struct audio_device *dev, uint8_t volume)
+{
+ struct avrcp_server *server;
+ struct avrcp_player *player;
+ uint8_t buf[AVRCP_HEADER_LENGTH + 1];
+ struct avrcp_header *pdu = (void *) buf;
+
+ server = find_server(servers, &dev->src);
+ if (server == NULL)
+ return -EINVAL;
+
+ player = server->active_player;
+ if (player == NULL)
+ return -ENOTSUP;
+
+ if (player->session == NULL)
+ return -ENOTCONN;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+ pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME;
+ pdu->params[0] = volume;
+ pdu->params_len = htons(1);
+
+ DBG("volume=%u", volume);
+
+ return avctp_send_vendordep_req(player->session, AVC_CTYPE_CONTROL,
+ AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+ avrcp_handle_set_volume, player);
+}
diff --git a/audio/avrcp.h b/audio/avrcp.h
index b520ef6..bf11a6c 100644
--- a/audio/avrcp.h
+++ b/audio/avrcp.h
gboolean avrcp_connect(struct audio_device *dev);
void avrcp_disconnect(struct audio_device *dev);
+int avrcp_set_volume(struct audio_device *dev, uint8_t volume);
struct avrcp_player *avrcp_register_player(const bdaddr_t *src,
struct avrcp_player_cb *cb,
int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data);
+
size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands);
diff --git a/audio/transport.c b/audio/transport.c
index ac9d358..bf86390 100644
--- a/audio/transport.c
+++ b/audio/transport.c
#include "a2dp.h"
#include "headset.h"
#include "gateway.h"
+#include "avrcp.h"
#ifndef DBUS_TYPE_UNIX_FD
#define DBUS_TYPE_UNIX_FD -1
/* FIXME: send new delay */
return 0;
+ } else if (g_strcmp0(property, "Volume") == 0) {
+ uint16_t volume;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &volume);
+
+ if (volume > 127)
+ return -EINVAL;
+
+ if (transport->volume == volume)
+ return 0;
+
+ return avrcp_set_volume(transport->device, volume);
}
return -EINVAL;