From a969f7000f133c4c04df17cebbcfb4f789a696bb Mon Sep 17 00:00:00 2001 From: Bharat Panda Date: Mon, 9 Nov 2015 17:43:30 +0530 Subject: audio/avrcp: Enable volume change notification Changes taken to enable volume change notification in TG role. When acting as a TG volume changes should be notified using RegisterNotification not SetAbsoluteVolume as the later is a CT operation. git repo link: http://git.kernel.org/cgit/bluetooth/bluez.git/commit/?id=ed347b646c57d1e75269a7dc69b6e2ab1a1b41b5 Change-Id: I317bfaf70b7088a3d9c531bb5c7a6536414fc09f --- profiles/audio/avrcp.c | 61 ++++++++++++++++++++++++++++++++++++++++++---- profiles/audio/avrcp.h | 2 +- profiles/audio/transport.c | 5 ++-- 3 files changed, 60 insertions(+), 8 deletions(-) (limited to 'profiles') diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c index 991c56cb..a276ecf0 100644 --- a/profiles/audio/avrcp.c +++ b/profiles/audio/avrcp.c @@ -3960,7 +3960,53 @@ static gboolean avrcp_handle_set_volume(struct avctp *conn, return FALSE; } -int avrcp_set_volume(struct btd_device *dev, uint8_t volume) +static int avrcp_event(struct avrcp *session, uint8_t id, const void *data) +{ + uint8_t buf[AVRCP_HEADER_LENGTH + 2]; + struct avrcp_header *pdu = (void *) buf; + uint8_t code; + uint16_t size; + int err; + + /* Verify that the event is registered */ + if (!(session->registered_events & (1 << id))) + return -ENOENT; + + memset(buf, 0, sizeof(buf)); + + set_company_id(pdu->company_id, IEEEID_BTSIG); + pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION; + code = AVC_CTYPE_CHANGED; + pdu->params[0] = id; + + DBG("id=%u", id); + + switch (id) { + case AVRCP_EVENT_VOLUME_CHANGED: + size = 2; + memcpy(&pdu->params[1], data, sizeof(uint8_t)); + break; + default: + error("Unknown event %u", id); + return -EINVAL; + } + + pdu->params_len = htons(size); + + err = avctp_send_vendordep(session->conn, + session->transaction_events[id], + code, AVC_SUBUNIT_PANEL, + buf, size + AVRCP_HEADER_LENGTH); + if (err < 0) + return err; + + /* Unregister event as per AVRCP 1.3 spec, section 5.4.2 */ + session->registered_events ^= 1 << id; + + return err; +} + +int avrcp_set_volume(struct btd_device *dev, uint8_t volume, bool notify) { struct avrcp_server *server; struct avrcp *session; @@ -3972,18 +4018,23 @@ int avrcp_set_volume(struct btd_device *dev, uint8_t volume) return -EINVAL; session = find_session(server->sessions, dev); - if (session == NULL || session->target == NULL) + if (session == NULL) return -ENOTCONN; - if (session->target->version < 0x0104) + if (notify) { + if (!session->target) + return -ENOTSUP; + return avrcp_event(session, AVRCP_EVENT_VOLUME_CHANGED, + &volume); + } + + if (!session->controller || session->controller->version < 0x0104) return -ENOTSUP; memset(buf, 0, sizeof(buf)); set_company_id(pdu->company_id, IEEEID_BTSIG); - DBG("volume=%u", volume); - pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME; pdu->params[0] = volume; pdu->params_len = htons(1); diff --git a/profiles/audio/avrcp.h b/profiles/audio/avrcp.h index 28074db5..f60e0361 100644 --- a/profiles/audio/avrcp.h +++ b/profiles/audio/avrcp.h @@ -104,7 +104,7 @@ struct avrcp_player_cb { bool (*previous) (void *user_data); }; -int avrcp_set_volume(struct btd_device *dev, uint8_t volume); +int avrcp_set_volume(struct btd_device *dev, uint8_t volume, bool notify); struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter, struct avrcp_player_cb *cb, diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c index 112ec176..f5c829f3 100644 --- a/profiles/audio/transport.c +++ b/profiles/audio/transport.c @@ -671,7 +671,8 @@ static void set_volume(const GDBusPropertyTable *property, } if (a2dp->volume != volume) - avrcp_set_volume(transport->device, volume); + avrcp_set_volume(transport->device, volume, + transport->source_watch ? true : false); a2dp->volume = volume; @@ -817,7 +818,7 @@ static int media_transport_init_sink(struct media_transport *transport) transport->destroy = destroy_a2dp; a2dp->volume = 127; - avrcp_set_volume(transport->device, a2dp->volume); + avrcp_set_volume(transport->device, a2dp->volume, true); transport->source_watch = source_add_state_cb(service, source_state_changed, transport); -- cgit v1.2.3