esphome 2024.12.3__py3-none-any.whl → 2025.2.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. esphome/__main__.py +16 -3
  2. esphome/components/adc/__init__.py +17 -11
  3. esphome/components/adc/adc_sensor.h +17 -0
  4. esphome/components/adc/adc_sensor_common.cpp +55 -0
  5. esphome/components/adc/adc_sensor_esp32.cpp +8 -5
  6. esphome/components/adc/adc_sensor_esp8266.cpp +10 -6
  7. esphome/components/adc/adc_sensor_libretiny.cpp +11 -6
  8. esphome/components/adc/adc_sensor_rp2040.cpp +13 -10
  9. esphome/components/adc/sensor.py +9 -3
  10. esphome/components/ads1115/ads1115.cpp +56 -7
  11. esphome/components/ads1115/ads1115.h +13 -1
  12. esphome/components/ads1115/sensor/__init__.py +16 -0
  13. esphome/components/ads1115/sensor/ads1115_sensor.cpp +2 -1
  14. esphome/components/ads1115/sensor/ads1115_sensor.h +2 -0
  15. esphome/components/animation/__init__.py +23 -261
  16. esphome/components/animation/animation.cpp +2 -2
  17. esphome/components/animation/animation.h +2 -1
  18. esphome/components/api/api_pb2.cpp +14 -0
  19. esphome/components/api/api_pb2.h +1 -0
  20. esphome/components/audio/__init__.py +112 -0
  21. esphome/components/audio/audio.cpp +67 -0
  22. esphome/components/audio/audio.h +125 -7
  23. esphome/components/audio/audio_decoder.cpp +361 -0
  24. esphome/components/audio/audio_decoder.h +135 -0
  25. esphome/components/audio/audio_reader.cpp +308 -0
  26. esphome/components/audio/audio_reader.h +85 -0
  27. esphome/components/audio/audio_resampler.cpp +159 -0
  28. esphome/components/audio/audio_resampler.h +101 -0
  29. esphome/components/audio/audio_transfer_buffer.cpp +165 -0
  30. esphome/components/audio/audio_transfer_buffer.h +139 -0
  31. esphome/components/audio_adc/__init__.py +41 -0
  32. esphome/components/audio_adc/audio_adc.h +17 -0
  33. esphome/components/audio_adc/automation.h +23 -0
  34. esphome/components/bk72xx/__init__.py +1 -0
  35. esphome/components/ble_client/ble_client.cpp +1 -2
  36. esphome/components/ble_client/sensor/__init__.py +1 -1
  37. esphome/components/ble_client/text_sensor/__init__.py +1 -1
  38. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +5 -0
  39. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -0
  40. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
  41. esphome/components/ch422g/ch422g.h +2 -0
  42. esphome/components/climate/__init__.py +1 -1
  43. esphome/components/climate_ir/climate_ir.cpp +2 -1
  44. esphome/components/coolix/coolix.cpp +2 -1
  45. esphome/components/custom/__init__.py +0 -3
  46. esphome/components/custom/binary_sensor/__init__.py +2 -28
  47. esphome/components/custom/climate/__init__.py +2 -27
  48. esphome/components/custom/cover/__init__.py +2 -27
  49. esphome/components/custom/light/__init__.py +2 -27
  50. esphome/components/custom/output/__init__.py +2 -58
  51. esphome/components/custom/sensor/__init__.py +2 -24
  52. esphome/components/custom/switch/__init__.py +2 -24
  53. esphome/components/custom/text_sensor/__init__.py +2 -29
  54. esphome/components/custom_component/__init__.py +3 -27
  55. esphome/components/daly_bms/daly_bms.cpp +6 -0
  56. esphome/components/daly_bms/daly_bms.h +2 -0
  57. esphome/components/daly_bms/sensor.py +6 -0
  58. esphome/components/debug/debug_component.cpp +4 -0
  59. esphome/components/debug/debug_component.h +14 -0
  60. esphome/components/debug/debug_esp32.cpp +154 -74
  61. esphome/components/dfplayer/dfplayer.cpp +15 -2
  62. esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
  63. esphome/components/dht/dht.cpp +2 -1
  64. esphome/components/display/__init__.py +18 -5
  65. esphome/components/display/display.cpp +2 -1
  66. esphome/components/display/rect.cpp +2 -1
  67. esphome/components/es7210/__init__.py +0 -0
  68. esphome/components/es7210/audio_adc.py +51 -0
  69. esphome/components/es7210/es7210.cpp +228 -0
  70. esphome/components/es7210/es7210.h +62 -0
  71. esphome/components/es7210/es7210_const.h +129 -0
  72. esphome/components/es7243e/__init__.py +0 -0
  73. esphome/components/es7243e/audio_adc.py +34 -0
  74. esphome/components/es7243e/es7243e.cpp +125 -0
  75. esphome/components/es7243e/es7243e.h +37 -0
  76. esphome/components/es7243e/es7243e_const.h +54 -0
  77. esphome/components/es8156/__init__.py +0 -0
  78. esphome/components/es8156/audio_dac.py +27 -0
  79. esphome/components/es8156/es8156.cpp +87 -0
  80. esphome/components/es8156/es8156.h +51 -0
  81. esphome/components/es8156/es8156_const.h +68 -0
  82. esphome/components/es8311/audio_dac.py +1 -2
  83. esphome/components/esp32/__init__.py +1 -0
  84. esphome/components/esp32/core.cpp +5 -1
  85. esphome/components/esp32/gpio.h +2 -0
  86. esphome/components/esp32_ble/__init__.py +39 -0
  87. esphome/components/esp32_ble/queue.h +4 -4
  88. esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
  89. esphome/components/esp32_ble_client/ble_client_base.h +2 -0
  90. esphome/components/esp32_ble_server/__init__.py +582 -12
  91. esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
  92. esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
  93. esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
  94. esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
  95. esphome/components/esp32_ble_server/ble_server.cpp +62 -67
  96. esphome/components/esp32_ble_server/ble_server.h +28 -32
  97. esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
  98. esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
  99. esphome/components/esp32_ble_server/ble_service.cpp +17 -15
  100. esphome/components/esp32_ble_server/ble_service.h +10 -14
  101. esphome/components/esp32_ble_tracker/__init__.py +6 -39
  102. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
  103. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
  104. esphome/components/esp32_improv/__init__.py +2 -8
  105. esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
  106. esphome/components/esp32_improv/esp32_improv_component.h +3 -4
  107. esphome/components/esp32_rmt/__init__.py +28 -3
  108. esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
  109. esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
  110. esphome/components/esp32_rmt_led_strip/light.py +72 -7
  111. esphome/components/esp32_touch/esp32_touch.cpp +5 -0
  112. esphome/components/esp8266/__init__.py +1 -0
  113. esphome/components/esp8266/gpio.h +1 -0
  114. esphome/components/ethernet/__init__.py +10 -10
  115. esphome/components/event/event.cpp +4 -2
  116. esphome/components/event/event.h +2 -0
  117. esphome/components/event_emitter/__init__.py +5 -0
  118. esphome/components/event_emitter/event_emitter.cpp +14 -0
  119. esphome/components/event_emitter/event_emitter.h +63 -0
  120. esphome/components/gcja5/gcja5.cpp +2 -1
  121. esphome/components/haier/haier_base.cpp +2 -1
  122. esphome/components/haier/hon_climate.cpp +2 -1
  123. esphome/components/heatpumpir/heatpumpir.cpp +2 -1
  124. esphome/components/host/__init__.py +1 -0
  125. esphome/components/host/gpio.h +1 -0
  126. esphome/components/http_request/http_request.h +2 -2
  127. esphome/components/http_request/http_request_arduino.cpp +1 -1
  128. esphome/components/http_request/http_request_idf.cpp +1 -1
  129. esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
  130. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
  131. esphome/components/i2s_audio/speaker/__init__.py +53 -6
  132. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
  133. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
  134. esphome/components/ili9xxx/display.py +29 -11
  135. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
  136. esphome/components/ili9xxx/ili9xxx_display.h +2 -1
  137. esphome/components/image/__init__.py +443 -255
  138. esphome/components/image/image.cpp +115 -61
  139. esphome/components/image/image.h +15 -24
  140. esphome/components/json/json_util.cpp +8 -34
  141. esphome/components/libretiny/__init__.py +1 -0
  142. esphome/components/libretiny/gpio_arduino.h +1 -0
  143. esphome/components/light/light_color_values.h +1 -1
  144. esphome/components/logger/__init__.py +43 -7
  145. esphome/components/logger/logger.cpp +16 -11
  146. esphome/components/logger/logger.h +11 -7
  147. esphome/components/logger/select/__init__.py +29 -0
  148. esphome/components/logger/select/logger_level_select.cpp +27 -0
  149. esphome/components/logger/select/logger_level_select.h +15 -0
  150. esphome/components/lvgl/__init__.py +96 -73
  151. esphome/components/lvgl/automation.py +39 -7
  152. esphome/components/lvgl/defines.py +8 -2
  153. esphome/components/lvgl/lvgl_esphome.cpp +8 -15
  154. esphome/components/lvgl/lvgl_esphome.h +20 -5
  155. esphome/components/lvgl/schemas.py +25 -14
  156. esphome/components/lvgl/trigger.py +27 -3
  157. esphome/components/lvgl/widgets/dropdown.py +1 -1
  158. esphome/components/lvgl/widgets/keyboard.py +8 -1
  159. esphome/components/lvgl/widgets/meter.py +2 -1
  160. esphome/components/lvgl/widgets/msgbox.py +1 -1
  161. esphome/components/lvgl/widgets/obj.py +1 -12
  162. esphome/components/lvgl/widgets/page.py +37 -2
  163. esphome/components/lvgl/widgets/tabview.py +1 -1
  164. esphome/components/max6956/max6956.h +2 -0
  165. esphome/components/mcp23016/mcp23016.h +2 -0
  166. esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
  167. esphome/components/mdns/__init__.py +1 -1
  168. esphome/components/media_player/__init__.py +37 -8
  169. esphome/components/media_player/automation.h +11 -2
  170. esphome/components/media_player/media_player.cpp +8 -0
  171. esphome/components/media_player/media_player.h +8 -4
  172. esphome/components/micronova/switch/micronova_switch.cpp +4 -2
  173. esphome/components/midea/ac_automations.h +3 -1
  174. esphome/components/midea/air_conditioner.cpp +7 -5
  175. esphome/components/midea/air_conditioner.h +1 -1
  176. esphome/components/midea/climate.py +4 -2
  177. esphome/components/midea/ir_transmitter.h +36 -5
  178. esphome/components/mixer/__init__.py +0 -0
  179. esphome/components/mixer/speaker/__init__.py +172 -0
  180. esphome/components/mixer/speaker/automation.h +19 -0
  181. esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
  182. esphome/components/mixer/speaker/mixer_speaker.h +207 -0
  183. esphome/components/mpr121/mpr121.h +2 -0
  184. esphome/components/mqtt/__init__.py +1 -1
  185. esphome/components/mqtt/mqtt_client.cpp +7 -1
  186. esphome/components/mqtt/mqtt_client.h +1 -1
  187. esphome/components/mqtt/mqtt_climate.cpp +2 -2
  188. esphome/components/network/ip_address.h +2 -0
  189. esphome/components/nextion/automation.h +17 -0
  190. esphome/components/nextion/display.py +42 -17
  191. esphome/components/nextion/nextion.cpp +4 -10
  192. esphome/components/nextion/nextion.h +89 -82
  193. esphome/components/nextion/nextion_commands.cpp +10 -10
  194. esphome/components/ntc/sensor.py +2 -4
  195. esphome/components/online_image/__init__.py +98 -46
  196. esphome/components/online_image/bmp_image.cpp +101 -0
  197. esphome/components/online_image/bmp_image.h +40 -0
  198. esphome/components/online_image/image_decoder.cpp +28 -2
  199. esphome/components/online_image/image_decoder.h +24 -15
  200. esphome/components/online_image/jpeg_image.cpp +90 -0
  201. esphome/components/online_image/jpeg_image.h +34 -0
  202. esphome/components/online_image/online_image.cpp +112 -53
  203. esphome/components/online_image/online_image.h +24 -7
  204. esphome/components/online_image/png_image.cpp +7 -3
  205. esphome/components/online_image/png_image.h +2 -1
  206. esphome/components/opentherm/__init__.py +73 -7
  207. esphome/components/opentherm/automation.h +25 -0
  208. esphome/components/opentherm/const.py +1 -0
  209. esphome/components/opentherm/generate.py +39 -6
  210. esphome/components/opentherm/hub.cpp +117 -79
  211. esphome/components/opentherm/hub.h +31 -15
  212. esphome/components/opentherm/opentherm.cpp +47 -23
  213. esphome/components/opentherm/opentherm.h +27 -6
  214. esphome/components/opentherm/opentherm_macros.h +11 -0
  215. esphome/components/opentherm/schema.py +78 -1
  216. esphome/components/opentherm/validate.py +7 -2
  217. esphome/components/pca6416a/pca6416a.h +2 -0
  218. esphome/components/pca9554/pca9554.h +2 -0
  219. esphome/components/pcf8574/pcf8574.h +2 -0
  220. esphome/components/preferences/__init__.py +2 -4
  221. esphome/components/preferences/syncer.h +10 -3
  222. esphome/components/prometheus/prometheus_handler.cpp +313 -0
  223. esphome/components/prometheus/prometheus_handler.h +48 -7
  224. esphome/components/psram/psram.cpp +8 -1
  225. esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
  226. esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
  227. esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
  228. esphome/components/qspi_dbi/__init__.py +3 -0
  229. esphome/components/qspi_dbi/display.py +74 -47
  230. esphome/components/qspi_dbi/models.py +245 -2
  231. esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
  232. esphome/components/qspi_dbi/qspi_dbi.h +2 -2
  233. esphome/components/remote_base/__init__.py +77 -25
  234. esphome/components/remote_base/remote_base.cpp +1 -1
  235. esphome/components/remote_base/remote_base.h +20 -2
  236. esphome/components/remote_base/toto_protocol.cpp +100 -0
  237. esphome/components/remote_base/toto_protocol.h +45 -0
  238. esphome/components/remote_receiver/__init__.py +55 -10
  239. esphome/components/remote_receiver/remote_receiver.h +36 -3
  240. esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
  241. esphome/components/remote_transmitter/__init__.py +62 -4
  242. esphome/components/remote_transmitter/remote_transmitter.h +21 -2
  243. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
  244. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
  245. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
  246. esphome/components/resampler/__init__.py +0 -0
  247. esphome/components/resampler/speaker/__init__.py +103 -0
  248. esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
  249. esphome/components/resampler/speaker/resampler_speaker.h +107 -0
  250. esphome/components/resistance/resistance_sensor.h +2 -3
  251. esphome/components/resistance/sensor.py +2 -9
  252. esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
  253. esphome/components/rp2040/__init__.py +1 -0
  254. esphome/components/rp2040/gpio.h +1 -0
  255. esphome/components/rtl87xx/__init__.py +2 -0
  256. esphome/components/sdl/binary_sensor.py +270 -0
  257. esphome/components/sdl/sdl_esphome.cpp +16 -0
  258. esphome/components/sdl/sdl_esphome.h +9 -0
  259. esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
  260. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
  261. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
  262. esphome/components/seeed_mr60bha2/sensor.py +9 -1
  263. esphome/components/sn74hc165/sn74hc165.h +3 -0
  264. esphome/components/sn74hc595/sn74hc595.h +3 -0
  265. esphome/components/speaker/__init__.py +5 -4
  266. esphome/components/speaker/media_player/__init__.py +458 -0
  267. esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
  268. esphome/components/speaker/media_player/audio_pipeline.h +159 -0
  269. esphome/components/speaker/media_player/automation.h +26 -0
  270. esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
  271. esphome/components/speaker/media_player/speaker_media_player.h +160 -0
  272. esphome/components/speaker/speaker.h +20 -0
  273. esphome/components/spi/__init__.py +1 -5
  274. esphome/components/spi/spi.cpp +7 -1
  275. esphome/components/spi/spi.h +21 -2
  276. esphome/components/spi_led_strip/light.py +3 -5
  277. esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
  278. esphome/components/spi_led_strip/spi_led_strip.h +8 -60
  279. esphome/components/sprinkler/sprinkler.cpp +3 -1
  280. esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
  281. esphome/components/tca9555/tca9555.h +2 -0
  282. esphome/components/toshiba/toshiba.cpp +2 -1
  283. esphome/components/tuya/light/tuya_light.cpp +4 -2
  284. esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
  285. esphome/components/uart/uart_component_esp_idf.cpp +2 -2
  286. esphome/components/udp/__init__.py +8 -2
  287. esphome/components/udp/udp_component.cpp +25 -56
  288. esphome/components/udp/udp_component.h +3 -0
  289. esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
  290. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
  291. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
  292. esphome/components/uptime/text_sensor/__init__.py +19 -0
  293. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
  294. esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
  295. esphome/components/voice_assistant/voice_assistant.cpp +24 -14
  296. esphome/components/voice_assistant/voice_assistant.h +8 -0
  297. esphome/components/waveshare_epaper/display.py +22 -1
  298. esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
  299. esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
  300. esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
  301. esphome/components/web_server/web_server.cpp +28 -6
  302. esphome/components/weikai/weikai.h +2 -0
  303. esphome/components/wifi/__init__.py +6 -6
  304. esphome/components/wifi/wifi_component.cpp +1 -1
  305. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
  306. esphome/components/wireguard/__init__.py +2 -2
  307. esphome/components/xl9535/xl9535.h +2 -0
  308. esphome/components/xxtea/__init__.py +3 -0
  309. esphome/components/xxtea/xxtea.cpp +46 -0
  310. esphome/components/xxtea/xxtea.h +26 -0
  311. esphome/components/yashima/yashima.cpp +2 -1
  312. esphome/config.py +9 -5
  313. esphome/config_validation.py +55 -17
  314. esphome/const.py +7 -10
  315. esphome/core/__init__.py +6 -13
  316. esphome/core/base_automation.h +1 -0
  317. esphome/core/config.py +57 -72
  318. esphome/core/defines.h +9 -1
  319. esphome/core/gpio.h +7 -0
  320. esphome/core/helpers.cpp +19 -15
  321. esphome/core/helpers.h +57 -8
  322. esphome/core/log.h +9 -7
  323. esphome/cpp_generator.py +2 -2
  324. esphome/espota2.py +3 -2
  325. esphome/loader.py +12 -4
  326. esphome/log.py +5 -7
  327. esphome/yaml_util.py +2 -2
  328. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/METADATA +12 -7
  329. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/RECORD +338 -289
  330. esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
  331. esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
  332. esphome/components/custom/climate/custom_climate.h +0 -22
  333. esphome/components/custom/cover/custom_cover.h +0 -21
  334. esphome/components/custom/light/custom_light_output.h +0 -24
  335. esphome/components/custom/output/custom_output.h +0 -37
  336. esphome/components/custom/sensor/custom_sensor.cpp +0 -16
  337. esphome/components/custom/sensor/custom_sensor.h +0 -24
  338. esphome/components/custom/switch/custom_switch.cpp +0 -16
  339. esphome/components/custom/switch/custom_switch.h +0 -24
  340. esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
  341. esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
  342. esphome/components/custom_component/custom_component.h +0 -28
  343. esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
  344. esphome/components/esp32_ble_server/ble_2901.h +0 -19
  345. esphome/components/resistance_sampler/__init__.py +0 -6
  346. esphome/components/resistance_sampler/resistance_sampler.h +0 -10
  347. esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
  348. /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
  349. /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
  350. /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
  351. /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
  352. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/LICENSE +0 -0
  353. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/WHEEL +0 -0
  354. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/entry_points.txt +0 -0
  355. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/top_level.txt +0 -0
@@ -1,21 +1,139 @@
1
1
  #pragma once
2
2
 
3
+ #include "esphome/core/defines.h"
4
+
3
5
  #include <cstddef>
4
6
  #include <cstdint>
5
7
 
6
8
  namespace esphome {
7
9
  namespace audio {
8
10
 
9
- struct AudioStreamInfo {
10
- bool operator==(const AudioStreamInfo &rhs) const {
11
- return (channels == rhs.channels) && (bits_per_sample == rhs.bits_per_sample) && (sample_rate == rhs.sample_rate);
11
+ class AudioStreamInfo {
12
+ /* Class to respresent important parameters of the audio stream that also provides helper function to convert between
13
+ * various audio related units.
14
+ *
15
+ * - An audio sample represents a unit of audio for one channel.
16
+ * - A frame represents a unit of audio with a sample for every channel.
17
+ *
18
+ * In gneneral, converting between bytes, samples, and frames shouldn't result in rounding errors so long as frames
19
+ * are used as the main unit when transferring audio data. Durations may result in rounding for certain sample rates;
20
+ * e.g., 44.1 KHz. The ``frames_to_milliseconds_with_remainder`` function should be used for accuracy, as it takes
21
+ * into account the remainder rather than just ignoring any rounding.
22
+ */
23
+ public:
24
+ AudioStreamInfo()
25
+ : AudioStreamInfo(16, 1, 16000){}; // Default values represent ESPHome's audio components historical values
26
+ AudioStreamInfo(uint8_t bits_per_sample, uint8_t channels, uint32_t sample_rate);
27
+
28
+ uint8_t get_bits_per_sample() const { return this->bits_per_sample_; }
29
+ uint8_t get_channels() const { return this->channels_; }
30
+ uint32_t get_sample_rate() const { return this->sample_rate_; }
31
+
32
+ /// @brief Convert bytes to duration in milliseconds.
33
+ /// @param bytes Number of bytes to convert
34
+ /// @return Duration in milliseconds that will store `bytes` bytes of audio. May round down for certain sample rates
35
+ /// or values of `bytes`.
36
+ uint32_t bytes_to_ms(size_t bytes) const {
37
+ return bytes * 1000 / (this->sample_rate_ * this->bytes_per_sample_ * this->channels_);
38
+ }
39
+
40
+ /// @brief Convert bytes to frames.
41
+ /// @param bytes Number of bytes to convert
42
+ /// @return Audio frames that will store `bytes` bytes.
43
+ uint32_t bytes_to_frames(size_t bytes) const { return (bytes / (this->bytes_per_sample_ * this->channels_)); }
44
+
45
+ /// @brief Convert bytes to samples.
46
+ /// @param bytes Number of bytes to convert
47
+ /// @return Audio samples that will store `bytes` bytes.
48
+ uint32_t bytes_to_samples(size_t bytes) const { return (bytes / this->bytes_per_sample_); }
49
+
50
+ /// @brief Converts frames to bytes.
51
+ /// @param frames Number of frames to convert.
52
+ /// @return Number of bytes that will store `frames` frames of audio.
53
+ size_t frames_to_bytes(uint32_t frames) const { return frames * this->bytes_per_sample_ * this->channels_; }
54
+
55
+ /// @brief Converts samples to bytes.
56
+ /// @param samples Number of samples to convert.
57
+ /// @return Number of bytes that will store `samples` samples of audio.
58
+ size_t samples_to_bytes(uint32_t samples) const { return samples * this->bytes_per_sample_; }
59
+
60
+ /// @brief Converts duration to frames.
61
+ /// @param ms Duration in milliseconds
62
+ /// @return Audio frames that will store `ms` milliseconds of audio. May round down for certain sample rates.
63
+ uint32_t ms_to_frames(uint32_t ms) const { return (ms * this->sample_rate_) / 1000; }
64
+
65
+ /// @brief Converts duration to samples.
66
+ /// @param ms Duration in milliseconds
67
+ /// @return Audio samples that will store `ms` milliseconds of audio. May round down for certain sample rates.
68
+ uint32_t ms_to_samples(uint32_t ms) const { return (ms * this->channels_ * this->sample_rate_) / 1000; }
69
+
70
+ /// @brief Converts duration to bytes. May round down for certain sample rates.
71
+ /// @param ms Duration in milliseconds
72
+ /// @return Bytes that will store `ms` milliseconds of audio. May round down for certain sample rates.
73
+ size_t ms_to_bytes(uint32_t ms) const {
74
+ return (ms * this->bytes_per_sample_ * this->channels_ * this->sample_rate_) / 1000;
12
75
  }
76
+
77
+ /// @brief Computes the duration, in microseconds, the given amount of frames represents.
78
+ /// @param frames Number of audio frames
79
+ /// @return Duration in microseconds `frames` respresents. May be slightly inaccurate due to integer divison rounding
80
+ /// for certain sample rates.
81
+ uint32_t frames_to_microseconds(uint32_t frames) const;
82
+
83
+ /// @brief Computes the duration, in milliseconds, the given amount of frames represents. Avoids
84
+ /// accumulating rounding errors by updating `frames` with the remainder after converting.
85
+ /// @param frames Pointer to uint32_t with the number of audio frames. Replaced with the remainder.
86
+ /// @return Duration in milliseconds `frames` represents. Always less than or equal to the actual value due to
87
+ /// rounding.
88
+ uint32_t frames_to_milliseconds_with_remainder(uint32_t *frames) const;
89
+
90
+ // Class comparison operators
91
+ bool operator==(const AudioStreamInfo &rhs) const;
13
92
  bool operator!=(const AudioStreamInfo &rhs) const { return !operator==(rhs); }
14
- size_t get_bytes_per_sample() const { return bits_per_sample / 8; }
15
- uint8_t channels = 1;
16
- uint8_t bits_per_sample = 16;
17
- uint32_t sample_rate = 16000;
93
+
94
+ protected:
95
+ uint8_t bits_per_sample_;
96
+ uint8_t channels_;
97
+ uint32_t sample_rate_;
98
+
99
+ // The greatest common divisor between 1000 ms = 1 second and the sample rate. Used to avoid accumulating error when
100
+ // converting from frames to duration. Computed at construction.
101
+ uint32_t ms_sample_rate_gcd_;
102
+
103
+ // Conversion factor derived from the number of bits per sample. Assumes audio data is aligned to the byte. Computed
104
+ // at construction.
105
+ size_t bytes_per_sample_;
18
106
  };
19
107
 
108
+ enum class AudioFileType : uint8_t {
109
+ NONE = 0,
110
+ #ifdef USE_AUDIO_FLAC_SUPPORT
111
+ FLAC,
112
+ #endif
113
+ #ifdef USE_AUDIO_MP3_SUPPORT
114
+ MP3,
115
+ #endif
116
+ WAV,
117
+ };
118
+
119
+ struct AudioFile {
120
+ const uint8_t *data;
121
+ size_t length;
122
+ AudioFileType file_type;
123
+ };
124
+
125
+ /// @brief Helper function to convert file type to a const char string
126
+ /// @param file_type
127
+ /// @return const char pointer to the readable file type
128
+ const char *audio_file_type_to_string(AudioFileType file_type);
129
+
130
+ /// @brief Scales Q15 fixed point audio samples. Scales in place if audio_samples == output_buffer.
131
+ /// @param audio_samples PCM int16 audio samples
132
+ /// @param output_buffer Buffer to store the scaled samples
133
+ /// @param scale_factor Q15 fixed point scaling factor
134
+ /// @param samples_to_scale Number of samples to scale
135
+ void scale_audio_samples(const int16_t *audio_samples, int16_t *output_buffer, int16_t scale_factor,
136
+ size_t samples_to_scale);
137
+
20
138
  } // namespace audio
21
139
  } // namespace esphome
@@ -0,0 +1,361 @@
1
+ #include "audio_decoder.h"
2
+
3
+ #ifdef USE_ESP32
4
+
5
+ #include "esphome/core/hal.h"
6
+
7
+ namespace esphome {
8
+ namespace audio {
9
+
10
+ static const uint32_t DECODING_TIMEOUT_MS = 50; // The decode function will yield after this duration
11
+ static const uint32_t READ_WRITE_TIMEOUT_MS = 20; // Timeout for transferring audio data
12
+
13
+ static const uint32_t MAX_POTENTIALLY_FAILED_COUNT = 10;
14
+
15
+ AudioDecoder::AudioDecoder(size_t input_buffer_size, size_t output_buffer_size) {
16
+ this->input_transfer_buffer_ = AudioSourceTransferBuffer::create(input_buffer_size);
17
+ this->output_transfer_buffer_ = AudioSinkTransferBuffer::create(output_buffer_size);
18
+ }
19
+
20
+ AudioDecoder::~AudioDecoder() {
21
+ #ifdef USE_AUDIO_MP3_SUPPORT
22
+ if (this->audio_file_type_ == AudioFileType::MP3) {
23
+ esp_audio_libs::helix_decoder::MP3FreeDecoder(this->mp3_decoder_);
24
+ }
25
+ #endif
26
+ }
27
+
28
+ esp_err_t AudioDecoder::add_source(std::weak_ptr<RingBuffer> &input_ring_buffer) {
29
+ if (this->input_transfer_buffer_ != nullptr) {
30
+ this->input_transfer_buffer_->set_source(input_ring_buffer);
31
+ return ESP_OK;
32
+ }
33
+ return ESP_ERR_NO_MEM;
34
+ }
35
+
36
+ esp_err_t AudioDecoder::add_sink(std::weak_ptr<RingBuffer> &output_ring_buffer) {
37
+ if (this->output_transfer_buffer_ != nullptr) {
38
+ this->output_transfer_buffer_->set_sink(output_ring_buffer);
39
+ return ESP_OK;
40
+ }
41
+ return ESP_ERR_NO_MEM;
42
+ }
43
+
44
+ #ifdef USE_SPEAKER
45
+ esp_err_t AudioDecoder::add_sink(speaker::Speaker *speaker) {
46
+ if (this->output_transfer_buffer_ != nullptr) {
47
+ this->output_transfer_buffer_->set_sink(speaker);
48
+ return ESP_OK;
49
+ }
50
+ return ESP_ERR_NO_MEM;
51
+ }
52
+ #endif
53
+
54
+ esp_err_t AudioDecoder::start(AudioFileType audio_file_type) {
55
+ if ((this->input_transfer_buffer_ == nullptr) || (this->output_transfer_buffer_ == nullptr)) {
56
+ return ESP_ERR_NO_MEM;
57
+ }
58
+
59
+ this->audio_file_type_ = audio_file_type;
60
+
61
+ this->potentially_failed_count_ = 0;
62
+ this->end_of_file_ = false;
63
+
64
+ switch (this->audio_file_type_) {
65
+ #ifdef USE_AUDIO_FLAC_SUPPORT
66
+ case AudioFileType::FLAC:
67
+ this->flac_decoder_ = make_unique<esp_audio_libs::flac::FLACDecoder>();
68
+ this->free_buffer_required_ =
69
+ this->output_transfer_buffer_->capacity(); // We'll revise this after reading the header
70
+ break;
71
+ #endif
72
+ #ifdef USE_AUDIO_MP3_SUPPORT
73
+ case AudioFileType::MP3:
74
+ this->mp3_decoder_ = esp_audio_libs::helix_decoder::MP3InitDecoder();
75
+ this->free_buffer_required_ = 1152 * sizeof(int16_t) * 2; // samples * size per sample * channels
76
+ break;
77
+ #endif
78
+ case AudioFileType::WAV:
79
+ this->wav_decoder_ = make_unique<esp_audio_libs::wav_decoder::WAVDecoder>();
80
+ this->wav_decoder_->reset();
81
+ this->free_buffer_required_ = 1024;
82
+ break;
83
+ case AudioFileType::NONE:
84
+ default:
85
+ return ESP_ERR_NOT_SUPPORTED;
86
+ break;
87
+ }
88
+
89
+ return ESP_OK;
90
+ }
91
+
92
+ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
93
+ if (stop_gracefully) {
94
+ if (this->output_transfer_buffer_->available() == 0) {
95
+ if (this->end_of_file_) {
96
+ // The file decoder indicates it reached the end of file
97
+ return AudioDecoderState::FINISHED;
98
+ }
99
+
100
+ if (!this->input_transfer_buffer_->has_buffered_data()) {
101
+ // If all the internal buffers are empty, the decoding is done
102
+ return AudioDecoderState::FINISHED;
103
+ }
104
+ }
105
+ }
106
+
107
+ if (this->potentially_failed_count_ > MAX_POTENTIALLY_FAILED_COUNT) {
108
+ if (stop_gracefully) {
109
+ // No more new data is going to come in, so decoding is done
110
+ return AudioDecoderState::FINISHED;
111
+ }
112
+ return AudioDecoderState::FAILED;
113
+ }
114
+
115
+ FileDecoderState state = FileDecoderState::MORE_TO_PROCESS;
116
+
117
+ uint32_t decoding_start = millis();
118
+
119
+ while (state == FileDecoderState::MORE_TO_PROCESS) {
120
+ // Transfer decoded out
121
+ if (!this->pause_output_) {
122
+ size_t bytes_written = this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
123
+ if (this->audio_stream_info_.has_value()) {
124
+ this->accumulated_frames_written_ += this->audio_stream_info_.value().bytes_to_frames(bytes_written);
125
+ this->playback_ms_ +=
126
+ this->audio_stream_info_.value().frames_to_milliseconds_with_remainder(&this->accumulated_frames_written_);
127
+ }
128
+ } else {
129
+ // If paused, block to avoid wasting CPU resources
130
+ delay(READ_WRITE_TIMEOUT_MS);
131
+ }
132
+
133
+ // Verify there is enough space to store more decoded audio and that the function hasn't been running too long
134
+ if ((this->output_transfer_buffer_->free() < this->free_buffer_required_) ||
135
+ (millis() - decoding_start > DECODING_TIMEOUT_MS)) {
136
+ return AudioDecoderState::DECODING;
137
+ }
138
+
139
+ // Decode more audio
140
+
141
+ size_t bytes_read = this->input_transfer_buffer_->transfer_data_from_source(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
142
+
143
+ if ((this->potentially_failed_count_ > 0) && (bytes_read == 0)) {
144
+ // Failed to decode in last attempt and there is no new data
145
+
146
+ if (this->input_transfer_buffer_->free() == 0) {
147
+ // The input buffer is full. Since it previously failed on the exact same data, we can never recover
148
+ state = FileDecoderState::FAILED;
149
+ } else {
150
+ // Attempt to get more data next time
151
+ state = FileDecoderState::IDLE;
152
+ }
153
+ } else if (this->input_transfer_buffer_->available() == 0) {
154
+ // No data to decode, attempt to get more data next time
155
+ state = FileDecoderState::IDLE;
156
+ } else {
157
+ switch (this->audio_file_type_) {
158
+ #ifdef USE_AUDIO_FLAC_SUPPORT
159
+ case AudioFileType::FLAC:
160
+ state = this->decode_flac_();
161
+ break;
162
+ #endif
163
+ #ifdef USE_AUDIO_MP3_SUPPORT
164
+ case AudioFileType::MP3:
165
+ state = this->decode_mp3_();
166
+ break;
167
+ #endif
168
+ case AudioFileType::WAV:
169
+ state = this->decode_wav_();
170
+ break;
171
+ case AudioFileType::NONE:
172
+ default:
173
+ state = FileDecoderState::IDLE;
174
+ break;
175
+ }
176
+ }
177
+
178
+ if (state == FileDecoderState::POTENTIALLY_FAILED) {
179
+ ++this->potentially_failed_count_;
180
+ } else if (state == FileDecoderState::END_OF_FILE) {
181
+ this->end_of_file_ = true;
182
+ } else if (state == FileDecoderState::FAILED) {
183
+ return AudioDecoderState::FAILED;
184
+ } else if (state == FileDecoderState::MORE_TO_PROCESS) {
185
+ this->potentially_failed_count_ = 0;
186
+ }
187
+ }
188
+ return AudioDecoderState::DECODING;
189
+ }
190
+
191
+ #ifdef USE_AUDIO_FLAC_SUPPORT
192
+ FileDecoderState AudioDecoder::decode_flac_() {
193
+ if (!this->audio_stream_info_.has_value()) {
194
+ // Header hasn't been read
195
+ auto result = this->flac_decoder_->read_header(this->input_transfer_buffer_->get_buffer_start(),
196
+ this->input_transfer_buffer_->available());
197
+
198
+ if (result == esp_audio_libs::flac::FLAC_DECODER_HEADER_OUT_OF_DATA) {
199
+ return FileDecoderState::POTENTIALLY_FAILED;
200
+ }
201
+
202
+ if (result != esp_audio_libs::flac::FLAC_DECODER_SUCCESS) {
203
+ // Couldn't read FLAC header
204
+ return FileDecoderState::FAILED;
205
+ }
206
+
207
+ size_t bytes_consumed = this->flac_decoder_->get_bytes_index();
208
+ this->input_transfer_buffer_->decrease_buffer_length(bytes_consumed);
209
+
210
+ this->free_buffer_required_ = flac_decoder_->get_output_buffer_size_bytes();
211
+ if (this->output_transfer_buffer_->capacity() < this->free_buffer_required_) {
212
+ // Output buffer is not big enough
213
+ if (!this->output_transfer_buffer_->reallocate(this->free_buffer_required_)) {
214
+ // Couldn't reallocate output buffer
215
+ return FileDecoderState::FAILED;
216
+ }
217
+ }
218
+
219
+ this->audio_stream_info_ =
220
+ audio::AudioStreamInfo(this->flac_decoder_->get_sample_depth(), this->flac_decoder_->get_num_channels(),
221
+ this->flac_decoder_->get_sample_rate());
222
+
223
+ return FileDecoderState::MORE_TO_PROCESS;
224
+ }
225
+
226
+ uint32_t output_samples = 0;
227
+ auto result = this->flac_decoder_->decode_frame(
228
+ this->input_transfer_buffer_->get_buffer_start(), this->input_transfer_buffer_->available(),
229
+ reinterpret_cast<int16_t *>(this->output_transfer_buffer_->get_buffer_end()), &output_samples);
230
+
231
+ if (result == esp_audio_libs::flac::FLAC_DECODER_ERROR_OUT_OF_DATA) {
232
+ // Not an issue, just needs more data that we'll get next time.
233
+ return FileDecoderState::POTENTIALLY_FAILED;
234
+ }
235
+
236
+ size_t bytes_consumed = this->flac_decoder_->get_bytes_index();
237
+ this->input_transfer_buffer_->decrease_buffer_length(bytes_consumed);
238
+
239
+ if (result > esp_audio_libs::flac::FLAC_DECODER_ERROR_OUT_OF_DATA) {
240
+ // Corrupted frame, don't retry with current buffer content, wait for new sync
241
+ return FileDecoderState::POTENTIALLY_FAILED;
242
+ }
243
+
244
+ // We have successfully decoded some input data and have new output data
245
+ this->output_transfer_buffer_->increase_buffer_length(
246
+ this->audio_stream_info_.value().samples_to_bytes(output_samples));
247
+
248
+ if (result == esp_audio_libs::flac::FLAC_DECODER_NO_MORE_FRAMES) {
249
+ return FileDecoderState::END_OF_FILE;
250
+ }
251
+
252
+ return FileDecoderState::MORE_TO_PROCESS;
253
+ }
254
+ #endif
255
+
256
+ #ifdef USE_AUDIO_MP3_SUPPORT
257
+ FileDecoderState AudioDecoder::decode_mp3_() {
258
+ // Look for the next sync word
259
+ int buffer_length = (int) this->input_transfer_buffer_->available();
260
+ int32_t offset =
261
+ esp_audio_libs::helix_decoder::MP3FindSyncWord(this->input_transfer_buffer_->get_buffer_start(), buffer_length);
262
+
263
+ if (offset < 0) {
264
+ // New data may have the sync word
265
+ this->input_transfer_buffer_->decrease_buffer_length(buffer_length);
266
+ return FileDecoderState::POTENTIALLY_FAILED;
267
+ }
268
+
269
+ // Advance read pointer to match the offset for the syncword
270
+ this->input_transfer_buffer_->decrease_buffer_length(offset);
271
+ uint8_t *buffer_start = this->input_transfer_buffer_->get_buffer_start();
272
+
273
+ buffer_length = (int) this->input_transfer_buffer_->available();
274
+ int err = esp_audio_libs::helix_decoder::MP3Decode(this->mp3_decoder_, &buffer_start, &buffer_length,
275
+ (int16_t *) this->output_transfer_buffer_->get_buffer_end(), 0);
276
+
277
+ size_t consumed = this->input_transfer_buffer_->available() - buffer_length;
278
+ this->input_transfer_buffer_->decrease_buffer_length(consumed);
279
+
280
+ if (err) {
281
+ switch (err) {
282
+ case esp_audio_libs::helix_decoder::ERR_MP3_OUT_OF_MEMORY:
283
+ // Intentional fallthrough
284
+ case esp_audio_libs::helix_decoder::ERR_MP3_NULL_POINTER:
285
+ return FileDecoderState::FAILED;
286
+ break;
287
+ default:
288
+ // Most errors are recoverable by moving on to the next frame, so mark as potentailly failed
289
+ return FileDecoderState::POTENTIALLY_FAILED;
290
+ break;
291
+ }
292
+ } else {
293
+ esp_audio_libs::helix_decoder::MP3FrameInfo mp3_frame_info;
294
+ esp_audio_libs::helix_decoder::MP3GetLastFrameInfo(this->mp3_decoder_, &mp3_frame_info);
295
+ if (mp3_frame_info.outputSamps > 0) {
296
+ int bytes_per_sample = (mp3_frame_info.bitsPerSample / 8);
297
+ this->output_transfer_buffer_->increase_buffer_length(mp3_frame_info.outputSamps * bytes_per_sample);
298
+
299
+ if (!this->audio_stream_info_.has_value()) {
300
+ this->audio_stream_info_ =
301
+ audio::AudioStreamInfo(mp3_frame_info.bitsPerSample, mp3_frame_info.nChans, mp3_frame_info.samprate);
302
+ }
303
+ }
304
+ }
305
+
306
+ return FileDecoderState::MORE_TO_PROCESS;
307
+ }
308
+ #endif
309
+
310
+ FileDecoderState AudioDecoder::decode_wav_() {
311
+ if (!this->audio_stream_info_.has_value()) {
312
+ // Header hasn't been processed
313
+
314
+ esp_audio_libs::wav_decoder::WAVDecoderResult result = this->wav_decoder_->decode_header(
315
+ this->input_transfer_buffer_->get_buffer_start(), this->input_transfer_buffer_->available());
316
+
317
+ if (result == esp_audio_libs::wav_decoder::WAV_DECODER_SUCCESS_IN_DATA) {
318
+ this->input_transfer_buffer_->decrease_buffer_length(this->wav_decoder_->bytes_processed());
319
+
320
+ this->audio_stream_info_ = audio::AudioStreamInfo(
321
+ this->wav_decoder_->bits_per_sample(), this->wav_decoder_->num_channels(), this->wav_decoder_->sample_rate());
322
+
323
+ this->wav_bytes_left_ = this->wav_decoder_->chunk_bytes_left();
324
+ this->wav_has_known_end_ = (this->wav_bytes_left_ > 0);
325
+ return FileDecoderState::MORE_TO_PROCESS;
326
+ } else if (result == esp_audio_libs::wav_decoder::WAV_DECODER_WARNING_INCOMPLETE_DATA) {
327
+ // Available data didn't have the full header
328
+ return FileDecoderState::POTENTIALLY_FAILED;
329
+ } else {
330
+ return FileDecoderState::FAILED;
331
+ }
332
+ } else {
333
+ if (!this->wav_has_known_end_ || (this->wav_bytes_left_ > 0)) {
334
+ size_t bytes_to_copy = this->input_transfer_buffer_->available();
335
+
336
+ if (this->wav_has_known_end_) {
337
+ bytes_to_copy = std::min(bytes_to_copy, this->wav_bytes_left_);
338
+ }
339
+
340
+ bytes_to_copy = std::min(bytes_to_copy, this->output_transfer_buffer_->free());
341
+
342
+ if (bytes_to_copy > 0) {
343
+ std::memcpy(this->output_transfer_buffer_->get_buffer_end(), this->input_transfer_buffer_->get_buffer_start(),
344
+ bytes_to_copy);
345
+ this->input_transfer_buffer_->decrease_buffer_length(bytes_to_copy);
346
+ this->output_transfer_buffer_->increase_buffer_length(bytes_to_copy);
347
+ if (this->wav_has_known_end_) {
348
+ this->wav_bytes_left_ -= bytes_to_copy;
349
+ }
350
+ }
351
+ return FileDecoderState::IDLE;
352
+ }
353
+ }
354
+
355
+ return FileDecoderState::END_OF_FILE;
356
+ }
357
+
358
+ } // namespace audio
359
+ } // namespace esphome
360
+
361
+ #endif
@@ -0,0 +1,135 @@
1
+ #pragma once
2
+
3
+ #ifdef USE_ESP32
4
+
5
+ #include "audio.h"
6
+ #include "audio_transfer_buffer.h"
7
+
8
+ #include "esphome/core/defines.h"
9
+ #include "esphome/core/helpers.h"
10
+ #include "esphome/core/ring_buffer.h"
11
+
12
+ #ifdef USE_SPEAKER
13
+ #include "esphome/components/speaker/speaker.h"
14
+ #endif
15
+
16
+ #include "esp_err.h"
17
+
18
+ // esp-audio-libs
19
+ #ifdef USE_AUDIO_FLAC_SUPPORT
20
+ #include <flac_decoder.h>
21
+ #endif
22
+ #ifdef USE_AUDIO_MP3_SUPPORT
23
+ #include <mp3_decoder.h>
24
+ #endif
25
+ #include <wav_decoder.h>
26
+
27
+ namespace esphome {
28
+ namespace audio {
29
+
30
+ enum class AudioDecoderState : uint8_t {
31
+ DECODING = 0, // More data is available to decode
32
+ FINISHED, // All file data has been decoded and transferred
33
+ FAILED, // Encountered an error
34
+ };
35
+
36
+ // Only used within the AudioDecoder class; conveys the state of the particular file type decoder
37
+ enum class FileDecoderState : uint8_t {
38
+ MORE_TO_PROCESS, // Successsfully read a file chunk and more data is available to decode
39
+ IDLE, // Not enough data to decode, waiting for more to be transferred
40
+ POTENTIALLY_FAILED, // Decoder encountered a potentially recoverable error if more file data is available
41
+ FAILED, // Decoder encoutnered an uncrecoverable error
42
+ END_OF_FILE, // The specific file decoder knows its the end of the file
43
+ };
44
+
45
+ class AudioDecoder {
46
+ /*
47
+ * @brief Class that facilitates decoding an audio file.
48
+ * The audio file is read from a ring buffer source, decoded, and sent to an audio sink (ring buffer or speaker
49
+ * component).
50
+ * Supports wav, flac, and mp3 formats.
51
+ */
52
+ public:
53
+ /// @brief Allocates the input and output transfer buffers
54
+ /// @param input_buffer_size Size of the input transfer buffer in bytes.
55
+ /// @param output_buffer_size Size of the output transfer buffer in bytes.
56
+ AudioDecoder(size_t input_buffer_size, size_t output_buffer_size);
57
+
58
+ /// @brief Deallocates the MP3 decoder (the flac and wav decoders are deallocated automatically)
59
+ ~AudioDecoder();
60
+
61
+ /// @brief Adds a source ring buffer for raw file data. Takes ownership of the ring buffer in a shared_ptr.
62
+ /// @param input_ring_buffer weak_ptr of a shared_ptr of the sink ring buffer to transfer ownership
63
+ /// @return ESP_OK if successsful, ESP_ERR_NO_MEM if the transfer buffer wasn't allocated
64
+ esp_err_t add_source(std::weak_ptr<RingBuffer> &input_ring_buffer);
65
+
66
+ /// @brief Adds a sink ring buffer for decoded audio. Takes ownership of the ring buffer in a shared_ptr.
67
+ /// @param output_ring_buffer weak_ptr of a shared_ptr of the sink ring buffer to transfer ownership
68
+ /// @return ESP_OK if successsful, ESP_ERR_NO_MEM if the transfer buffer wasn't allocated
69
+ esp_err_t add_sink(std::weak_ptr<RingBuffer> &output_ring_buffer);
70
+
71
+ #ifdef USE_SPEAKER
72
+ /// @brief Adds a sink speaker for decoded audio.
73
+ /// @param speaker pointer to speaker component
74
+ /// @return ESP_OK if successsful, ESP_ERR_NO_MEM if the transfer buffer wasn't allocated
75
+ esp_err_t add_sink(speaker::Speaker *speaker);
76
+ #endif
77
+
78
+ /// @brief Sets up decoding the file
79
+ /// @param audio_file_type AudioFileType of the file
80
+ /// @return ESP_OK if successful, ESP_ERR_NO_MEM if the transfer buffers fail to allocate, or ESP_ERR_NOT_SUPPORTED if
81
+ /// the format isn't supported.
82
+ esp_err_t start(AudioFileType audio_file_type);
83
+
84
+ /// @brief Decodes audio from the ring buffer source and writes to the sink.
85
+ /// @param stop_gracefully If true, it indicates the file source is finished. The decoder will decode all the
86
+ /// reamining data and then finish.
87
+ /// @return AudioDecoderState
88
+ AudioDecoderState decode(bool stop_gracefully);
89
+
90
+ /// @brief Gets the audio stream information, if it has been decoded from the files header
91
+ /// @return optional<AudioStreamInfo> with the audio information. If not available yet, returns no value.
92
+ const optional<audio::AudioStreamInfo> &get_audio_stream_info() const { return this->audio_stream_info_; }
93
+
94
+ /// @brief Returns the duration of audio (in milliseconds) decoded and sent to the sink
95
+ /// @return Duration of decoded audio in milliseconds
96
+ uint32_t get_playback_ms() const { return this->playback_ms_; }
97
+
98
+ /// @brief Pauses sending resampled audio to the sink. If paused, it will continue to process internal buffers.
99
+ /// @param pause_state If true, audio data is not sent to the sink.
100
+ void set_pause_output_state(bool pause_state) { this->pause_output_ = pause_state; }
101
+
102
+ protected:
103
+ std::unique_ptr<esp_audio_libs::wav_decoder::WAVDecoder> wav_decoder_;
104
+ #ifdef USE_AUDIO_FLAC_SUPPORT
105
+ FileDecoderState decode_flac_();
106
+ std::unique_ptr<esp_audio_libs::flac::FLACDecoder> flac_decoder_;
107
+ #endif
108
+ #ifdef USE_AUDIO_MP3_SUPPORT
109
+ FileDecoderState decode_mp3_();
110
+ esp_audio_libs::helix_decoder::HMP3Decoder mp3_decoder_;
111
+ #endif
112
+ FileDecoderState decode_wav_();
113
+
114
+ std::unique_ptr<AudioSourceTransferBuffer> input_transfer_buffer_;
115
+ std::unique_ptr<AudioSinkTransferBuffer> output_transfer_buffer_;
116
+
117
+ AudioFileType audio_file_type_{AudioFileType::NONE};
118
+ optional<AudioStreamInfo> audio_stream_info_{};
119
+
120
+ size_t free_buffer_required_{0};
121
+ size_t wav_bytes_left_{0};
122
+
123
+ uint32_t potentially_failed_count_{0};
124
+ bool end_of_file_{false};
125
+ bool wav_has_known_end_{false};
126
+
127
+ bool pause_output_{false};
128
+
129
+ uint32_t accumulated_frames_written_{0};
130
+ uint32_t playback_ms_{0};
131
+ };
132
+ } // namespace audio
133
+ } // namespace esphome
134
+
135
+ #endif