audio_prompt.c 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #include "audio_prompt.h"
  2. #include "audio_prompts_data.h"
  3. #include "audio_output.h"
  4. #include "esp_log.h"
  5. #include "freertos/FreeRTOS.h"
  6. #include "freertos/task.h"
  7. #include "dac_njw1195.h"
  8. static const char *TAG = "AudioPrompt";
  9. void audio_prompt_init(void) {
  10. ESP_LOGI(TAG, "Audio prompt module initialized");
  11. }
  12. void audio_prompt_play(prompt_id_t id) {
  13. const int16_t *prompt_data = NULL;
  14. size_t prompt_len = 0;
  15. switch (id) {
  16. case PROMPT_BT_CONNECTED:
  17. prompt_data = prompt_bt_connected;
  18. prompt_len = prompt_bt_connected_len;
  19. break;
  20. case PROMPT_BT_DISCONNECTED:
  21. prompt_data = prompt_bt_disconnected;
  22. prompt_len = prompt_bt_disconnected_len;
  23. break;
  24. case PROMPT_LOW_BATTERY:
  25. prompt_data = prompt_low_battery;
  26. prompt_len = prompt_low_battery_len;
  27. break;
  28. default:
  29. return;
  30. }
  31. if (prompt_data == NULL || prompt_len == 0) {
  32. return;
  33. }
  34. ESP_LOGI(TAG, "Playing prompt tone ID: %d", id);
  35. // Lock audio output so we don't interleave with BT/AirPlay
  36. audio_output_lock();
  37. // Switch DAC to prompt volume
  38. dac_njw1195_set_prompt_mode(true);
  39. // Prompts are generated at 44100Hz 16-bit Mono.
  40. // audio_output_write expects 16-bit Stereo. We duplicate channels.
  41. // We send in chunks to avoid large memory allocations.
  42. const size_t CHUNK_SAMPLES = 256;
  43. int16_t stereo_buf[CHUNK_SAMPLES * 2];
  44. for (size_t i = 0; i < prompt_len; i += CHUNK_SAMPLES) {
  45. size_t samples_to_process = prompt_len - i;
  46. if (samples_to_process > CHUNK_SAMPLES) {
  47. samples_to_process = CHUNK_SAMPLES;
  48. }
  49. for (size_t j = 0; j < samples_to_process; j++) {
  50. int16_t sample = prompt_data[i + j];
  51. stereo_buf[j * 2] = sample; // Left
  52. stereo_buf[j * 2 + 1] = sample; // Right
  53. }
  54. // Write stereo PCM data. audio_output_write internally calls i2s_channel_write.
  55. audio_output_write(stereo_buf, samples_to_process * 4, portMAX_DELAY);
  56. }
  57. // Write silence to flush the DMA buffers.
  58. // I2S_DMA_DESC_NUM(8) * I2S_DMA_FRAME_NUM(352) = 2816 frames.
  59. // Writing roughly 3000 frames of silence ensures the prompt is pushed out.
  60. memset(stereo_buf, 0, sizeof(stereo_buf));
  61. for (int i = 0; i < 12; i++) { // 12 * 256 = 3072 frames
  62. audio_output_write(stereo_buf, CHUNK_SAMPLES * 4, portMAX_DELAY);
  63. }
  64. // Restore original volume
  65. dac_njw1195_set_prompt_mode(false);
  66. audio_output_unlock();
  67. }