Saltar al contenido principal

Transmisión UDP de reSpeaker Flex con Xiao ESP32S3

Descripción general

Este proyecto demuestra la transmisión de audio en tiempo real utilizando la matriz de micrófonos ReSpeaker Flex XVF3800 con una placa XIAO ESP32S3. El audio se captura mediante I2S y se transmite por UDP a un servidor que se ejecuta en una máquina local, donde puede almacenarse y procesarse como un archivo .wav.

reSpeaker Flex XVF3800 Lineal con XIAO ESP32S3 reSpeaker Flex XVF3800 Circular con XIAO ESP32S3

Descripción de la funcionalidad

Este sketch realiza las siguientes tareas:

  • Se conecta a la red Wi-Fi especificada.
  • Se conecta a un servidor UDP (por ejemplo, un script de Python que se ejecuta en el PC host).
  • Captura audio en tiempo real mediante I2S desde el ReSpeaker XVF3800 usando el XIAO ESP32S3.
  • Transmite el audio capturado como datos en bruto.
nota

El firmware utilizado en este ejemplo es la versión I2S de 16 kHz. Asegúrate de que el firmware de tu XIAO ESP32S3 esté configurado para audio I2S a 16 kHz.

Código de Arduino

Actualiza estos campos antes de subirlo:

// WiFi credentials
const char* ssid = "Your-SSID";
const char* password = "WIFI-PASSWORD";
// UDP target
const char* udpAddress = "192.168.X.X"; // Change to PC/server IP
const int udpPort = 12345; // Port to send audio

Código completo (transmite ~5 segundos de audio)

#include "WiFi.h"
#include "WiFiUdp.h"
#include "AudioTools.h"

// WiFi credentials
const char* ssid = "Your-SSID";
const char* password = "WIFI-PASSWORD";

// UDP target
const char* udpAddress = "192.168.x.x";
const int udpPort = 12345;

WiFiUDP udp;

// Audio: 16kHz, stereo, 32-bit
AudioInfo info(16000, 2, 32);
I2SStream i2s_in;
I2SConfig i2s_config;

// Buffer for reading audio
#define BUFFER_SIZE 1024
uint8_t buffer[BUFFER_SIZE];

// 5 seconds of audio = 16000 Hz × 2 channels × 4 bytes = 128,000 bytes/sec
// 5 seconds = 640,000 bytes
#define TOTAL_BYTES 640000

void connectWiFi() {
Serial.printf("Connecting to WiFi: %s\n", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("\nConnected!");
Serial.printf("IP Address: %s\n", WiFi.localIP().toString().c_str());
}

void setupI2SInput() {
i2s_config = i2s_in.defaultConfig(RX_MODE);
i2s_config.copyFrom(info);

// XVF3800 pins
i2s_config.pin_bck = 8;
i2s_config.pin_ws = 7;
i2s_config.pin_data = 44;
i2s_config.pin_data_rx = 43;
i2s_config.is_master = false;

i2s_in.begin(i2s_config);
Serial.println("I2S input started.");
}

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

AudioLogger::instance().begin(Serial, AudioLogger::Info);

connectWiFi();
setupI2SInput();

// Wait a bit for I2S to stabilize
delay(500);

Serial.printf("Sending 5 seconds of audio via UDP to %s:%d\n", udpAddress, udpPort);

size_t total_sent = 0;
size_t bytes_read = 0;

// Send audio in chunks
while (total_sent < TOTAL_BYTES) {
// Read audio data
bytes_read = i2s_in.readBytes(buffer, BUFFER_SIZE);

if (bytes_read > 0) {
// Send via UDP
udp.beginPacket(udpAddress, udpPort);
udp.write(buffer, bytes_read);
udp.endPacket();

total_sent += bytes_read;

// Progress indicator
if (total_sent % 64000 == 0) {
Serial.printf("Sent %d bytes (%.1f seconds)\n", total_sent, total_sent / 128000.0);
}
} else {
Serial.println("Warning: No data read from I2S");
delay(10);
}
}

Serial.printf("Finished! Sent %d bytes total\n", total_sent);
}

void loop() {
// Nothing - runs once
}

Utiliza el Monitor Serie (115200 baudios) para confirmar el estado de la conexión y de la transmisión.

pir

Script de Python (para recibir y guardar el audio)

import socket
import wave
import time

# UDP settings
udp_ip = "0.0.0.0"
udp_port = 12345

# Audio settings (must match ESP32)
SAMPLE_RATE = 16000
CHANNELS = 2
SAMPLE_WIDTH = 4 # 32-bit = 4 bytes

# Expected data size (5 seconds)
EXPECTED_BYTES = 640000

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((udp_ip, udp_port))
sock.settimeout(2.0) # 2 second timeout

print(f"Listening for audio on {udp_ip}:{udp_port}...")

audio_data = bytearray()
last_packet_time = time.time()

try:
while True:
try:
data, addr = sock.recvfrom(4096)
if data:
audio_data.extend(data)
last_packet_time = time.time()

# Progress
if len(audio_data) % 64000 < 4096:
print(f"Received {len(audio_data)} bytes ({len(audio_data) / 128000:.1f} seconds)")

except socket.timeout:
# No data for 2 seconds - assume transmission complete
if len(audio_data) > 0:
print("Timeout - assuming transmission complete")
break
else:
print("Waiting for data...")
continue

except KeyboardInterrupt:
print("\nStopped by user")

# Save as WAV file
if len(audio_data) > 0:
print(f"\nTotal received: {len(audio_data)} bytes")
print("Saving to output.wav...")

with wave.open("output.wav", "wb") as wav_file:
wav_file.setnchannels(CHANNELS)
wav_file.setsampwidth(SAMPLE_WIDTH)
wav_file.setframerate(SAMPLE_RATE)
wav_file.writeframes(bytes(audio_data))

print("Done! Audio saved to output.wav")
else:
print("No data received!")

sock.close()

Escuchar el audio

Una vez que el archivo se haya guardado (output.wav), simplemente ábrelo usando cualquier reproductor de audio como:

  • VLC
  • Windows Media Player
  • Audacity (para inspección)

Soporte técnico y debate sobre el producto

Gracias por elegir nuestros productos. Estamos aquí para ofrecerte diferentes tipos de soporte y garantizar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para adaptarnos a diferentes preferencias y necesidades.

Loading Comments...