audio_output_usb.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /**
  2. * USB Audio Class (UAC) output — ESP32 as a USB audio source
  3. *
  4. * The ESP32 enumerates as a USB microphone (audio input device) on the
  5. * connected host. Decoded AirPlay audio is fed to the host via the UAC
  6. * input callback. This allows direct connection to USB-input amplifiers
  7. * or recording on a PC with software like Audacity.
  8. *
  9. * Uses the espressif/usb_device_uac managed component which handles all
  10. * USB descriptor, endpoint, and class-level protocol details.
  11. */
  12. #include "audio_output.h"
  13. #include "audio_receiver.h"
  14. #include "audio_resample.h"
  15. #include "led.h"
  16. #include "esp_check.h"
  17. #include "esp_log.h"
  18. #include "freertos/FreeRTOS.h"
  19. #include "freertos/ringbuf.h"
  20. #include "freertos/task.h"
  21. #include "rtsp_server.h"
  22. #include "usb_device_uac.h"
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #define TAG "audio_usb"
  26. #define OUTPUT_RATE CONFIG_OUTPUT_SAMPLE_RATE_HZ
  27. #define FRAME_SAMPLES 352
  28. #if CONFIG_OUTPUT_SAMPLE_RATE_HZ != CONFIG_UAC_SAMPLE_RATE
  29. #error \
  30. "USB audio output requires CONFIG_OUTPUT_SAMPLE_RATE_HZ to match CONFIG_UAC_SAMPLE_RATE"
  31. #endif
  32. /* Max output frames after resampling one input frame */
  33. #define MAX_RESAMPLE_FRAMES \
  34. ((size_t)((FRAME_SAMPLES + 2) * ((double)OUTPUT_RATE / 44100) + 16))
  35. #if CONFIG_FREERTOS_UNICORE
  36. #define PLAYBACK_CORE 0
  37. #else
  38. #define PLAYBACK_CORE 1
  39. #endif
  40. /* Ring buffer bridging the playback task (producer) and the USB input
  41. * callback (consumer). Sized for ~50 ms of stereo 16-bit audio. */
  42. #define USB_RINGBUF_BYTES \
  43. ((size_t)(OUTPUT_RATE) / 10 * 4) /* ~100 ms stereo 16-bit */
  44. static RingbufHandle_t s_ringbuf;
  45. static volatile bool flush_requested = false;
  46. static volatile int source_rate = 44100;
  47. static volatile bool resample_reinit_needed = false;
  48. /* ── USB UAC input callback (pull model) ──────────────────────────────
  49. * Called by the UAC stack when the host requests audio data.
  50. * We fill buf from the ring buffer; on underrun we send silence. */
  51. static esp_err_t usb_input_cb(uint8_t *buf, size_t len, size_t *bytes_read,
  52. void *cb_ctx) {
  53. size_t item_size = 0;
  54. void *data = xRingbufferReceiveUpTo(s_ringbuf, &item_size, 0, len);
  55. if (data && item_size > 0) {
  56. memcpy(buf, data, item_size);
  57. vRingbufferReturnItem(s_ringbuf, data);
  58. *bytes_read = item_size;
  59. } else {
  60. memset(buf, 0, len);
  61. *bytes_read = len;
  62. }
  63. return ESP_OK;
  64. }
  65. /* ── Volume ────────────────────────────────────────────────────────── */
  66. static void apply_volume(int16_t *buf, size_t n) {
  67. #ifndef CONFIG_DAC_CONTROLS_VOLUME
  68. int32_t vol = airplay_get_volume_q15();
  69. for (size_t i = 0; i < n; i++) {
  70. buf[i] = (int16_t)(((int32_t)buf[i] * vol) >> 15);
  71. }
  72. #endif
  73. }
  74. /* ── Playback task ─────────────────────────────────────────────────── */
  75. static void playback_task(void *arg) {
  76. int16_t *pcm = malloc((size_t)(FRAME_SAMPLES + 1) * 2 * sizeof(int16_t));
  77. int16_t *silence = calloc((size_t)FRAME_SAMPLES * 2, sizeof(int16_t));
  78. int16_t *resample_buf = malloc(MAX_RESAMPLE_FRAMES * 2 * sizeof(int16_t));
  79. if (!pcm || !silence || !resample_buf) {
  80. ESP_LOGE(TAG, "Failed to allocate buffers");
  81. free(pcm);
  82. free(silence);
  83. free(resample_buf);
  84. vTaskDelete(NULL);
  85. return;
  86. }
  87. while (true) {
  88. if (resample_reinit_needed) {
  89. resample_reinit_needed = false;
  90. audio_resample_init((uint32_t)source_rate, OUTPUT_RATE, 2);
  91. }
  92. if (flush_requested) {
  93. flush_requested = false;
  94. audio_resample_reset();
  95. /* Drain the ring buffer */
  96. size_t item_size;
  97. void *item;
  98. while ((item = xRingbufferReceive(s_ringbuf, &item_size, 0)) != NULL) {
  99. vRingbufferReturnItem(s_ringbuf, item);
  100. }
  101. }
  102. size_t samples = audio_receiver_read(pcm, FRAME_SAMPLES + 1);
  103. if (samples > 0) {
  104. int16_t *play_buf = pcm;
  105. size_t play_samples = samples;
  106. if (audio_resample_is_active()) {
  107. play_samples = audio_resample_process(pcm, samples, resample_buf,
  108. MAX_RESAMPLE_FRAMES);
  109. play_buf = resample_buf;
  110. }
  111. apply_volume(play_buf, play_samples * 2);
  112. led_audio_feed(play_buf, play_samples);
  113. size_t bytes = play_samples * 4; /* stereo 16-bit */
  114. xRingbufferSend(s_ringbuf, play_buf, bytes, portMAX_DELAY);
  115. taskYIELD();
  116. } else {
  117. led_audio_feed(silence, FRAME_SAMPLES);
  118. /* Feed silence to keep the USB stream flowing */
  119. xRingbufferSend(s_ringbuf, silence, (size_t)FRAME_SAMPLES * 4,
  120. pdMS_TO_TICKS(10));
  121. vTaskDelay(1);
  122. }
  123. }
  124. }
  125. /* ── Public API ────────────────────────────────────────────────────── */
  126. esp_err_t audio_output_init(void) {
  127. ESP_LOGI(TAG, "Initialising USB UAC audio output (rate=%d)", OUTPUT_RATE);
  128. s_ringbuf = xRingbufferCreate(USB_RINGBUF_BYTES, RINGBUF_TYPE_BYTEBUF);
  129. if (!s_ringbuf) {
  130. ESP_LOGE(TAG, "Failed to create ring buffer");
  131. return ESP_ERR_NO_MEM;
  132. }
  133. uac_device_config_t uac_cfg = {
  134. .skip_tinyusb_init = false,
  135. .output_cb = NULL, /* not a speaker — no host-to-device audio */
  136. .input_cb = usb_input_cb, /* device-to-host: AirPlay audio out */
  137. .set_mute_cb = NULL,
  138. .set_volume_cb = NULL,
  139. .cb_ctx = NULL,
  140. };
  141. esp_err_t err = uac_device_init(&uac_cfg);
  142. if (err != ESP_OK) {
  143. ESP_LOGE(TAG, "UAC device init failed: %s", esp_err_to_name(err));
  144. vRingbufferDelete(s_ringbuf);
  145. s_ringbuf = NULL;
  146. return err;
  147. }
  148. audio_resample_init(44100, OUTPUT_RATE, 2);
  149. ESP_LOGI(TAG, "USB UAC output ready");
  150. return ESP_OK;
  151. }
  152. void audio_output_start(void) {
  153. xTaskCreatePinnedToCore(playback_task, "usb_play", 4096, NULL, 7, NULL,
  154. PLAYBACK_CORE);
  155. }
  156. void audio_output_flush(void) {
  157. flush_requested = true;
  158. }
  159. void audio_output_set_source_rate(int rate) {
  160. if (rate > 0 && rate != source_rate) {
  161. source_rate = rate;
  162. resample_reinit_needed = true;
  163. }
  164. }
  165. uint32_t audio_output_get_hardware_latency_us(void) {
  166. // USB isochronous audio: ~2ms double-buffered endpoint latency.
  167. return 2000;
  168. }