aes67_audio.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * SPDX-FileCopyrightText: 2026 DatanoiseTV
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * Audio I/O driver using I2S TDM on ESP32-P4.
  8. *
  9. * Manages I2S DMA transfers for audio capture and playback. Provides
  10. * the audio frame callback (TIC) that drives the RTP engine's timing.
  11. * DMA buffers are in internal SRAM; larger ring buffers use PSRAM.
  12. */
  13. #pragma once
  14. #include <stdint.h>
  15. #include <stdbool.h>
  16. #include "esp_err.h"
  17. #include "aes67_config.h"
  18. #ifdef __cplusplus
  19. extern "C" {
  20. #endif
  21. /* Audio frame callback (TIC). Invoked once per audio frame period.
  22. * The callback should read from sink jitter buffers and write to
  23. * source ring buffers. */
  24. typedef void (*aes67_audio_frame_cb_t)(uint32_t frame_count, void *user_data);
  25. /* Opaque audio driver handle */
  26. typedef struct aes67_audio_ctx *aes67_audio_handle_t;
  27. /**
  28. * Initialize the I2S audio driver.
  29. *
  30. * @param audio_config Audio parameters (sample rate, channels, format)
  31. * @param pins I2S pin configuration
  32. * @param use_psram If true, allocate ring buffers in PSRAM
  33. * @param ring_buf_ms Ring buffer size in milliseconds
  34. * @param handle Output handle
  35. */
  36. esp_err_t aes67_audio_init(const aes67_audio_config_t *audio_config,
  37. const aes67_i2s_pins_t *pins,
  38. bool use_psram,
  39. uint16_t ring_buf_ms,
  40. aes67_audio_handle_t *handle);
  41. /**
  42. * Start audio I/O (enables I2S DMA).
  43. */
  44. esp_err_t aes67_audio_start(aes67_audio_handle_t handle);
  45. /**
  46. * Stop audio I/O.
  47. */
  48. esp_err_t aes67_audio_stop(aes67_audio_handle_t handle);
  49. /**
  50. * Destroy audio driver and free all buffers.
  51. */
  52. esp_err_t aes67_audio_destroy(aes67_audio_handle_t handle);
  53. /**
  54. * Register the audio frame callback. The callback is invoked from a
  55. * high-priority task each time a DMA transfer completes (one frame period).
  56. */
  57. esp_err_t aes67_audio_register_frame_cb(aes67_audio_handle_t handle,
  58. aes67_audio_frame_cb_t cb,
  59. void *user_data);
  60. /**
  61. * Write samples to the playback ring buffer (sink path).
  62. * Called from the RTP jitter buffer read path.
  63. *
  64. * @param handle Audio driver handle
  65. * @param samples Interleaved audio samples
  66. * @param frame_count Number of frames to write
  67. * @return ESP_OK, or ESP_ERR_NO_MEM if buffer full
  68. */
  69. esp_err_t aes67_audio_write_playback(aes67_audio_handle_t handle,
  70. const void *samples, uint32_t frame_count);
  71. /**
  72. * Read samples from the capture ring buffer (source path).
  73. * Called by the RTP engine to get audio data for transmission.
  74. *
  75. * @param handle Audio driver handle
  76. * @param samples Output buffer for interleaved samples
  77. * @param frame_count Number of frames to read
  78. * @return ESP_OK, or ESP_ERR_NOT_FOUND if insufficient data
  79. */
  80. esp_err_t aes67_audio_read_capture(aes67_audio_handle_t handle,
  81. void *samples, uint32_t frame_count);
  82. /**
  83. * Get current audio parameters.
  84. */
  85. esp_err_t aes67_audio_get_config(aes67_audio_handle_t handle,
  86. aes67_audio_config_t *config);
  87. /**
  88. * Get buffer fill levels (for monitoring).
  89. *
  90. * @param handle Audio driver handle
  91. * @param capture_frames Frames available in capture ring buffer
  92. * @param playback_frames Frames available in playback ring buffer
  93. */
  94. esp_err_t aes67_audio_get_buffer_levels(aes67_audio_handle_t handle,
  95. uint32_t *capture_frames,
  96. uint32_t *playback_frames);
  97. /**
  98. * Write int32 samples directly to I2S via i2s_channel_write.
  99. * Blocks until DMA has room (used for DMA-paced playback).
  100. */
  101. esp_err_t aes67_audio_direct_write(aes67_audio_handle_t handle,
  102. const int32_t *samples, uint32_t frame_count);
  103. /**
  104. * Get the I2S TX channel handle (for DMA-paced playback).
  105. */
  106. #include "driver/i2s_types.h"
  107. i2s_chan_handle_t aes67_audio_get_tx_chan(aes67_audio_handle_t handle);
  108. /**
  109. * Write int16 stereo samples to the staging ring buffer.
  110. * Called by the playback task; the DMA ISR reads from this ring.
  111. */
  112. esp_err_t aes67_audio_staging_write(aes67_audio_handle_t handle,
  113. const int16_t *samples, uint32_t sample_count);
  114. /**
  115. * Get DMA staging statistics.
  116. */
  117. void aes67_audio_get_staging_stats(aes67_audio_handle_t handle,
  118. uint32_t *isr_count, uint32_t *underruns);
  119. /**
  120. * Initialize ISR-driven playback via slot ring. Must be called
  121. * BEFORE aes67_audio_start(). The DMA ISR reads from the slot ring
  122. * which is fed by aes67_audio_slot_write().
  123. */
  124. #include "freertos/stream_buffer.h"
  125. void aes67_audio_set_isr_stream_buf(aes67_audio_handle_t handle,
  126. StreamBufferHandle_t sbuf);
  127. /**
  128. * Write one packet to the slot ring (called from Ethernet hook).
  129. */
  130. void aes67_audio_slot_write(const void *data, uint32_t len);
  131. /**
  132. * Log ISR statistics.
  133. */
  134. void aes67_audio_log_isr_stats(void);
  135. /**
  136. * Initialize I2S RX capture for source (TX) streams.
  137. * The DMA ISR copies captured int32 samples to a stream buffer.
  138. * Must be called BEFORE aes67_audio_start().
  139. */
  140. void aes67_audio_init_capture(aes67_audio_handle_t handle);
  141. /**
  142. * Get the capture stream buffer for reading captured I2S audio.
  143. */
  144. StreamBufferHandle_t aes67_audio_get_capture_buf(aes67_audio_handle_t handle);
  145. /**
  146. * Adjust the I2S TX MCLK divider for adaptive clock recovery.
  147. * ppm_adj: parts-per-million adjustment. +100 = 0.01% faster.
  148. */
  149. void aes67_audio_adjust_clock_ppm(aes67_audio_handle_t handle, int32_t ppm_adj);
  150. #ifdef __cplusplus
  151. }
  152. #endif