audio_output_spdif.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /**
  2. * SPDIF audio output via I2S bit-banging — amedes approach
  3. *
  4. * Based on the public-domain SPDIF implementation by amedes:
  5. * https://github.com/amedes/esp_a2dp_sink_spdif
  6. *
  7. * The buffer is pre-filled with alternating M (left) / W (right) preambles.
  8. * Only the audio-data words (odd uint32_t indices) are written during
  9. * conversion. The B (block-start) preamble is applied by XOR-flipping one
  10. * byte at the start of each half-block write — the XOR naturally toggles
  11. * between M and B every 96 stereo frames, placing B exactly once per
  12. * 192-frame SPDIF block.
  13. *
  14. * BCK and WS are not routed to any GPIO — only the DOUT pin carries the
  15. * SPDIF signal. The internal I2S clock still runs, but no external
  16. * clocks are emitted.
  17. *
  18. * For coax SPDIF output, use this passive circuit:
  19. *
  20. * 100nF
  21. * GPIO ----210R------||---- coax SPDIF signal out
  22. * |
  23. * 110R
  24. * |
  25. * GND -------------------- coax signal ground
  26. */
  27. #include "audio_output.h"
  28. #include "audio_receiver.h"
  29. #include "audio_resample.h"
  30. #include "led.h"
  31. #include "driver/i2s_std.h"
  32. #include "esp_check.h"
  33. #include "soc/soc_caps.h"
  34. #include "freertos/FreeRTOS.h"
  35. #include "freertos/task.h"
  36. #include "rtsp_server.h"
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #define TAG "audio_spdif"
  40. #define OUTPUT_RATE CONFIG_OUTPUT_SAMPLE_RATE_HZ
  41. #define FRAME_SAMPLES 352
  42. /* Max output frames after resampling one input frame */
  43. #define MAX_RESAMPLE_FRAMES \
  44. ((size_t)((FRAME_SAMPLES + 2) * ((double)OUTPUT_RATE / 44100) + 16))
  45. #define SPDIF_DO_PIN CONFIG_SPDIF_DO_IO
  46. #if CONFIG_FREERTOS_UNICORE
  47. #define PLAYBACK_CORE 0
  48. #else
  49. #define PLAYBACK_CORE 1
  50. #endif
  51. /* ── SPDIF framing constants ──────────────────────────────────────────── */
  52. #define I2S_BITS 32
  53. #define I2S_CHANNELS 2
  54. #define BMC_BITS 64 /* bits per SPDIF sub-frame after BMC */
  55. #define BMC_FACTOR (BMC_BITS / I2S_BITS) /* = 2 */
  56. #define SPDIF_BLOCK 192 /* sub-frames per SPDIF block (L+R) */
  57. #define SPDIF_BUF_DIV 2 /* half-block buffering */
  58. /* DMA: one DMA buffer = one half-block = 96 stereo frames = 192 I2S
  59. * "pseudo-frames" of 32-bit stereo. Size = 192 × 8 = 1536 bytes. */
  60. #define DMA_BUF_COUNT 2
  61. #define DMA_BUF_FRAMES (SPDIF_BLOCK * BMC_BITS / I2S_BITS / SPDIF_BUF_DIV)
  62. /* Encode buffer (uint32_t array) — one half-block */
  63. #define SPDIF_BUF_BYTES \
  64. (SPDIF_BLOCK * (BMC_BITS / 8) * I2S_CHANNELS / SPDIF_BUF_DIV)
  65. #define SPDIF_BUF_WORDS (SPDIF_BUF_BYTES / sizeof(uint32_t))
  66. /* ── BMC preambles ─────────────────────────────────────────────────────── */
  67. #define BMC_B 0x33173333U /* block start (B) */
  68. #define BMC_M 0x331d3333U /* left channel (M) */
  69. #define BMC_W 0x331b3333U /* right channel (W) */
  70. #define BMC_MW_DIF (BMC_M ^ BMC_W)
  71. /* Byte offset within the first preamble word where M↔B differs */
  72. #define SYNC_OFFSET 2
  73. #define SYNC_FLIP ((BMC_B ^ BMC_M) >> (SYNC_OFFSET * 8))
  74. /* ── BMC lookup table ──────────────────────────────────────────────────
  75. * 8-bit PCM → 16-bit BMC, LSb first, ending with a "1" level. */
  76. // NOLINTBEGIN(bugprone-narrowing-conversions)
  77. static const int16_t bmc_tab[256] = {
  78. 0x3333, 0xb333, 0xd333, 0x5333, 0xcb33, 0x4b33, 0x2b33, 0xab33, 0xcd33,
  79. 0x4d33, 0x2d33, 0xad33, 0x3533, 0xb533, 0xd533, 0x5533, 0xccb3, 0x4cb3,
  80. 0x2cb3, 0xacb3, 0x34b3, 0xb4b3, 0xd4b3, 0x54b3, 0x32b3, 0xb2b3, 0xd2b3,
  81. 0x52b3, 0xcab3, 0x4ab3, 0x2ab3, 0xaab3, 0xccd3, 0x4cd3, 0x2cd3, 0xacd3,
  82. 0x34d3, 0xb4d3, 0xd4d3, 0x54d3, 0x32d3, 0xb2d3, 0xd2d3, 0x52d3, 0xcad3,
  83. 0x4ad3, 0x2ad3, 0xaad3, 0x3353, 0xb353, 0xd353, 0x5353, 0xcb53, 0x4b53,
  84. 0x2b53, 0xab53, 0xcd53, 0x4d53, 0x2d53, 0xad53, 0x3553, 0xb553, 0xd553,
  85. 0x5553, 0xcccb, 0x4ccb, 0x2ccb, 0xaccb, 0x34cb, 0xb4cb, 0xd4cb, 0x54cb,
  86. 0x32cb, 0xb2cb, 0xd2cb, 0x52cb, 0xcacb, 0x4acb, 0x2acb, 0xaacb, 0x334b,
  87. 0xb34b, 0xd34b, 0x534b, 0xcb4b, 0x4b4b, 0x2b4b, 0xab4b, 0xcd4b, 0x4d4b,
  88. 0x2d4b, 0xad4b, 0x354b, 0xb54b, 0xd54b, 0x554b, 0x332b, 0xb32b, 0xd32b,
  89. 0x532b, 0xcb2b, 0x4b2b, 0x2b2b, 0xab2b, 0xcd2b, 0x4d2b, 0x2d2b, 0xad2b,
  90. 0x352b, 0xb52b, 0xd52b, 0x552b, 0xccab, 0x4cab, 0x2cab, 0xacab, 0x34ab,
  91. 0xb4ab, 0xd4ab, 0x54ab, 0x32ab, 0xb2ab, 0xd2ab, 0x52ab, 0xcaab, 0x4aab,
  92. 0x2aab, 0xaaab, 0xcccd, 0x4ccd, 0x2ccd, 0xaccd, 0x34cd, 0xb4cd, 0xd4cd,
  93. 0x54cd, 0x32cd, 0xb2cd, 0xd2cd, 0x52cd, 0xcacd, 0x4acd, 0x2acd, 0xaacd,
  94. 0x334d, 0xb34d, 0xd34d, 0x534d, 0xcb4d, 0x4b4d, 0x2b4d, 0xab4d, 0xcd4d,
  95. 0x4d4d, 0x2d4d, 0xad4d, 0x354d, 0xb54d, 0xd54d, 0x554d, 0x332d, 0xb32d,
  96. 0xd32d, 0x532d, 0xcb2d, 0x4b2d, 0x2b2d, 0xab2d, 0xcd2d, 0x4d2d, 0x2d2d,
  97. 0xad2d, 0x352d, 0xb52d, 0xd52d, 0x552d, 0xccad, 0x4cad, 0x2cad, 0xacad,
  98. 0x34ad, 0xb4ad, 0xd4ad, 0x54ad, 0x32ad, 0xb2ad, 0xd2ad, 0x52ad, 0xcaad,
  99. 0x4aad, 0x2aad, 0xaaad, 0x3335, 0xb335, 0xd335, 0x5335, 0xcb35, 0x4b35,
  100. 0x2b35, 0xab35, 0xcd35, 0x4d35, 0x2d35, 0xad35, 0x3535, 0xb535, 0xd535,
  101. 0x5535, 0xccb5, 0x4cb5, 0x2cb5, 0xacb5, 0x34b5, 0xb4b5, 0xd4b5, 0x54b5,
  102. 0x32b5, 0xb2b5, 0xd2b5, 0x52b5, 0xcab5, 0x4ab5, 0x2ab5, 0xaab5, 0xccd5,
  103. 0x4cd5, 0x2cd5, 0xacd5, 0x34d5, 0xb4d5, 0xd4d5, 0x54d5, 0x32d5, 0xb2d5,
  104. 0xd2d5, 0x52d5, 0xcad5, 0x4ad5, 0x2ad5, 0xaad5, 0x3355, 0xb355, 0xd355,
  105. 0x5355, 0xcb55, 0x4b55, 0x2b55, 0xab55, 0xcd55, 0x4d55, 0x2d55, 0xad55,
  106. 0x3555, 0xb555, 0xd555, 0x5555,
  107. };
  108. // NOLINTEND(bugprone-narrowing-conversions)
  109. /* ── I2S handle ────────────────────────────────────────────────────────── */
  110. static i2s_chan_handle_t tx_handle;
  111. static volatile bool flush_requested = false;
  112. static volatile int source_rate = 44100;
  113. static volatile bool resample_reinit_needed = false;
  114. /* ── SPDIF encode buffer and write pointer ─────────────────────────────── */
  115. static uint32_t spdif_buf[SPDIF_BUF_WORDS];
  116. static uint32_t *spdif_ptr;
  117. /* ── Volume ────────────────────────────────────────────────────────────── */
  118. static void apply_volume(int16_t *buf, size_t n) {
  119. #ifndef CONFIG_DAC_CONTROLS_VOLUME
  120. int32_t vol = airplay_get_volume_q15();
  121. for (size_t i = 0; i < n; i++) {
  122. buf[i] = (int16_t)(((int32_t)buf[i] * vol) >> 15);
  123. }
  124. #endif
  125. }
  126. /* ── SPDIF buffer init ─────────────────────────────────────────────────
  127. * Pre-fill even indices with alternating M / W preamble words.
  128. * Odd indices (audio data) will be overwritten during conversion. */
  129. static void spdif_buf_init(void) {
  130. uint32_t bmc_mw = BMC_W;
  131. for (int i = 0; i < (int)SPDIF_BUF_WORDS; i += 2) {
  132. spdif_buf[i] = (bmc_mw ^= BMC_MW_DIF);
  133. }
  134. }
  135. /* ── SPDIF write ───────────────────────────────────────────────────────
  136. * Convert interleaved 16-bit PCM to BMC and push to I2S when the
  137. * half-block buffer fills.
  138. *
  139. * src — pointer to interleaved 16-bit stereo PCM
  140. * size — total byte count (frames × 2 ch × 2 bytes) */
  141. static void spdif_write(const void *src, size_t size) {
  142. const uint8_t *p = src;
  143. while (p < (const uint8_t *)src + size) {
  144. /* Each 16-bit sample → one SPDIF sub-frame:
  145. * bmc_tab[lo_byte] occupies upper 16 bits
  146. * bmc_tab[hi_byte] occupies lower 16 bits
  147. * XOR gives differential encoding
  148. * << 1 >> 1 clears MSB (parity = 0) */
  149. *(spdif_ptr + 1) =
  150. (uint32_t)(((bmc_tab[*p] << 16) ^ bmc_tab[*(p + 1)]) << 1) >> 1;
  151. p += 2;
  152. spdif_ptr += 2; /* skip preamble word → next slot pair */
  153. /* Half-block complete → toggle B-preamble and flush to DMA */
  154. if (spdif_ptr >= &spdif_buf[SPDIF_BUF_WORDS]) {
  155. size_t written;
  156. /* XOR toggles byte at SYNC_OFFSET between M and B preamble.
  157. * Because we always XOR, it alternates: B on even half-blocks,
  158. * M on odd ones → B appears once every 192 frames. */
  159. ((uint8_t *)spdif_buf)[SYNC_OFFSET] ^= SYNC_FLIP;
  160. i2s_channel_write(tx_handle, spdif_buf, sizeof(spdif_buf), &written,
  161. portMAX_DELAY);
  162. spdif_ptr = spdif_buf;
  163. }
  164. }
  165. }
  166. /* ── Playback task ─────────────────────────────────────────────────────── */
  167. static void playback_task(void *arg) {
  168. int16_t *pcm = malloc((size_t)(FRAME_SAMPLES + 1) * 2 * sizeof(int16_t));
  169. int16_t *silence = calloc((size_t)FRAME_SAMPLES * 2, sizeof(int16_t));
  170. int16_t *resample_buf = malloc(MAX_RESAMPLE_FRAMES * 2 * sizeof(int16_t));
  171. if (!pcm || !silence || !resample_buf) {
  172. ESP_LOGE(TAG, "Failed to allocate PCM buffers");
  173. free(pcm);
  174. free(silence);
  175. free(resample_buf);
  176. vTaskDelete(NULL);
  177. return;
  178. }
  179. while (true) {
  180. if (resample_reinit_needed) {
  181. resample_reinit_needed = false;
  182. audio_resample_init((uint32_t)source_rate, OUTPUT_RATE, 2);
  183. }
  184. if (flush_requested) {
  185. flush_requested = false;
  186. audio_resample_reset();
  187. i2s_channel_disable(tx_handle);
  188. spdif_buf_init();
  189. spdif_ptr = spdif_buf;
  190. i2s_channel_enable(tx_handle);
  191. }
  192. size_t samples = audio_receiver_read(pcm, FRAME_SAMPLES + 1);
  193. if (samples > 0) {
  194. int16_t *play_buf = pcm;
  195. size_t play_samples = samples;
  196. if (audio_resample_is_active()) {
  197. play_samples = audio_resample_process(pcm, samples, resample_buf,
  198. MAX_RESAMPLE_FRAMES);
  199. play_buf = resample_buf;
  200. }
  201. apply_volume(play_buf, play_samples * 2);
  202. led_audio_feed(play_buf, play_samples);
  203. spdif_write(play_buf, play_samples * 2 * sizeof(int16_t));
  204. taskYIELD();
  205. } else {
  206. led_audio_feed(silence, FRAME_SAMPLES);
  207. spdif_write(silence, (size_t)FRAME_SAMPLES * 2 * sizeof(int16_t));
  208. vTaskDelay(1);
  209. }
  210. }
  211. }
  212. /* ── Public API ────────────────────────────────────────────────────────── */
  213. esp_err_t audio_output_init(void) {
  214. ESP_LOGI(TAG, "Initialising SPDIF output (amedes) on GPIO %d", SPDIF_DO_PIN);
  215. /* Pre-fill buffer with alternating M/W preambles */
  216. spdif_buf_init();
  217. spdif_ptr = spdif_buf;
  218. /* ── I2S channel ─────────────────────────────────────────────────── */
  219. i2s_chan_config_t chan_cfg =
  220. I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
  221. chan_cfg.dma_desc_num = DMA_BUF_COUNT;
  222. chan_cfg.dma_frame_num = DMA_BUF_FRAMES;
  223. ESP_RETURN_ON_ERROR(i2s_new_channel(&chan_cfg, &tx_handle, NULL), TAG,
  224. "channel create failed");
  225. /* SPDIF: I2S at 2× sample rate, 32-bit stereo.
  226. * Only DOUT carries the SPDIF signal; BCK and WS are internal-only.
  227. * APLL provides exact audio-rate clocking (ESP32). */
  228. i2s_std_clk_config_t clk_cfg =
  229. I2S_STD_CLK_DEFAULT_CONFIG((uint32_t)OUTPUT_RATE * BMC_FACTOR);
  230. #if SOC_I2S_SUPPORTS_APLL
  231. clk_cfg.clk_src = I2S_CLK_SRC_APLL;
  232. #endif
  233. clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256;
  234. i2s_std_config_t std_cfg = {
  235. .clk_cfg = clk_cfg,
  236. .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT,
  237. I2S_SLOT_MODE_STEREO),
  238. .gpio_cfg =
  239. {
  240. .mclk = I2S_GPIO_UNUSED,
  241. .bclk = I2S_GPIO_UNUSED,
  242. .ws = I2S_GPIO_UNUSED,
  243. .dout = SPDIF_DO_PIN,
  244. .din = I2S_GPIO_UNUSED,
  245. },
  246. };
  247. ESP_RETURN_ON_ERROR(i2s_channel_init_std_mode(tx_handle, &std_cfg), TAG,
  248. "std mode init failed");
  249. ESP_RETURN_ON_ERROR(i2s_channel_enable(tx_handle), TAG,
  250. "channel enable failed");
  251. /* Pre-fill DMA with SPDIF-encoded silence so the receiver can lock */
  252. {
  253. int16_t silence_pcm[SPDIF_BLOCK * 2];
  254. memset(silence_pcm, 0, sizeof(silence_pcm));
  255. for (int i = 0; i < DMA_BUF_COUNT; i++) {
  256. spdif_write(silence_pcm,
  257. (size_t)(SPDIF_BLOCK / SPDIF_BUF_DIV) * 2 * sizeof(int16_t));
  258. }
  259. }
  260. audio_resample_init(44100, OUTPUT_RATE, 2);
  261. ESP_LOGI(TAG, "SPDIF output ready rate=%d×%d dma=%d×%d", OUTPUT_RATE,
  262. BMC_FACTOR, DMA_BUF_FRAMES, DMA_BUF_COUNT);
  263. return ESP_OK;
  264. }
  265. void audio_output_start(void) {
  266. xTaskCreatePinnedToCore(playback_task, "spdif_play", 4096, NULL, 7, NULL,
  267. PLAYBACK_CORE);
  268. }
  269. void audio_output_flush(void) {
  270. flush_requested = true;
  271. }
  272. void audio_output_set_source_rate(int rate) {
  273. if (rate > 0 && rate != source_rate) {
  274. source_rate = rate;
  275. resample_reinit_needed = true;
  276. }
  277. }
  278. uint32_t audio_output_get_hardware_latency_us(void) {
  279. // SPDIF DMA ring: DMA_BUF_COUNT half-blocks, each SPDIF_BLOCK/SPDIF_BUF_DIV
  280. // audio samples (= 96 stereo frames per buffer).
  281. const uint32_t audio_samples = DMA_BUF_COUNT * (SPDIF_BLOCK / SPDIF_BUF_DIV);
  282. return (uint32_t)((uint64_t)audio_samples * 1000000ULL / OUTPUT_RATE);
  283. }