@@ -186,7 +186,7 @@ bool bt_audio_vcp_set_volume(struct btd_device *device, int8_t volume)
return FALSE;
}
-static void vcp_detached(struct bt_vcp *vcp, void *user_data)
+static void vcp_remote_client_detached(struct bt_vcp *vcp, void *user_data)
{
struct vcp_data *data;
@@ -201,7 +201,7 @@ static void vcp_detached(struct bt_vcp *vcp, void *user_data)
vcp_data_remove(data);
}
-static void vcp_attached(struct bt_vcp *vcp, void *user_data)
+static void vcp_remote_client_attached(struct bt_vcp *vcp, void *user_data)
{
struct vcp_data *data;
struct bt_att *att;
@@ -352,7 +352,8 @@ static int vcp_init(void)
if (err)
return err;
- vcp_id = bt_vcp_register(vcp_attached, vcp_detached, NULL);
+ vcp_id = bt_vcp_register(vcp_remote_client_attached,
+ vcp_remote_client_detached, NULL);
return 0;
}
@@ -379,7 +379,15 @@ static struct bt_aics *vcp_get_aics(struct bt_vcp *vcp)
return vcp->rdb->aics;
}
-static void vcp_detached(void *data, void *user_data)
+static void vcp_remote_client_attached(void *data, void *user_data)
+{
+ struct bt_vcp_cb *cb = data;
+ struct bt_vcp *vcp = user_data;
+
+ cb->attached(vcp, cb->user_data);
+}
+
+static void vcp_remote_client_detached(void *data, void *user_data)
{
struct bt_vcp_cb *cb = data;
struct bt_vcp *vcp = user_data;
@@ -389,7 +397,6 @@ static void vcp_detached(void *data, void *user_data)
void bt_vcp_detach(struct bt_vcp *vcp)
{
- struct bt_vcs *vcs;
if (!queue_remove(sessions, vcp))
return;
@@ -399,7 +406,7 @@ void bt_vcp_detach(struct bt_vcp *vcp)
}
if (vcp->rdb) {
- vcs = vcp_get_vcs(vcp);
+ struct bt_vcs *vcs = vcp_get_vcs(vcp);
vcs->service = NULL;
vcs->vs = NULL;
vcs->vs_ccc = NULL;
@@ -506,6 +513,7 @@ static void vcp_disconnected(int err, void *user_data)
DBG(vcp, "vcp %p disconnected err %d", vcp, err);
bt_vcp_detach(vcp);
+ queue_foreach(vcp_cbs, vcp_remote_client_detached, vcp);
}
static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db)
@@ -524,6 +532,8 @@ static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db)
vcp = bt_vcp_new(db, NULL);
vcp->att = att;
+ queue_foreach(vcp_cbs, vcp_remote_client_attached, vcp);
+
bt_att_register_disconnect(att, vcp_disconnected, vcp, NULL);
if (!sessions)
@@ -566,6 +576,10 @@ static uint8_t vcs_rel_vol_down(struct bt_vcs *vcs, struct bt_vcp *vcp,
vstate->vol_set = MAX((vstate->vol_set - VCP_STEP_SIZE), 0);
vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+ vcp->volume = vstate->vol_set;
+
+ if (vcp->volume_changed)
+ vcp->volume_changed(vcp, vcp->volume / 2);
gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
sizeof(struct vol_state),
@@ -605,6 +619,10 @@ static uint8_t vcs_rel_vol_up(struct bt_vcs *vcs, struct bt_vcp *vcp,
vstate->vol_set = MIN((vstate->vol_set + VCP_STEP_SIZE), 255);
vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+ vcp->volume = vstate->vol_set;
+
+ if (vcp->volume_changed)
+ vcp->volume_changed(vcp, vcp->volume / 2);
gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
sizeof(struct vol_state),
@@ -645,6 +663,10 @@ static uint8_t vcs_unmute_rel_vol_down(struct bt_vcs *vcs, struct bt_vcp *vcp,
vstate->mute = 0x00;
vstate->vol_set = MAX((vstate->vol_set - VCP_STEP_SIZE), 0);
vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+ vcp->volume = vstate->vol_set;
+
+ if (vcp->volume_changed)
+ vcp->volume_changed(vcp, vcp->volume / 2);
gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
sizeof(struct vol_state),
@@ -685,6 +707,10 @@ static uint8_t vcs_unmute_rel_vol_up(struct bt_vcs *vcs, struct bt_vcp *vcp,
vstate->mute = 0x00;
vstate->vol_set = MIN((vstate->vol_set + VCP_STEP_SIZE), 255);
vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+ vcp->volume = vstate->vol_set;
+
+ if (vcp->volume_changed)
+ vcp->volume_changed(vcp, vcp->volume / 2);
gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
sizeof(struct vol_state),
@@ -724,6 +750,10 @@ static uint8_t vcs_set_absolute_vol(struct bt_vcs *vcs, struct bt_vcp *vcp,
vstate->vol_set = req->vol_set;
vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+ vcp->volume = vstate->vol_set;
+
+ if (vcp->volume_changed)
+ vcp->volume_changed(vcp, vcp->volume / 2);
gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
sizeof(struct vol_state),
@@ -2023,34 +2053,59 @@ bool bt_vcp_set_volume(struct bt_vcp *vcp, int8_t volume)
{
struct bt_vcs_client_ab_vol req;
uint16_t value_handle;
- struct bt_vcs *vcs = vcp_get_vcs(vcp);
- if (!vcs) {
- DBG(vcp, "error: vcs not available");
- return false;
- }
+ vcp->volume = volume * 2;
- if (!vcs->vol_cp) {
- DBG(vcp, "error: vol_cp characteristics not available");
- return false;
- }
+ if (vcp->rdb) {
+ /* local gatt client */
+ struct bt_vcs *vcs = vcp_get_vcs(vcp);
- if (!gatt_db_attribute_get_char_data(vcs->vol_cp, NULL, &value_handle,
- NULL, NULL, NULL)) {
- DBG(vcp, "error: vol_cp characteristics not available");
- return false;
- }
+ if (!vcs) {
+ DBG(vcp, "error: vcs not available");
+ return false;
+ }
- vcp->volume = volume * 2;
- req.op = BT_VCS_SET_ABSOLUTE_VOL;
- req.vol_set = vcp->volume;
- req.change_counter = vcp->volume_counter;
-
- if (!bt_gatt_client_write_value(vcp->client, value_handle, (void *) &req,
- sizeof(struct bt_vcs_client_ab_vol), vcp_volume_cp_sent, vcp,
- NULL)) {
- DBG(vcp, "error writing volume");
- return false;
+ if (!vcs->vol_cp) {
+ DBG(vcp, "error: vol_cp characteristics not available");
+ return false;
+ }
+
+ if (!gatt_db_attribute_get_char_data(vcs->vol_cp, NULL,
+ &value_handle, NULL, NULL, NULL)) {
+ DBG(vcp, "error: vol_cp characteristics not available");
+ return false;
+ }
+
+ req.op = BT_VCS_SET_ABSOLUTE_VOL;
+ req.vol_set = vcp->volume;
+ req.change_counter = vcp->volume_counter;
+
+ if (!bt_gatt_client_write_value(vcp->client, value_handle,
+ (void *) &req, sizeof(struct bt_vcs_client_ab_vol),
+ vcp_volume_cp_sent, vcp, NULL)) {
+ DBG(vcp, "error writing volume");
+ return false;
+ }
+ } else {
+ // local gatt server
+ struct bt_vcp_db *vdb = vcp_get_vdb(vcp);
+ struct vol_state *vstate;
+
+ if (!vdb) {
+ DBG(vcp, "error: VDB not available");
+ return false;
+ }
+
+ vstate = vdb_get_vstate(vdb);
+ if (!vstate) {
+ DBG(vcp, "error: VSTATE not available");
+ return false;
+ }
+
+ vstate->vol_set = vcp->volume;
+ vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+ gatt_db_attribute_notify(vdb->vcs->vs, (void *) vstate,
+ sizeof(struct vol_state), bt_vcp_get_att(vcp));
}
return true;
}