Advertisement
rextdev

audio.cpp

May 13th, 2025
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.84 KB | None | 0 0
  1. #include "audio.h"
  2. #include <Arduino.h>
  3. #include <driver/i2s.h>
  4. #include <HTTPClient.h>
  5. // I2S altavoz
  6. #define I2S_DIN 4
  7. #define I2S_BCLK 5
  8. #define I2S_LRCK 40
  9.  
  10. #define I2S_NUM I2S_NUM_0
  11. #define SAMPLE_RATE 16000
  12. #define BUFFER_SIZE 4096 // == 4KB
  13. const static char *TAG = "AUDIO";
  14.  
  15. i2s_config_t i2s_config = {
  16.     .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
  17.     .sample_rate = SAMPLE_RATE,
  18.     .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
  19.     .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
  20.     .communication_format = I2S_COMM_FORMAT_STAND_I2S,
  21.     .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
  22.     .dma_buf_count = 16,
  23.     .dma_buf_len = 128,
  24.     .use_apll = true,
  25.     .tx_desc_auto_clear = true,
  26.     //.fixed_mclk = 0
  27. };
  28.  
  29. i2s_pin_config_t pin_config = {
  30.     .bck_io_num = I2S_BCLK,
  31.     .ws_io_num = I2S_LRCK,
  32.     .data_out_num = I2S_DIN,
  33.     .data_in_num = I2S_PIN_NO_CHANGE};
  34.  
  35. void initAudio()
  36. {
  37.     // Configurar I2S
  38.     esp_err_t err = i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
  39.     if (err != ESP_OK)
  40.     {
  41.         Serial.println("Error al instalar el controlador I2S");
  42.         return;
  43.     }
  44.     err = i2s_set_pin(I2S_NUM, &pin_config);
  45.     if (err != ESP_OK)
  46.     {
  47.         Serial.println("Error al configurar los pines I2S");
  48.         return;
  49.     }
  50.     i2s_zero_dma_buffer(I2S_NUM);
  51.     i2s_set_clk(I2S_NUM, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
  52.     Serial.println("I2S configurado correctamente");
  53. }
  54.  
  55. void playAudioBuffer(uint8_t *buffer, size_t size)
  56. {
  57.     size_t bytes_written = 0;
  58.     // Serial.printf("Reproduciendo %d bytes\n", size);
  59.     esp_err_t err = i2s_write(I2S_NUM, buffer, size, &bytes_written, portMAX_DELAY);
  60.     if (err != ESP_OK)
  61.     {
  62.         Serial.println("Error al escribir en I2S");
  63.     }
  64.     if (bytes_written != size)
  65.     {
  66.         Serial.printf("No se reprodujeron todos los bytes: %d de %d\n", bytes_written, size);
  67.     }
  68. }
  69.  
  70. void playAudioFromServer(const char *url, uint16_t port, const char *filename)
  71. {
  72.     HTTPClient http;
  73.     String fullUrl = url + String(":") + String(port) + String("/audio/stream/") + String(filename);
  74.     Serial.printf("Conectando a %s\n", fullUrl.c_str());
  75.     http.begin(fullUrl);
  76.    
  77.     // Aumentar el timeout para evitar desconexiones
  78.     http.setTimeout(15000); // 15 segundos de timeout
  79.    
  80.     int httpCode = http.GET();
  81.     if (httpCode > 0)
  82.     {
  83.         Serial.printf("Código de respuesta HTTP: %d\n", httpCode);
  84.         if (httpCode == HTTP_CODE_OK)
  85.         {
  86.             WiFiClient *stream = http.getStreamPtr();
  87.             if (!stream)
  88.             {
  89.                 Serial.println("[AUDIO] Error al obtener el stream");
  90.                 http.end();
  91.                 return;
  92.             }
  93.  
  94.             // Implementar buffer circular
  95.             const size_t ringBufferSize = BUFFER_SIZE * 4; // Buffer más grande para streaming (16KB)
  96.             uint8_t *ringBuffer = (uint8_t*)malloc(ringBufferSize);
  97.             if (!ringBuffer) {
  98.                 Serial.println("[AUDIO] Error al asignar memoria para el buffer");
  99.                 http.end();
  100.                 return;
  101.             }
  102.            
  103.             size_t writePos = 0;
  104.             size_t readPos = 0;
  105.             size_t bufferedBytes = 0;
  106.             unsigned long lastDataTime = millis();
  107.             int totalBytesRead = 0;
  108.            
  109.             Serial.println("[AUDIO] Comenzando pre-llenado del buffer...");
  110.            
  111.             // Pre-llenar el buffer antes de iniciar la reproducción
  112.             while (http.connected() && bufferedBytes < ringBufferSize/2) {
  113.                 size_t available_bytes = stream->available();
  114.                 if (available_bytes > 0) {
  115.                     size_t bytesToRead = min(available_bytes, ringBufferSize - bufferedBytes);
  116.                     size_t bytesRead = stream->readBytes(ringBuffer + writePos, bytesToRead);
  117.                    
  118.                     writePos = (writePos + bytesRead) % ringBufferSize;
  119.                     bufferedBytes += bytesRead;
  120.                     totalBytesRead += bytesRead;
  121.                     lastDataTime = millis();
  122.                 } else {
  123.                     delay(5);  // Pequeña pausa si no hay datos
  124.                 }
  125.                
  126.                 // Timeout de pre-buffering
  127.                 if (millis() - lastDataTime > 5000) break;
  128.             }
  129.            
  130.             Serial.printf("[AUDIO] Buffer inicial: %d bytes\n", bufferedBytes);
  131.            
  132.             // Bucle principal de reproducción
  133.             Serial.println("[AUDIO] Comenzando reproducción...");
  134.             while (http.connected() || bufferedBytes > 0) {
  135.                 // Leer datos del servidor si hay espacio en el buffer
  136.                 if (http.connected() && bufferedBytes < ringBufferSize - BUFFER_SIZE) {
  137.                     size_t available_bytes = stream->available();
  138.                     if (available_bytes > 0) {
  139.                         size_t bytesToRead = min(available_bytes, ringBufferSize - bufferedBytes);
  140.                         size_t writeSize = min(bytesToRead, ringBufferSize - writePos);
  141.                        
  142.                         size_t bytesRead = stream->readBytes(ringBuffer + writePos, writeSize);
  143.                         writePos = (writePos + bytesRead) % ringBufferSize;
  144.                         bufferedBytes += bytesRead;
  145.                         totalBytesRead += bytesRead;
  146.                        
  147.                         // Si hay más datos pero llegamos al final del buffer, continuamos desde el principio
  148.                         if (bytesToRead > writeSize && bytesRead == writeSize) {
  149.                             size_t remaining = bytesToRead - writeSize;
  150.                             bytesRead = stream->readBytes(ringBuffer, remaining);
  151.                             writePos = bytesRead;
  152.                             bufferedBytes += bytesRead;
  153.                             totalBytesRead += bytesRead;
  154.                         }
  155.                        
  156.                         lastDataTime = millis();
  157.                     }
  158.                 }
  159.                
  160.                 // Reproducir datos si hay suficientes
  161.                 if (bufferedBytes >= BUFFER_SIZE/2) {
  162.                     size_t playSize = min(bufferedBytes, (size_t)BUFFER_SIZE/2);
  163.                     size_t contiguousBytes = min(playSize, ringBufferSize - readPos);
  164.                    
  165.                     playAudioBuffer(ringBuffer + readPos, contiguousBytes);
  166.                     readPos = (readPos + contiguousBytes) % ringBufferSize;
  167.                     bufferedBytes -= contiguousBytes;
  168.                    
  169.                     // Si necesitamos reproducir más pero llegamos al final del buffer
  170.                     if (playSize > contiguousBytes) {
  171.                         size_t remaining = playSize - contiguousBytes;
  172.                         playAudioBuffer(ringBuffer, remaining);
  173.                         readPos = remaining;
  174.                         bufferedBytes -= remaining;
  175.                     }
  176.                 }
  177.                 else if (!http.connected() && bufferedBytes > 0) {
  178.                     // Reproducir los bytes restantes al final del stream
  179.                     size_t contiguousBytes = min(bufferedBytes, ringBufferSize - readPos);
  180.                     playAudioBuffer(ringBuffer + readPos, contiguousBytes);
  181.                     readPos = (readPos + contiguousBytes) % ringBufferSize;
  182.                     bufferedBytes -= contiguousBytes;
  183.                    
  184.                     if (bufferedBytes > 0) {
  185.                         playAudioBuffer(ringBuffer, bufferedBytes);
  186.                         readPos = bufferedBytes;
  187.                         bufferedBytes = 0;
  188.                     }
  189.                 }
  190.                 else if (!http.connected() && bufferedBytes == 0) {
  191.                     break; // No hay más datos para reproducir
  192.                 }
  193.                 else {
  194.                     // Pequeña pausa si no podemos reproducir todavía
  195.                     delay(5);
  196.                 }
  197.                
  198.                 // Timeout si no recibimos datos por un periodo largo
  199.                 if (http.connected() && millis() - lastDataTime > 10000) {
  200.                     Serial.println("[AUDIO] Timeout de datos");
  201.                     break;
  202.                 }
  203.             }
  204.            
  205.             free(ringBuffer);
  206.             Serial.printf("[AUDIO] Reproducción completa, bytes leídos: %d\n", totalBytesRead);
  207.         }
  208.         else
  209.         {
  210.             Serial.printf("Error al obtener el audio: %s\n", http.errorToString(httpCode).c_str());
  211.         }
  212.     }
  213.     else
  214.     {
  215.         Serial.printf("Error al conectar al servidor: %s\n", http.errorToString(httpCode).c_str());
  216.     }
  217.     http.end();
  218. }
  219.  
  220. // Añadir después de la función playAudioFromServer
  221.  
  222. void playTestTone(int frequency, int duration_ms)
  223. {
  224.     // Generar un tono sinusoidal simple
  225.     const int samples = SAMPLE_RATE * duration_ms / 1000;
  226.     const int16_t amplitude = 10000; // Menor que 32767 para evitar distorsión
  227.    
  228.     // Creamos buffer para 100ms de audio a la vez
  229.     const int bufferSize = SAMPLE_RATE / 10;
  230.     int16_t *sampleBuffer = new int16_t[bufferSize];
  231.    
  232.     Serial.println("[AUDIO] Reproduciendo tono de prueba...");
  233.    
  234.     for (int i = 0; i < samples; i += bufferSize) {
  235.         int samplesToGenerate = min(bufferSize, samples - i);
  236.        
  237.         // Generar muestras para un tono sinusoidal
  238.         for (int j = 0; j < samplesToGenerate; j++) {
  239.             float v = sin(2 * PI * frequency * (i + j) / SAMPLE_RATE);
  240.             sampleBuffer[j] = (int16_t)(amplitude * v);
  241.         }
  242.        
  243.         // Reproducir buffer
  244.         playAudioBuffer((uint8_t*)sampleBuffer, samplesToGenerate * 2); // *2 porque cada muestra es de 2 bytes
  245.     }
  246.    
  247.     delete[] sampleBuffer;
  248.     Serial.println("[AUDIO] Tono de prueba finalizado");
  249. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement