Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "audio.h"
- #include <Arduino.h>
- #include <driver/i2s.h>
- #include <HTTPClient.h>
- // I2S altavoz
- #define I2S_DIN 4
- #define I2S_BCLK 5
- #define I2S_LRCK 40
- #define I2S_NUM I2S_NUM_0
- #define SAMPLE_RATE 16000
- #define BUFFER_SIZE 4096 // == 4KB
- const static char *TAG = "AUDIO";
- i2s_config_t i2s_config = {
- .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
- .sample_rate = SAMPLE_RATE,
- .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
- .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
- .communication_format = I2S_COMM_FORMAT_STAND_I2S,
- .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
- .dma_buf_count = 16,
- .dma_buf_len = 128,
- .use_apll = true,
- .tx_desc_auto_clear = true,
- //.fixed_mclk = 0
- };
- i2s_pin_config_t pin_config = {
- .bck_io_num = I2S_BCLK,
- .ws_io_num = I2S_LRCK,
- .data_out_num = I2S_DIN,
- .data_in_num = I2S_PIN_NO_CHANGE};
- void initAudio()
- {
- // Configurar I2S
- esp_err_t err = i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
- if (err != ESP_OK)
- {
- Serial.println("Error al instalar el controlador I2S");
- return;
- }
- err = i2s_set_pin(I2S_NUM, &pin_config);
- if (err != ESP_OK)
- {
- Serial.println("Error al configurar los pines I2S");
- return;
- }
- i2s_zero_dma_buffer(I2S_NUM);
- i2s_set_clk(I2S_NUM, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
- Serial.println("I2S configurado correctamente");
- }
- void playAudioBuffer(uint8_t *buffer, size_t size)
- {
- size_t bytes_written = 0;
- // Serial.printf("Reproduciendo %d bytes\n", size);
- esp_err_t err = i2s_write(I2S_NUM, buffer, size, &bytes_written, portMAX_DELAY);
- if (err != ESP_OK)
- {
- Serial.println("Error al escribir en I2S");
- }
- if (bytes_written != size)
- {
- Serial.printf("No se reprodujeron todos los bytes: %d de %d\n", bytes_written, size);
- }
- }
- void playAudioFromServer(const char *url, uint16_t port, const char *filename)
- {
- HTTPClient http;
- String fullUrl = url + String(":") + String(port) + String("/audio/stream/") + String(filename);
- Serial.printf("Conectando a %s\n", fullUrl.c_str());
- http.begin(fullUrl);
- // Aumentar el timeout para evitar desconexiones
- http.setTimeout(15000); // 15 segundos de timeout
- int httpCode = http.GET();
- if (httpCode > 0)
- {
- Serial.printf("Código de respuesta HTTP: %d\n", httpCode);
- if (httpCode == HTTP_CODE_OK)
- {
- WiFiClient *stream = http.getStreamPtr();
- if (!stream)
- {
- Serial.println("[AUDIO] Error al obtener el stream");
- http.end();
- return;
- }
- // Implementar buffer circular
- const size_t ringBufferSize = BUFFER_SIZE * 4; // Buffer más grande para streaming (16KB)
- uint8_t *ringBuffer = (uint8_t*)malloc(ringBufferSize);
- if (!ringBuffer) {
- Serial.println("[AUDIO] Error al asignar memoria para el buffer");
- http.end();
- return;
- }
- size_t writePos = 0;
- size_t readPos = 0;
- size_t bufferedBytes = 0;
- unsigned long lastDataTime = millis();
- int totalBytesRead = 0;
- Serial.println("[AUDIO] Comenzando pre-llenado del buffer...");
- // Pre-llenar el buffer antes de iniciar la reproducción
- while (http.connected() && bufferedBytes < ringBufferSize/2) {
- size_t available_bytes = stream->available();
- if (available_bytes > 0) {
- size_t bytesToRead = min(available_bytes, ringBufferSize - bufferedBytes);
- size_t bytesRead = stream->readBytes(ringBuffer + writePos, bytesToRead);
- writePos = (writePos + bytesRead) % ringBufferSize;
- bufferedBytes += bytesRead;
- totalBytesRead += bytesRead;
- lastDataTime = millis();
- } else {
- delay(5); // Pequeña pausa si no hay datos
- }
- // Timeout de pre-buffering
- if (millis() - lastDataTime > 5000) break;
- }
- Serial.printf("[AUDIO] Buffer inicial: %d bytes\n", bufferedBytes);
- // Bucle principal de reproducción
- Serial.println("[AUDIO] Comenzando reproducción...");
- while (http.connected() || bufferedBytes > 0) {
- // Leer datos del servidor si hay espacio en el buffer
- if (http.connected() && bufferedBytes < ringBufferSize - BUFFER_SIZE) {
- size_t available_bytes = stream->available();
- if (available_bytes > 0) {
- size_t bytesToRead = min(available_bytes, ringBufferSize - bufferedBytes);
- size_t writeSize = min(bytesToRead, ringBufferSize - writePos);
- size_t bytesRead = stream->readBytes(ringBuffer + writePos, writeSize);
- writePos = (writePos + bytesRead) % ringBufferSize;
- bufferedBytes += bytesRead;
- totalBytesRead += bytesRead;
- // Si hay más datos pero llegamos al final del buffer, continuamos desde el principio
- if (bytesToRead > writeSize && bytesRead == writeSize) {
- size_t remaining = bytesToRead - writeSize;
- bytesRead = stream->readBytes(ringBuffer, remaining);
- writePos = bytesRead;
- bufferedBytes += bytesRead;
- totalBytesRead += bytesRead;
- }
- lastDataTime = millis();
- }
- }
- // Reproducir datos si hay suficientes
- if (bufferedBytes >= BUFFER_SIZE/2) {
- size_t playSize = min(bufferedBytes, (size_t)BUFFER_SIZE/2);
- size_t contiguousBytes = min(playSize, ringBufferSize - readPos);
- playAudioBuffer(ringBuffer + readPos, contiguousBytes);
- readPos = (readPos + contiguousBytes) % ringBufferSize;
- bufferedBytes -= contiguousBytes;
- // Si necesitamos reproducir más pero llegamos al final del buffer
- if (playSize > contiguousBytes) {
- size_t remaining = playSize - contiguousBytes;
- playAudioBuffer(ringBuffer, remaining);
- readPos = remaining;
- bufferedBytes -= remaining;
- }
- }
- else if (!http.connected() && bufferedBytes > 0) {
- // Reproducir los bytes restantes al final del stream
- size_t contiguousBytes = min(bufferedBytes, ringBufferSize - readPos);
- playAudioBuffer(ringBuffer + readPos, contiguousBytes);
- readPos = (readPos + contiguousBytes) % ringBufferSize;
- bufferedBytes -= contiguousBytes;
- if (bufferedBytes > 0) {
- playAudioBuffer(ringBuffer, bufferedBytes);
- readPos = bufferedBytes;
- bufferedBytes = 0;
- }
- }
- else if (!http.connected() && bufferedBytes == 0) {
- break; // No hay más datos para reproducir
- }
- else {
- // Pequeña pausa si no podemos reproducir todavía
- delay(5);
- }
- // Timeout si no recibimos datos por un periodo largo
- if (http.connected() && millis() - lastDataTime > 10000) {
- Serial.println("[AUDIO] Timeout de datos");
- break;
- }
- }
- free(ringBuffer);
- Serial.printf("[AUDIO] Reproducción completa, bytes leídos: %d\n", totalBytesRead);
- }
- else
- {
- Serial.printf("Error al obtener el audio: %s\n", http.errorToString(httpCode).c_str());
- }
- }
- else
- {
- Serial.printf("Error al conectar al servidor: %s\n", http.errorToString(httpCode).c_str());
- }
- http.end();
- }
- // Añadir después de la función playAudioFromServer
- void playTestTone(int frequency, int duration_ms)
- {
- // Generar un tono sinusoidal simple
- const int samples = SAMPLE_RATE * duration_ms / 1000;
- const int16_t amplitude = 10000; // Menor que 32767 para evitar distorsión
- // Creamos buffer para 100ms de audio a la vez
- const int bufferSize = SAMPLE_RATE / 10;
- int16_t *sampleBuffer = new int16_t[bufferSize];
- Serial.println("[AUDIO] Reproduciendo tono de prueba...");
- for (int i = 0; i < samples; i += bufferSize) {
- int samplesToGenerate = min(bufferSize, samples - i);
- // Generar muestras para un tono sinusoidal
- for (int j = 0; j < samplesToGenerate; j++) {
- float v = sin(2 * PI * frequency * (i + j) / SAMPLE_RATE);
- sampleBuffer[j] = (int16_t)(amplitude * v);
- }
- // Reproducir buffer
- playAudioBuffer((uint8_t*)sampleBuffer, samplesToGenerate * 2); // *2 porque cada muestra es de 2 bytes
- }
- delete[] sampleBuffer;
- Serial.println("[AUDIO] Tono de prueba finalizado");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement