audio/avrcp: Only allow absolute volume call/event on category-2 peers
authorMarijn Suijten <marijn.suijten@somainline.org>
Sat, 5 Oct 2024 21:43:07 +0000 (23:43 +0200)
committerWootak Jung <wootak.jung@samsung.com>
Thu, 20 Feb 2025 07:43:23 +0000 (16:43 +0900)
Restrict the use of SetAbsoluteVolume and EVENT_VOLUME_CHANGED to peers
with at least AVRCP version 1.4 and AVRCP_FEATURE_CATEGORY_2 on their
respective target or controller profiles.

For backwards-compatibility, add a (default-enabled) `VolumeCategory =
true` configuration option under `[AVRCP]` to allow optionally disabling
this new check.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
profiles/audio/avrcp.c

index d17608646cde3bac0d0b9b0ee55090b3c6339d4e..2db3ec3ff5605a3e1b94c1b1cda1beef742022c3 100644 (file)
@@ -1947,6 +1947,19 @@ err:
        return AVC_CTYPE_REJECTED;
 }
 
+/* SetAbsoluteVolume requires at least version 1.4 and a category-2 */
+static bool avrcp_volume_supported(struct avrcp_data *data)
+{
+       if (!data || data->version < 0x0104)
+               return false;
+
+       if (btd_opts.avrcp.volume_category &&
+                       !(data->features & AVRCP_FEATURE_CATEGORY_2))
+               return false;
+
+       return true;
+}
+
 static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
                                                struct avrcp_header *pdu,
                                                uint8_t transaction)
@@ -1957,6 +1970,11 @@ static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
        if (len != 1)
                goto err;
 
+       if (!avrcp_volume_supported(session->target)) {
+               error("SetAbsoluteVolume not supported");
+               goto err;
+       }
+
        volume = pdu->params[0] & 0x7F;
 
        media_transport_update_device_volume(session->dev, volume);
@@ -4174,6 +4192,11 @@ static void avrcp_volume_changed(struct avrcp *session,
        struct avrcp_player *player = target_get_player(session);
        int8_t volume;
 
+       if (!avrcp_volume_supported(session->controller)) {
+               error("EVENT_VOLUME_CHANGED not supported");
+               return;
+       }
+
        volume = pdu->params[1] & 0x7F;
 
        /* Always attempt to update the transport volume */
@@ -4527,7 +4550,7 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code,
                case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
                case AVRCP_EVENT_UIDS_CHANGED:
                case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
-                       /* These events above requires a player */
+                       /* These events above require a player */
                        if (!session->controller ||
                                                !session->controller->player)
                                break;
@@ -4757,11 +4780,13 @@ static void target_init(struct avrcp *session)
        if (adapter_avrcp_tg_ver < 0x0104)
                return;
 #endif
+       if (!avrcp_volume_supported(target))
+               session->supported_events |=
+                       (1 << AVRCP_EVENT_VOLUME_CHANGED);
 
        session->supported_events |=
                                (1 << AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED) |
-                               (1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED) |
-                               (1 << AVRCP_EVENT_VOLUME_CHANGED);
+                               (1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED);
 
        /* Only check capabilities if controller is not supported */
        if (session->controller == NULL)
@@ -5204,8 +5229,10 @@ int avrcp_set_volume(struct btd_device *dev, int8_t volume, bool notify)
                return -ENOTCONN;
 
        if (notify) {
-               if (!session->target)
+               if (!avrcp_volume_supported(session->target)) {
+                       error("EVENT_VOLUME_CHANGED not supported");
                        return -ENOTSUP;
+               }
                return avrcp_event(session, AVRCP_EVENT_VOLUME_CHANGED,
                                                                &volume);
        }
@@ -5218,8 +5245,8 @@ int avrcp_set_volume(struct btd_device *dev, int8_t volume, bool notify)
                if (!session->controller && !avrcp_event_registered(session,
                                                AVRCP_EVENT_VOLUME_CHANGED))
                        return -ENOTSUP;
-       } else if (!session->controller ||
-                               session->controller->version < 0x0104) {
+       } else if (!avrcp_volume_supported(session->controller)) {
+               error("SetAbsoluteVolume not supported");
                return -ENOTSUP;
        }