Передача звука в двух направлениях между двумя ESP32

Добрый день. Есть маленький проект, в котором необходимо передавать звук с одной платы ESP32 на другую такую же платку по Wi-Fi. Звук надо передавать в двух направлениях в режиме реального времени. К каждой из плат подключены по шине I2S цифровой микрофон и усилитель мощности.
Нужна помощь, чтобы разобраться со сложившейся проблемой. Код уже написан, но передача звука происходит очень не стабильно. Постоянно происходит прерывание передачи звука, иногда происходит искажения звука. Потратил много времени на самостоятельное разбирательство, но не смог решить проблему. Все остальные нюансы сложившейся проблемы расскажу при общении.
Оплачу потраченное время после получения результата.

Какой-то странный подход.
Обычно работа оплачивается либо по времени (безотносительно результата), либо за результат (при этом оплата может быть далеко не пропорциональна потраченному времени).
А тут какой-то странный гибрид, причем, явно в ущерб исполнителю.

Выразился не совсем верно. Имел в виду написанный Вами второй вариант оплаты.

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

Я не отказываюсь заплатить вперед, но какие гарантии, что Вы не исчезните просто с моими деньгами или предложите мне не рабочее решение?
За какую сумму Вы готовы предложить свое решение?

1 лайк

Ну тогда если вы боитесь, что вас кинут, то есть конторы, которые заключат договор с вами и ни куда не убегут, решат ваши задачи. Правда ценник будет не гуманный. Но вы хотите сэкономить, и обратились на любительский форум, к фрилансерам. Ну тогда все риски вы априори берёте на себя. Человек выполняющий ваш заказ будет рисковать только своей репутацией на данном форуме. А это дороже в несколько раз ваших денег. Читайте форум, выбирайте исполнителя. А стомость вашей хотелки я думаю от $100. Удачи.

за 200$ предложил… с 0 написать… перед оплатой показал бы видео… что то он вообще не ответил))) видимо денех нету

1 лайк

эта фраза не предполагает большой оплаты - за что платить, когда код уже есть ? :slight_smile:

Дуплекс, симплекс?

тот хто йето может сделать, разве этого мало ?)
код он не выложил… в личке ему написал про это…
за то что бы написать код с 0, мой код будет норм передавать значения аналогового сигнала и преобразовывать в звук, а искать проблему и вникать в его код, еще не известно что там… это то еще удовольствие, а главное нету от него денех за общение, что бы выяснять нюансы)

1 лайк

Код который я использую:

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsClient.h>
#include "esp_wifi.h"
#include "driver/i2s.h"
#include "soc/i2s_reg.h"

#define SAMPLE_RATE (8000)
#define BITS_PER_SAMPLE (I2S_BITS_PER_SAMPLE_16BIT)

// микрофон I2S
#define MIC_I2S_PORT (I2S_NUM_0)
#define MIC_I2S_BCLK_PIN (GPIO_NUM_18)
#define MIC_I2S_WS_PIN (GPIO_NUM_19)
#define MIC_I2S_DATA_PIN (GPIO_NUM_21)

// динамик I2S
#define SPEAKER_I2S_PORT (I2S_NUM_1)
#define SPEAKER_I2S_BCLK_PIN (GPIO_NUM_25)
#define SPEAKER_I2S_WS_PIN (GPIO_NUM_26)
#define SPEAKER_I2S_DATA_PIN (GPIO_NUM_27)

#define READ_BUF_SIZE_BYTES   512

// Определяем название и пароль точки доступа
const char* ssid = "*******";
const char* password = "******";

// Определяем адрес сервера
const char* ADDR = "192.168.0.103";

// Определяем url подключения
const char* URL = "/";

// Определяем порт
const uint16_t PORT = 81;

// Создаём массив для чтения с микрофона
uint8_t mic_read_buf[READ_BUF_SIZE_BYTES];

// Создаём массив для получения
uint8_t rdata[512] {0};

// Массив для передачи на сервер
uint8_t stream_audio_output[512];

// Создаём экземпляр класса клиента
WebSocketsClient webSocket;

 
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
    memcpy(rdata, payload, length);
    Serial.println();
}

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

    // Подключаемся к WiFi
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    // Ждём подключения WiFi
    while (WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }
    Serial.println();
    Serial.print("IP адрес: ");
    Serial.println(WiFi.localIP());

    // Подключаемся к серверу
    webSocket.begin(ADDR, PORT, URL);

    // Метод событий WebSocket
    webSocket.onEvent(webSocketEvent);

    // Если соединение прервано, повторить попытку через 5 сек.
    webSocket.setReconnectInterval(5000);

    init_speaker();
    init_mic();
}


void loop() {

  webSocket.loop();
  // Считываем звук из микрофона
  size_t bytes_read = 0;
  esp_err_t err = i2s_read(MIC_I2S_PORT, &mic_read_buf, READ_BUF_SIZE_BYTES, &bytes_read,
                           portMAX_DELAY);    //portMAX_DELAY  ticks_to_wait
  if (err != ESP_OK) {
    printf("ошибка чтения I2S: %0x\n", err);
  }
  memcpy(stream_audio_output, mic_read_buf, sizeof(mic_read_buf));
  
  webSocket.sendBIN((uint8_t*)stream_audio_output, sizeof(stream_audio_output));
  printf("Данные на сервер отправлены.\n");

  // выводим звук на динамик
  size_t bytes_written = 0;

  err = i2s_write(SPEAKER_I2S_PORT, rdata, sizeof(rdata), &bytes_written,
                            portMAX_DELAY);
  if (err != ESP_OK) {
    printf("ошибка записи I2S: %0x\n", err);
  }
}

void init_mic() {
  i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = BITS_PER_SAMPLE,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4,
    .dma_buf_len = 256,
    .use_apll = false,
    .tx_desc_auto_clear = false,
    .fixed_mclk = 0,
  };

  esp_err_t err = i2s_driver_install(MIC_I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    printf("ошибка инициализации I2S микрофон\n");
  }

  i2s_pin_config_t pin_config = {
    .mck_io_num = I2S_PIN_NO_CHANGE,
    .bck_io_num = MIC_I2S_BCLK_PIN,
    .ws_io_num = MIC_I2S_WS_PIN,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num = MIC_I2S_DATA_PIN,
  };

  err = i2s_set_pin(MIC_I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    printf("ошибка настроек I2S микрофон pins\n");
  }

  err = i2s_set_clk(MIC_I2S_PORT, SAMPLE_RATE, BITS_PER_SAMPLE, I2S_CHANNEL_MONO);
  if (err != ESP_OK) {
    printf("ошибка настроек I2S микрофон clock\n");
  }
}

void init_speaker() {
  i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = BITS_PER_SAMPLE,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4,
    .dma_buf_len = 256,
    .use_apll = false,
    .tx_desc_auto_clear = true,
  };

  i2s_pin_config_t pin_config = {
    .mck_io_num = I2S_PIN_NO_CHANGE,
    .bck_io_num = SPEAKER_I2S_BCLK_PIN,
    .ws_io_num = SPEAKER_I2S_WS_PIN,
    .data_out_num = SPEAKER_I2S_DATA_PIN,
    .data_in_num = I2S_PIN_NO_CHANGE // Not used
  };

  esp_err_t err = i2s_driver_install(SPEAKER_I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    printf("ошибка инициализации I2S динамик\n");
  }

  err = i2s_set_pin(SPEAKER_I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    printf("ошибка динамик I2S pins\n");
  }

  err = i2s_set_clk(SPEAKER_I2S_PORT, SAMPLE_RATE, BITS_PER_SAMPLE, I2S_CHANNEL_MONO);
  if (err != ESP_OK) {
    printf("ошибка настроек I2S динамик clk\n");
  }
}

Звук в рутинах с idle priority обязан заикаться.

Вебсокет? Серьезно?

1 лайк

Пытался использовать ESP-NOW. Результат был очень похожим.

Учета темпа воспроизведения нет, буферизации потока нет, вебсокет, отправка блокирует прием. Короче бери предложение с написанием с нуля.

а можно код как раз с протоколом esp now ?)))

за 200$ от меня)))

В чем смысл цену в долларах называть?
Мырыкосы же не дают в них оплату вести…

судя по некоторым оговоркам этого @BABOS , он напишет примерно тоже самое.

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

1 лайк

В общем, @СерёгаК , “дорабатывать” в вашем коде нечего. кода тут фактически нет.
Так что вам нужно изменить ТЗ с “доработки” на создание полноценного продукта с нуля.