espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.38k stars 7.22k forks source link

Blocking version of esp_a2d_sink_connect (IDFGH-9241) #10627

Open ftab opened 1 year ago

ftab commented 1 year ago

Is your feature request related to a problem?

esp_a2d_sink_connect returns immediately without a clear indication of when the a2dp connection attempt has finished (whether success or failure). There is a callback for ESP_A2D_CONNECTION_STATE_EVT but it isn't clear from the code that it could be used to build one's own blocking connection attempt (for example, there is not a "not found" conn_state). It would be wonderful to have a blocking version of this function so that the application's auto-connect logic can be more reliable and simpler

Describe the solution you'd like.

Ideal example:

void app_main() {
// ...
// Try to connect to a Bluetooth device
esp_err_t result;
do
{
    result = esp_a2d_sink_connect_blocking(a_bluetooth_addr, portMAX_DELAY);
} while (result != ESP_OK);
// ESP_OK = successfully connected. ESP_ERR_TIMEOUT or ESP_ERR_NOT_FOUND if device wasn't found. etc.
// ...
}

Describe alternatives you've considered.

For example (some long parts omitted in comments for brevity):

// Keep track of connection state to Bluetooth device
volatile int connected = 0;

void app_main() {
// ...
// Try to connect to a Bluetooth device
while (connected == 0)
{
    esp_a2d_sink_connect(a_bluetooth_addr);
    // 5 second delay or wait for task notification
}
// ...
}

static void bt_a2d_sink_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
{
// ...
    switch (event) {
        case ESP_A2D_CONNECTION_STATE_EVT:
            // ... depending on the conn_state, set connected = 0 or 1
            // ... notify task
     }
// ...
}

I've considered trying this (e.g. to see if I get a DISCONNECTED event when it fails), but I feel with the lack of distinction between a connected device disconnecting, and an outgoing connection attempt failing, the callback logic could get kind of messy. Especially if more than one device is connected.

Additional context.

No response

ftab commented 7 months ago

This would still be helpful

boblane1 commented 7 months ago

Hi @ftab,

Thanks for your suggestion. The ESP32 Bluetooth stack is designed to be non-blocking, so you can implement your own blocking mechanism by using events in callbacks. You can use esp_bt_gap_start_discovery to see if the peer device is in the range. However, it does appear to be more complex than your feature request. Maybe we can provide a simple discovery API like esp_a2d_sink_discovery to see if the a2dp source is in the range.

ftab commented 7 months ago

Thanks for the reply @boblane1

If I understand correctly, esp_bt_gap_start_discovery only works when the device is in pairing mode (e.g. phone is at Bluetooth settings screen)

I wanted to make my own blocking version of esp_a2d_sink_connect but a failed attempt to connect does not bubble up to the layer that esp_a2d_sink_connect works at (additionally: it is sometimes hung up for a full minute due to #13154 ). I only get "disconnecting", "disconnected", "connecting", "connected" -- there is no "failed to connect" status, and I'm not entirely sure how to get to the lower layer to get, for example, the result of the "hcif conn complete" event to try to guess myself. So my current method is just blindly attempt every 5 seconds until I receive the "connected" callback.

boblane1 commented 7 months ago

If I understand correctly, esp_bt_gap_start_discovery only works when the device is in pairing mode (e.g. phone is at Bluetooth settings screen)

Yes, you are right.

How about not issuing the second connection process before the first connection result comes("disconnected", "connected") to implement blocking connection? In fact, the stack will ignore the redundant connection requests when it is already in connecting state.