Skip to content

AD2P as source in tasks #800

Description

@p-jbouras

Problem Description

I'm trying to play an mp3 file from sdcard using tasks to a bluetooth speaker and i was able to play the sound. After playing the mp3 i run the hibernate-method to close the resouces, but it get blocked on the "a2dp.end();" with the following output:

[I] AudioSourceSDFAT.h : 90 - void audio_tools::AudioSourceSDFAT<AudioFs, AudioFile>::end() [with AudioFs = SdFs; AudioFile = FsFile]
I (63820) gpio: GPIO[14]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (63821) gpio: GPIO[13]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
I (63829) gpio: GPIO[12]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 
[I] AudioEncoded.h : 185 - virtual void audio_tools::EncodedAudioOutput::end()
[I] MetaDataID3.h : 595 - virtual void audio_tools::MetaDataID3::end()
[I] AudioPlayer.h : 234 - reset codec
[I] CodecMP3Helix.h : 82 - virtual bool audio_tools::MP3DecoderHelix::begin()
I (63876) BT_AV: disconect a2d: 11:22:33:44:55:66
I (63876) BT_AV: ==> a2dp esp_a2d_source_disconnect from: 11:22:33:44:55:66
D (67403) BT_API: bt_app_work_dispatch event 0xff00, param len 0
D (67404) BT_API: app_task_handler, signal: 0x1, event: 0xff00
D (67404) BT_AV: app_work_dispatched
I (67408) BT_AV: bt_app_av_sm_hdlr state CONNECTED, evt 0xff00
D (67415) BT_AV: process_user_state_callbacks
D (67419) BT_AV: bt_app_av_state_connected_hdlr evt 65280
D (67425) BT_AV: bt_app_av_media_proc evt 65280
I (67429) BT_AV: a2dp media started
D (77403) BT_API: bt_app_work_dispatch event 0xff00, param len 0
D (77403) BT_API: app_task_handler, signal: 0x1, event: 0xff00
D (77404) BT_AV: app_work_dispatched
I (77408) BT_AV: bt_app_av_sm_hdlr state CONNECTED, evt 0xff00
D (77414) BT_AV: process_user_state_callbacks
D (77418) BT_AV: bt_app_av_state_connected_hdlr evt 65280
D (77424) BT_AV: bt_app_av_media_proc evt 65280
I (77429) BT_AV: a2dp media started

I need to free the resources because the esp32 goes after playing the mp3 to light sleep mode and on wakeup the playback should start again.

Any idea what the problem is? or how to reuse BluetoothA2DPSource after a light sleep?

Best regards

Device Description

ESP32-D0WDQ6-V3 (Dual-core, 240MHz) with 16MB Flash and 8MB PSRAM.

Sketch

The class implementing the ad2p logic looks like this:

#ifndef BLUETOOTH_H
#define BLUETOOTH_H

#include "device.h"

#define USE_HELIX
#define USE_A2DP
#define USE_SDFAT

#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/Communication/A2DPStream.h"
#include "AudioTools/Concurrency/RTOS.h"
#include "AudioTools/Disk/AudioSourceSDFAT.h"
#include <SPI.h>
#include <stdint.h>

#define SD_SPI_CS_PIN 4

extern BufferRTOS<uint8_t> buffer;

int32_t dataCallback(uint8_t *data, int bytes);

class BluetoothSpeaker : public Device {
  public:
    BluetoothSpeaker(const char *device, const char *file, uint32_t connectionTimeout = 15000, float defaultVolume = 0.5f, float volumeStep = 0.1f) : source("/", "mp3", SD_SPI_CS_PIN, 25, SHARED_SPI), out(buffer), player(source, out, decoder) {
        this->device = device;
        this->file = file;
        this->connectionTimeout = connectionTimeout;
        this->defaultVolume = defaultVolume;
        this->volumeStep = volumeStep;
    }

  private:
    AudioSourceSDFAT<SdFs, FsFile> source;
    MP3DecoderHelix decoder;
    QueueStream<uint8_t> out;
    AudioPlayer player;
    BluetoothA2DPSource a2dp;

    const char *device = nullptr;
    const char *file = nullptr;
    uint32_t connectionTimeout;
    float defaultVolume;
    float volumeStep;

    volatile bool stopRequested = false;
    TaskHandle_t taskHandle = nullptr;

    static bool parse_mac(const char *str, esp_bd_addr_t addr) {
        return sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) == 6;
    }

    /// converts a esp_bd_addr_t to a string - the string is 18 characters long!
    static const char *to_str(esp_bd_addr_t bda) {
        static char bda_str[18];
        sprintf(bda_str, "%02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
        return (const char *)bda_str;
    }

  protected:
    void static startPlayingTask(void *pvParameters) {
        auto *self = static_cast<BluetoothSpeaker *>(pvParameters);
        self->doStartPlaying();
    }

    void static stopPlayingTask(void *pvParameters) {
        auto *self = static_cast<BluetoothSpeaker *>(pvParameters);
        self->doStopPlaying();
    }

    void doStartPlaying() {
        buffer.resize(15 * 1024);
        out.begin(95);
        player.setDelayIfOutputFull(0);
        player.setVolume(getVolume());
        player.begin();
        a2dp.set_data_callback(dataCallback);

        bool connected = a2dp.reconnect();
        if (!connected) {
            if (taskHandle != nullptr) {
                vTaskDelete(taskHandle);
                taskHandle = nullptr;
            }
            return;
        }

        if (!player.setPath(this->file)) {
            if (taskHandle != nullptr) {
                vTaskDelete(taskHandle);
                taskHandle = nullptr;
            }
            return;
        }

        stopRequested = false;
        player.play();
        while (player.copy() > 0 && !stopRequested) {
            vTaskDelay(1);
        }
        player.stop();

        if (taskHandle != nullptr) {
            vTaskDelete(taskHandle);
            taskHandle = nullptr;
        }
    }
	
    void doStopPlaying() {
        stopRequested = true;
        vTaskDelete(NULL);
    }

    static bool ssidCallback(const char *ssid, esp_bd_addr_t address, int rssi) {
        Serial.printf("SSID: %s, MAC: %s\n", ssid, to_str(address));
        return false;
    }

  public:

    void init() {
        a2dp.set_ssid_callback(ssidCallback);
        a2dp.start();
    }

    bool connect() {
        AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);

        esp_bd_addr_t addr;
        parse_mac(mac.c_str(), "11:22:33:44:55:66");
        a2dp.set_auto_reconnect(addr);
        a2dp.set_auto_reconnect(true);

        while (!a2dp.is_connected()) {
            delay(1000);
        }

        return a2dp.is_connected();
    }

    bool isPlaying() {
        if (taskHandle == nullptr) {
            return false;
        }
        eTaskState state = eTaskGetState(taskHandle);
        return state != eDeleted && state != eInvalid;
    }

    void startPlaying() {
        xTaskCreatePinnedToCore(startPlayingTask, "startPlayingTask", 12000, this, 2, &taskHandle, 1);
    }

    void stopPlaying() {
        xTaskCreatePinnedToCore(stopPlayingTask, "stopPlayingTask", 12000, this, 2, NULL, 1);
    }

    void hibernate() {
        source.end();
        player.end();

        a2dp.set_auto_reconnect(false);
        a2dp.disconnect();
        a2dp.cancel_discovery();
        a2dp.end();
    }

};

#endif

Other Steps to Reproduce

No response

Provide your Version of the EP32 Arduino Core (or the IDF Version)

v5.2.2

I have checked existing issues, discussions and online documentation (incl. the Wiki)

  • I confirm I have checked existing issues, discussions and online documentation (incl. the Wiki)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions