Skip to content

Fix: Implement Bidirectional Volume Sync and Prevent Feedback Loop#765

Merged
pschatzmann merged 1 commit intopschatzmann:mainfrom
GiacoBot:main
Jan 28, 2026
Merged

Fix: Implement Bidirectional Volume Sync and Prevent Feedback Loop#765
pschatzmann merged 1 commit intopschatzmann:mainfrom
GiacoBot:main

Conversation

@GiacoBot
Copy link
Contributor

This pull request addresses a feature gap where set_volume() in A2DP Source mode only updated the local volume state without synchronizing it to the connected sink device via AVRC. It also corrects a potential infinite feedback loop that could occur from the volume synchronization mechanism.

Problem

When the library is used in A2DP Source mode, there were two primary issues with volume control:

  1. One-Way Synchronization: Volume changes initiated on the ESP32 using the set_volume() method were not transmitted back to the sink device. This resulted in a desynchronization where the ESP32's internal volume state updated, but the actual audio output level on the sink device remained at its previous setting.

  2. Infinite Feedback Loop: The mechanism for receiving volume updates from the sink involves an AVRC notification (ESP_AVRC_RN_VOLUME_CHANGE) that, in turn, calls the set_volume() function. If set_volume() also sends an update to the sink, it creates a circular dependency:

    • set_volume() -> sends command to sink.
    • Sink changes volume -> sends notification to ESP32.
    • ESP32 receives notification -> calls set_volume() again.
      This would result in an infinite loop of commands and notifications, wasting resources and potentially causing instability.

Solution

To resolve this and provide a truly bidirectional and stable synchronized volume control, this PR implements the following changes:

  1. Feedback Loop Prevention: A guard condition has been added at the beginning of the set_volume function:

    if (is_volume_used && volume_value == volume) {
      return;
    }

    It breaks the infinite loop by immediately exiting the function if the requested volume is the same as the current volume. This ensures that when the ESP32 receives a volume-changed notification from the sink for a volume it just set, it doesn't trigger another redundant command.

  2. Integration of AVRC Command: Inside the set_volume method, a call to the ESP-IDF function esp_avrc_ct_send_set_absolute_volume_cmd() has been added. This function is responsible for sending the new volume level to the connected sink device via AVRC.

  3. Conditional Logic for Safety: The AVRC command is wrapped in a conditional check:

    #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
    if (isSource() && is_connected()){
        esp_avrc_ct_send_set_absolute_volume_cmd(0, volume_value);
    }
    #endif

    This ensures that the esp_avrc_ct_send_set_absolute_volume_cmd() is only executed when the instance is operating as an A2DP Source and is connected to a remote device

@pschatzmann pschatzmann merged commit 5a5766d into pschatzmann:main Jan 28, 2026
@pschatzmann
Copy link
Owner

I assume that you have tested this solution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants