Как исправить конфликт <driver_i2s.h> и <Audio.h>

Добрый вечер !
Я хочу создать проект, который сможет записывать голос, сохранять его в wav-файл и отправлять на сервер для перевода (речь в текст), и я пытаюсь использовать MAX98357A в качестве динамика из ответов ChatGPT. Для этого я пытаюсь использовать две библиотеки:
<driver/i2s_h> для микрофона и <Audio.h> (GitHub - schreibfaul1/ESP32-audioI2S: Play mp3 files from SD via I2S)
для динамика (эта библиотека автоматически делает запрос в Google TTS).
И когда я проверяю свой код в Arduino IDE, я не получаю никаких ошибок, но после сборки и загрузки этого кода я получаю следующее:
КОНФЛИКТ! Новый драйвер i2s не может работать вместе с устаревшим драйвером i2s.

Как это исправить?

Код:


#include <EEPROM.h>
#include <DNSServer.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <WiFiUdp.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <FS.h>
#include <LittleFS.h>
#include <ArduinoJson.h>
#include <TimeLib.h>
#include
#include
#include
#include “Audio.h”
#include “esp_heap_caps.h”
#include “driver/temperature_sensor.h”
#include <driver/i2s.h>

// ===================================================================
// ==========================AUDIO OUTPUT============================
// ===================================================================

#define MAX98357A_I2S_DOUT 37
#define MAX98357A_I2S_BCLK 36
#define MAX98357A_I2S_LRC 35

Audio audio;

const size_t audioBufferSize = 64 * 1024;
uint8_t* audioBufferPSRAM = nullptr;

// ===================================================================
// ==========================MIC======================================
// ===================================================================

#define I2S_WS 15
#define I2S_SD 13
#define I2S_SCK 2
#define I2S_PORT I2S_NUM_0
#define I2S_SAMPLE_RATE (16000)
#define I2S_SAMPLE_BITS (16)
#define I2S_READ_LEN (16 * 1024)
#define RECORD_TIME (5)
#define I2S_CHANNEL_NUM (1)
#define FLASH_RECORD_SIZE (I2S_CHANNEL_NUM * I2S_SAMPLE_RATE * I2S_SAMPLE_BITS / 8 * RECORD_TIME)

File file;
const char filename = “/audio.wav”;
const int headerSize = 44;
const char* transcription = “”;

==========================================================

void initFile() {
LittleFS.remove(filename);
file = LittleFS.open(filename, “w”);
if (!file) {
Serial.println(“File is not available!”);
return;
}

uint8_t header[headerSize];
wavHeader(header, FLASH_RECORD_SIZE);
file.write(header, headerSize);
scanFiles();
}

void i2sInit() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = I2S_SAMPLE_RATE,
.bits_per_sample = i2s_bits_per_sample_t(I2S_SAMPLE_BITS),
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 1024,
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
};

i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);

const i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = -1,
.data_in_num = I2S_SD
};

i2s_set_pin(I2S_PORT, &pin_config);
}

void i2s_adc_data_scale(uint8_t *d_buff, uint8_t *s_buff, uint32_t len) {
uint32_t j = 0;
uint32_t dac_value = 0;
for (int i = 0; i < len; i += 2) {
dac_value = ((((uint16_t)(s_buff[i + 1] & 0xf) << 8) | ((s_buff[i + 0]))));
d_buff[j++] = 0;
d_buff[j++] = dac_value * 256 / 2048;
}
}

void i2s_adc(void *arg) {
int i2s_read_len = I2S_READ_LEN;
int flash_wr_size = 0;
size_t bytes_read;

char *i2s_read_buff = (char *)calloc(i2s_read_len, sizeof(char));
uint8_t *flash_write_buff = (uint8_t *)calloc(i2s_read_len, sizeof(char));

i2s_read(I2S_PORT, (void *)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
i2s_read(I2S_PORT, (void *)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);

Serial.println(" *** Recording Start *** ");
initFile();
while (flash_wr_size < FLASH_RECORD_SIZE) {
i2s_read(I2S_PORT, (void *)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
i2s_adc_data_scale(flash_write_buff, (uint8_t *)i2s_read_buff, i2s_read_len);
file.write((const uint8_t *)flash_write_buff, i2s_read_len);
flash_wr_size += i2s_read_len;
ets_printf(“Sound recording %u%%\n”, flash_wr_size * 100 / FLASH_RECORD_SIZE);
ets_printf(“Never Used Stack Size: %u\n”, uxTaskGetStackHighWaterMark(NULL));
}
file.close();

free(i2s_read_buff);
i2s_read_buff = NULL;
free(flash_write_buff);
flash_write_buff = NULL;

scanFiles();

if (WiFi.status() == WL_CONNECTED) {
uploadaudioFile();
}

vTaskDelete(NULL);
}

void wavHeader(uint8_t *header, int wavSize) {
header[0] = ‘R’;
header[1] = ‘I’;
header[2] = ‘F’;
header[3] = ‘F’;
unsigned int fileSize = wavSize + headerSize - 8;
header[4] = (uint8_t)(fileSize & 0xFF);
header[5] = (uint8_t)((fileSize >> 8) & 0xFF);
header[6] = (uint8_t)((fileSize >> 16) & 0xFF);
header[7] = (uint8_t)((fileSize >> 24) & 0xFF);
header[8] = ‘W’;
header[9] = ‘A’;
header[10] = ‘V’;
header[11] = ‘E’;
header[12] = ‘f’;
header[13] = ‘m’;
header[14] = ‘t’;
header[15] = ’ ';
header[16] = 0x10;
header[17] = 0x00;
header[18] = 0x00;
header[19] = 0x00;
header[20] = 0x01;
header[21] = 0x00;
header[22] = 0x01;
header[23] = 0x00;
header[24] = 0x80;
header[25] = 0x3E;
header[26] = 0x00;
header[27] = 0x00;
header[28] = 0x00;
header[29] = 0x7D;
header[30] = 0x01;
header[31] = 0x00;
header[32] = 0x02;
header[33] = 0x00;
header[34] = 0x10;
header[35] = 0x00;
header[36] = ‘d’;
header[37] = ‘a’;
header[38] = ‘t’;
header[39] = ‘a’;
header[40] = (uint8_t)(wavSize & 0xFF);
header[41] = (uint8_t)((wavSize >> 8) & 0xFF);
header[42] = (uint8_t)((wavSize >> 16) & 0xFF);
header[43] = (uint8_t)((wavSize >> 24) & 0xFF);
}

void uploadaudioFile() {
Serial.println(“Uploading audio file…”);

WiFiClient client;
HTTPClient http;

http.begin(client, stt_url);
http.addHeader(“X-API-KEY”, encrypted_api_key);
http.addHeader(“Content-Type”, “audio/wav”);

File uploadaudioFile = LittleFS.open(filename, “r”);
if (!uploadaudioFile) {
Serial.println(“Failed to open file for reading”);
return;
}

int httpResponseCode = http.sendRequest(“POST”, &uploadaudioFile, uploadaudioFile.size());
if (httpResponseCode > 0) {
Serial.printf(“File uploaded successfully, response code: %d\n”, httpResponseCode);
String response = http.getString();
Serial.println("Response from server: ");
Serial.println(response);

DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, response);

if (!error) {
  const char* transcription = doc["transcription"];
  Serial.print("Transcription: ");
  Serial.println(transcription);
} else {
  Serial.println("Failed to parse JSON response");
}
} else {
Serial.printf(“Error uploading file: %s\n”, http.errorToString(httpResponseCode).c_str());
}

uploadaudioFile.close();
http.end();
}

void waitForSpeechEnd() {
while (audio.isRunning()) {
audio.loop();
yield();
}
}

void setup() {
Serial.begin(115200);

if (psramFound()) {
Serial.println(“PSRAM found and ready to use”);
} else {
Serial.println(“No PSRAM found”);
}

audioBufferPSRAM = (uint8_t*)heap_caps_malloc(audioBufferSize, MALLOC_CAP_SPIRAM);
if (audioBufferPSRAM == nullptr) {
Serial.println(“Error: Failed to allocate audio buffer in PSRAM”);
} else {
Serial.println(“Audio buffer allocated in PSRAM”);
}

i2sInit();
xTaskCreate(i2s_adc, “i2s_adc”, 4096, NULL, 2, NULL);
delay(500);
audio.setPinout(MAX98357A_I2S_BCLK, MAX98357A_I2S_LRC, MAX98357A_I2S_DOUT);
audio.setVolume(100);
audio.connecttospeech(“TEST TEST”, “en”);
waitForSpeechEnd();

}

Это заявка на бан за дублирование тем?

@ЕвгенийП

Не знал, что за это банят, удалите эту тему

или предыдущую, так как там скетч выложен неправильно!
А глядя на скетч на ум приходят строки “смешались в кучу кони, люди”
Видимо чтобы не конфликтовали надо одну и туже библиотеку использовать

Да, вот корректный скетч

Я пытался использовать новый драйвер <driver/i2s_std.h>, но не совсем понял, как им пользоваться

ты себе льстишь, драть код на просторах вселенной надо осмысленно, то, что ты выложил даже не скомпилируется, для начала детские ошибки исправь

@remosYa

Если вы не можете помочь, а лишь обвинять умеете, то я понимаю, зачем вы сидите в теме этого вопроса.

Код:

#include <driver/i2s.h>
#include <FS.h>
#include <LittleFS.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "Audio.h"

SET_LOOP_TASK_STACK_SIZE(16 * 1024);

#define MAX98357A_I2S_DOUT  37
#define MAX98357A_I2S_BCLK 36
#define MAX98357A_I2S_LRC  35

Audio audio;

const size_t audioBufferSize = 64 * 1024;
uint8_t* audioBufferPSRAM = nullptr;

const char *ssid = "SSID";
const char *password = "PASS";
#define SERVER_URL "URL"
const char* encrypted_api_key = "API-KEY";
#define I2S_WS 15
#define I2S_SD 13
#define I2S_SCK 2
#define I2S_PORT I2S_NUM_0
#define I2S_SAMPLE_RATE (16000)
#define I2S_SAMPLE_BITS (16)
#define I2S_READ_LEN (16 * 1024)
#define I2S_CHANNEL_NUM (1)
#define SILENCE_THRESHOLD 100
#define SILENCE_DURATION 500
#define FLASH_RECORD_SIZE_MAX (I2S_CHANNEL_NUM * I2S_SAMPLE_RATE * I2S_SAMPLE_BITS / 8 * 60)


File file;
const char filename[] = "/audio.wav";
const int headerSize = 44;
bool isWIFIConnected;

void setup() {
  Serial.begin(115200);
  LittleFS.begin();
  i2sInit();
  xTaskCreate(wifiConnect, "wifi_Connect", 4096, NULL, 1, NULL);
  xTaskCreate(i2s_adc, "i2s_adc", 4096, NULL, 2, NULL);
  delay(500);

  if (psramFound()) {
    Serial.println("PSRAM found and ready to use");
  } else {
    Serial.println("No PSRAM found");
  }

  audioBufferPSRAM = (uint8_t*)heap_caps_malloc(audioBufferSize, MALLOC_CAP_SPIRAM);
  if (audioBufferPSRAM == nullptr) {
    Serial.println("Error: Failed to allocate audio buffer in PSRAM");
  } else {
    Serial.println("Audio buffer allocated in PSRAM");
  }

  audio.connecttospeech("TEST TEST", "en");
  waitForSpeechEnd();

}

void loop() {
}

void waitForSpeechEnd() {
    while (audio.isRunning()) {
        audio.loop();
        yield();
    }
}

void initFile() {
    LittleFS.remove(filename);
    file = LittleFS.open(filename, "w");
    if (!file) {
        Serial.println("File is not available!");
        return;
    }

    uint8_t header[headerSize];
    wavHeader(header, FLASH_RECORD_SIZE_MAX);
    file.write(header, headerSize);
    listFiles();
}

void handleSilence(unsigned long& silenceStart, bool& isSilent, char *i2s_read_buff, uint8_t *flash_write_buff, size_t& flash_wr_size) {
    Serial.println(" *** Detected Silence, waiting for speech to resume *** ");
    unsigned long waitStart = millis();
    
    while (millis() - waitStart < 3000) {
        size_t uint8_ts_read;
        i2s_read(I2S_PORT, (void *)i2s_read_buff, I2S_READ_LEN, &uint8_ts_read, portMAX_DELAY);
        
        int16_t *samples = (int16_t *)i2s_read_buff;
        bool soundDetected = false;
        for (size_t i = 0; i < uint8_ts_read / 2; i++) {
            if (abs(samples[i]) >= SILENCE_THRESHOLD) {
                soundDetected = true;
                break;
            }
        }

        if (soundDetected) {
            Serial.println(" *** Sound detected, continuing recording *** ");
            return;
        }
        delay(50);
    }
    Serial.println(" *** Ending recording after silence timeout *** ");
}

void i2sInit() {
    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
        .sample_rate = I2S_SAMPLE_RATE,
        .bits_per_sample = i2s_bits_per_sample_t(I2S_SAMPLE_BITS),
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 8,
        .dma_buf_len = 1024,
        .use_apll = false,
        .tx_desc_auto_clear = true,
        .fixed_mclk = 0
    };

    i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);

    const i2s_pin_config_t pin_config = {
        .bck_io_num = I2S_SCK,
        .ws_io_num = I2S_WS,
        .data_out_num = -1,
        .data_in_num = I2S_SD
    };

    i2s_set_pin(I2S_PORT, &pin_config);
}

void i2s_adc_data_scale(uint8_t *d_buff, uint8_t *s_buff, uint32_t len) {
    uint32_t j = 0;
    uint32_t dac_value = 0;
    for (int i = 0; i < len; i += 2) {
        dac_value = ((((uint16_t)(s_buff[i + 1] & 0xf) << 8) | ((s_buff[i + 0]))));
        d_buff[j++] = 0;
        d_buff[j++] = dac_value * 256 / 2048;
    }
}

void i2s_adc(void *arg) {
    size_t flash_wr_size = 0;
    size_t uint8_ts_read;

    char *i2s_read_buff = (char *)calloc(I2S_READ_LEN, sizeof(char));
    uint8_t *flash_write_buff = (uint8_t *)calloc(I2S_READ_LEN, sizeof(char));

    Serial.println(" *** Recording Start *** ");
    initFile();

    unsigned long silenceStart = 0;
    bool isSilent = false;

    while (flash_wr_size < FLASH_RECORD_SIZE_MAX) {
        i2s_read(I2S_PORT, (void *)i2s_read_buff, I2S_READ_LEN, &uint8_ts_read, portMAX_DELAY);
        i2s_adc_data_scale(flash_write_buff, (uint8_t *)i2s_read_buff, I2S_READ_LEN);
        file.write((const uint8_t *)flash_write_buff, I2S_READ_LEN);
        flash_wr_size += I2S_READ_LEN;

        int16_t *samples = (int16_t *)i2s_read_buff;
        for (size_t i = 0; i < uint8_ts_read / 2; i++) {
            if (abs(samples[i]) < SILENCE_THRESHOLD) {
                if (!isSilent) {
                    silenceStart = millis();
                    isSilent = true;
                }
            } else {
                isSilent = false;
                silenceStart = 0;
            }
        }

        if (isSilent && (millis() - silenceStart > SILENCE_DURATION)) {
            handleSilence(silenceStart, isSilent, i2s_read_buff, flash_write_buff, flash_wr_size);
            break;
        }

        ets_printf("Sound recording %u%%\n", flash_wr_size * 100 / FLASH_RECORD_SIZE_MAX);
        ets_printf("Never Used Stack Size: %u\n", uxTaskGetStackHighWaterMark(NULL));
    }

    file.close();
    free(i2s_read_buff);
    free(flash_write_buff);

    listFiles();

    if (isWIFIConnected) {
        uploadFile();
    }

    vTaskDelete(NULL);
}

void wavHeader(uint8_t *header, int wavSize) {
    header[0] = 'R';
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    unsigned int fileSize = wavSize + headerSize - 8;
    header[4] = (uint8_t)(fileSize & 0xFF);
    header[5] = (uint8_t)((fileSize >> 8) & 0xFF);
    header[6] = (uint8_t)((fileSize >> 16) & 0xFF);
    header[7] = (uint8_t)((fileSize >> 24) & 0xFF);
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    header[12] = 'f';
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 0x10;
    header[17] = 0x00;
    header[18] = 0x00;
    header[19] = 0x00;
    header[20] = 0x01;
    header[21] = 0x00;
    header[22] = 0x01;
    header[23] = 0x00;
    header[24] = 0x80;
    header[25] = 0x3E;
    header[26] = 0x00;
    header[27] = 0x00;
    header[28] = 0x00;
    header[29] = 0x7D;
    header[30] = 0x01;
    header[31] = 0x00;
    header[32] = 0x02;
    header[33] = 0x00;
    header[34] = 0x10;
    header[35] = 0x00;
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
    header[40] = (uint8_t)(wavSize & 0xFF);
    header[41] = (uint8_t)((wavSize >> 8) & 0xFF);
    header[42] = (uint8_t)((wavSize >> 16) & 0xFF);
    header[43] = (uint8_t)((wavSize >> 24) & 0xFF);
}

void uploadFile() {
  Serial.println("Uploading audio file...");

  WiFiClient client;
  HTTPClient http;

  http.begin(client, SERVER_URL);
  http.addHeader("X-API-KEY", encrypted_api_key);
  http.addHeader("Content-Type", "audio/wav");

  File uploadFile = LittleFS.open(filename, "r");
  if (!uploadFile) {
    Serial.println("Failed to open file for reading");
    return;
  }

  int httpResponseCode = http.sendRequest("POST", &uploadFile, uploadFile.size());
  if (httpResponseCode > 0) {
    Serial.printf("File uploaded successfully, response code: %d\n", httpResponseCode);
    
    String response = http.getString();
    Serial.println("Response from server: ");
    Serial.println(response);

    DynamicJsonDocument doc(1024);
    DeserializationError error = deserializeJson(doc, response);
    
    if (!error) {
      const char* transcription = doc["transcription"];
      Serial.print("Transcription: ");
      Serial.println(transcription);
    } else {
      Serial.println("Failed to parse JSON response");
    }
    
  } else {
    Serial.printf("Error uploading file: %s\n", http.errorToString(httpResponseCode).c_str());
  }
  
  uploadFile.close();
  http.end();
}

void listFiles(void) {
  Serial.println(F("\r\nListing LittleFS files:"));
  static const char line[] PROGMEM = "=================================================";

  Serial.println(FPSTR(line));
  Serial.println(F("  File name                              Size"));
  Serial.println(FPSTR(line));

  fs::File root = LittleFS.open("/");
  if (!root) {
    Serial.println(F("Failed to open directory"));
    return;
  }
  if (!root.isDirectory()) {
    Serial.println(F("Not a directory"));
    return;
  }

  fs::File file = root.openNextFile();
  while (file) {
    if (file.isDirectory()) {
      Serial.print("DIR : ");
      String fileName = file.name();
      Serial.print(fileName);
    } else {
      String fileName = file.name();
      Serial.print("  " + fileName);
      int spaces = 33 - fileName.length();
      if (spaces < 1) spaces = 1;
      while (spaces--) Serial.print(" ");
      Serial.print(file.size());
      Serial.println(" uint8_ts");
    }
    file = root.openNextFile();
  }
  Serial.println(FPSTR(line));
}

void wifiConnect(void *arg) {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    isWIFIConnected = true;
    vTaskDelete(NULL);
}

сначала ты выкладываешь какую-то хрень в которой на 250 строк более 100 ошибок, потом какие-то претензии, что не так помогают…
Почитай правила, тут НИКОМУ никто ничего не обязан, это форум по интересам, я прежде чем что-то спросить три дня читал с упоением и, мне сразу помогли, автор поправил библиотеку под мои хотелки )))

@remosYa

Я бы не писал сюда, если бы у меня не возникла проблема и я бы не попробовал использовать какие-то другие варианты. Не спорю, что никто никому ничего не должен.

и в чем проблема? скетч компилируется но не работает?

Скетч использует 1327201 байт (42%) памяти устройства. Всего доступно 3145728 байт.
Глобальные переменные используют 54128 байт (16%) динамической памяти, оставляя 273552 байт для локальных переменных. Максимум: 327680 байт.

@remosYa

Да, все так.
Скетч компилируется, загружается на устройство, но затем устройство входит в циклическую перезагрузку с ошибкой:

CONFLICT! The new i2s driver can't work along with the legacy i2s driver.

ну так используй старый драйвер, в чём проблема?
кстати для оцифровки модуль с PSRAM нужен, у тебя такой?

@remosYa

Я бы наоборот хотел использовать новый драйвер для микрофона, а не менять существующую библиотеку <Audio.h> под использование старого драйвера

версия ядра какая?
заодно покажи и версии библиотек

@remosYa

8 MB (Octal SPI)

ESP-IDF version:
v5.1.4-972-g632e0c2a9f-dirty

ESP32-audioI2S-master версии 2.0.0 :grinning:

Это самая свежая вроде, НЕ?
У автора библиотеки когнитивный диссонанс, на самом деле внутри версия 3хх

name=ESP32-audioI2S-master
version=2.0.0
author=schreibfaul1
maintainer=schreibfaul1
sentence=With this library You can easily build a WebRadio with a ESP32 board and a I2S-module.
paragraph=Plays webradio, playlists can be m3u, pls or asx. Data format can be only mp3, aac, flac or m4a. It can also play files from a SD Card.
category=Device Control
url=https://github.com/schreibfaul1/ESP32-audioI2S
architectures=esp32

@remosYa

“Audio.h” в менеджере библиотек указана V1.0.6, но я её устанавливал из github-а (Releases · schreibfaul1/ESP32-audioI2S · GitHub), там версия [3.0.12]

/*
 * Audio.h
 *
 *  Created on: Oct 28,2018
 *
 *  Version 3.0.13j
 *  Updated on: Oct 30.2024
 *      Author: Wolle (schreibfaul1)
 */

не хочу тебя расстраивать, но эта версия под старое ядро 2.ххх

@remosYa

Да, в Audio.h я увидел:

#if ESP_IDF_VERSION_MAJOR == 5
#include <driver/i2s_std.h>
#else
#include <driver/i2s.h>
#endif

Поэтому вот и подумал, что может менять стоит не Audio.h, а саму <driver/i2s> на <driver/i2s_std> в коде под микрофон