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
@@ -0,0 +1,308 @@
1
+ #include "audio_reader.h"
2
+
3
+ #ifdef USE_ESP_IDF
4
+
5
+ #include "esphome/core/defines.h"
6
+ #include "esphome/core/hal.h"
7
+ #include "esphome/core/helpers.h"
8
+
9
+ #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
10
+ #include "esp_crt_bundle.h"
11
+ #endif
12
+
13
+ namespace esphome {
14
+ namespace audio {
15
+
16
+ static const uint32_t READ_WRITE_TIMEOUT_MS = 20;
17
+
18
+ // The number of times the http read times out with no data before throwing an error
19
+ static const uint32_t ERROR_COUNT_NO_DATA_READ_TIMEOUT = 100;
20
+
21
+ static const size_t HTTP_STREAM_BUFFER_SIZE = 2048;
22
+
23
+ static const uint8_t MAX_REDIRECTION = 5;
24
+
25
+ // Some common HTTP status codes - borrowed from http_request component accessed 20241224
26
+ enum HttpStatus {
27
+ HTTP_STATUS_OK = 200,
28
+ HTTP_STATUS_NO_CONTENT = 204,
29
+ HTTP_STATUS_PARTIAL_CONTENT = 206,
30
+
31
+ /* 3xx - Redirection */
32
+ HTTP_STATUS_MULTIPLE_CHOICES = 300,
33
+ HTTP_STATUS_MOVED_PERMANENTLY = 301,
34
+ HTTP_STATUS_FOUND = 302,
35
+ HTTP_STATUS_SEE_OTHER = 303,
36
+ HTTP_STATUS_NOT_MODIFIED = 304,
37
+ HTTP_STATUS_TEMPORARY_REDIRECT = 307,
38
+ HTTP_STATUS_PERMANENT_REDIRECT = 308,
39
+
40
+ /* 4XX - CLIENT ERROR */
41
+ HTTP_STATUS_BAD_REQUEST = 400,
42
+ HTTP_STATUS_UNAUTHORIZED = 401,
43
+ HTTP_STATUS_FORBIDDEN = 403,
44
+ HTTP_STATUS_NOT_FOUND = 404,
45
+ HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
46
+ HTTP_STATUS_NOT_ACCEPTABLE = 406,
47
+ HTTP_STATUS_LENGTH_REQUIRED = 411,
48
+
49
+ /* 5xx - Server Error */
50
+ HTTP_STATUS_INTERNAL_ERROR = 500
51
+ };
52
+
53
+ AudioReader::~AudioReader() { this->cleanup_connection_(); }
54
+
55
+ esp_err_t AudioReader::add_sink(const std::weak_ptr<RingBuffer> &output_ring_buffer) {
56
+ if (current_audio_file_ != nullptr) {
57
+ // A transfer buffer isn't ncessary for a local file
58
+ this->file_ring_buffer_ = output_ring_buffer.lock();
59
+ return ESP_OK;
60
+ }
61
+
62
+ if (this->output_transfer_buffer_ != nullptr) {
63
+ this->output_transfer_buffer_->set_sink(output_ring_buffer);
64
+ return ESP_OK;
65
+ }
66
+
67
+ return ESP_ERR_INVALID_STATE;
68
+ }
69
+
70
+ esp_err_t AudioReader::start(AudioFile *audio_file, AudioFileType &file_type) {
71
+ file_type = AudioFileType::NONE;
72
+
73
+ this->current_audio_file_ = audio_file;
74
+
75
+ this->file_current_ = audio_file->data;
76
+ file_type = audio_file->file_type;
77
+
78
+ return ESP_OK;
79
+ }
80
+
81
+ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
82
+ file_type = AudioFileType::NONE;
83
+
84
+ this->cleanup_connection_();
85
+
86
+ if (uri.empty()) {
87
+ return ESP_ERR_INVALID_ARG;
88
+ }
89
+
90
+ esp_http_client_config_t client_config = {};
91
+
92
+ client_config.url = uri.c_str();
93
+ client_config.cert_pem = nullptr;
94
+ client_config.disable_auto_redirect = false;
95
+ client_config.max_redirection_count = 10;
96
+ client_config.event_handler = http_event_handler;
97
+ client_config.user_data = this;
98
+ client_config.buffer_size = HTTP_STREAM_BUFFER_SIZE;
99
+ client_config.keep_alive_enable = true;
100
+ client_config.timeout_ms = 5000; // Shouldn't trigger watchdog resets if caller runs in a task
101
+
102
+ #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
103
+ if (uri.find("https:") != std::string::npos) {
104
+ client_config.crt_bundle_attach = esp_crt_bundle_attach;
105
+ }
106
+ #endif
107
+
108
+ this->client_ = esp_http_client_init(&client_config);
109
+
110
+ if (this->client_ == nullptr) {
111
+ return ESP_FAIL;
112
+ }
113
+
114
+ esp_err_t err = esp_http_client_open(this->client_, 0);
115
+
116
+ if (err != ESP_OK) {
117
+ this->cleanup_connection_();
118
+ return err;
119
+ }
120
+
121
+ int64_t header_length = esp_http_client_fetch_headers(this->client_);
122
+ if (header_length < 0) {
123
+ this->cleanup_connection_();
124
+ return ESP_FAIL;
125
+ }
126
+
127
+ int status_code = esp_http_client_get_status_code(this->client_);
128
+
129
+ if ((status_code < HTTP_STATUS_OK) || (status_code > HTTP_STATUS_PERMANENT_REDIRECT)) {
130
+ this->cleanup_connection_();
131
+ return ESP_FAIL;
132
+ }
133
+
134
+ ssize_t redirect_count = 0;
135
+
136
+ while ((esp_http_client_set_redirection(this->client_) == ESP_OK) && (redirect_count < MAX_REDIRECTION)) {
137
+ err = esp_http_client_open(this->client_, 0);
138
+ if (err != ESP_OK) {
139
+ this->cleanup_connection_();
140
+ return ESP_FAIL;
141
+ }
142
+
143
+ header_length = esp_http_client_fetch_headers(this->client_);
144
+ if (header_length < 0) {
145
+ this->cleanup_connection_();
146
+ return ESP_FAIL;
147
+ }
148
+
149
+ status_code = esp_http_client_get_status_code(this->client_);
150
+
151
+ if ((status_code < HTTP_STATUS_OK) || (status_code > HTTP_STATUS_PERMANENT_REDIRECT)) {
152
+ this->cleanup_connection_();
153
+ return ESP_FAIL;
154
+ }
155
+
156
+ ++redirect_count;
157
+ }
158
+
159
+ if (this->audio_file_type_ == AudioFileType::NONE) {
160
+ // Failed to determine the file type from the header, fallback to using the url
161
+ char url[500];
162
+ err = esp_http_client_get_url(this->client_, url, 500);
163
+ if (err != ESP_OK) {
164
+ this->cleanup_connection_();
165
+ return err;
166
+ }
167
+
168
+ std::string url_string = str_lower_case(url);
169
+
170
+ if (str_endswith(url_string, ".wav")) {
171
+ file_type = AudioFileType::WAV;
172
+ }
173
+ #ifdef USE_AUDIO_MP3_SUPPORT
174
+ else if (str_endswith(url_string, ".mp3")) {
175
+ file_type = AudioFileType::MP3;
176
+ }
177
+ #endif
178
+ #ifdef USE_AUDIO_FLAC_SUPPORT
179
+ else if (str_endswith(url_string, ".flac")) {
180
+ file_type = AudioFileType::FLAC;
181
+ }
182
+ #endif
183
+ else {
184
+ file_type = AudioFileType::NONE;
185
+ this->cleanup_connection_();
186
+ return ESP_ERR_NOT_SUPPORTED;
187
+ }
188
+ } else {
189
+ file_type = this->audio_file_type_;
190
+ }
191
+
192
+ this->no_data_read_count_ = 0;
193
+
194
+ this->output_transfer_buffer_ = AudioSinkTransferBuffer::create(this->buffer_size_);
195
+ if (this->output_transfer_buffer_ == nullptr) {
196
+ return ESP_ERR_NO_MEM;
197
+ }
198
+
199
+ return ESP_OK;
200
+ }
201
+
202
+ AudioReaderState AudioReader::read() {
203
+ if (this->client_ != nullptr) {
204
+ return this->http_read_();
205
+ } else if (this->current_audio_file_ != nullptr) {
206
+ return this->file_read_();
207
+ }
208
+
209
+ return AudioReaderState::FAILED;
210
+ }
211
+
212
+ AudioFileType AudioReader::get_audio_type(const char *content_type) {
213
+ #ifdef USE_AUDIO_MP3_SUPPORT
214
+ if (strcasecmp(content_type, "mp3") == 0 || strcasecmp(content_type, "audio/mp3") == 0 ||
215
+ strcasecmp(content_type, "audio/mpeg") == 0) {
216
+ return AudioFileType::MP3;
217
+ }
218
+ #endif
219
+ if (strcasecmp(content_type, "audio/wav") == 0) {
220
+ return AudioFileType::WAV;
221
+ }
222
+ #ifdef USE_AUDIO_FLAC_SUPPORT
223
+ if (strcasecmp(content_type, "audio/flac") == 0 || strcasecmp(content_type, "audio/x-flac") == 0) {
224
+ return AudioFileType::FLAC;
225
+ }
226
+ #endif
227
+ return AudioFileType::NONE;
228
+ }
229
+
230
+ esp_err_t AudioReader::http_event_handler(esp_http_client_event_t *evt) {
231
+ // Based on https://github.com/maroc81/WeatherLily/tree/main/main/net accessed 20241224
232
+ AudioReader *this_reader = (AudioReader *) evt->user_data;
233
+
234
+ switch (evt->event_id) {
235
+ case HTTP_EVENT_ON_HEADER:
236
+ if (strcasecmp(evt->header_key, "Content-Type") == 0) {
237
+ this_reader->audio_file_type_ = get_audio_type(evt->header_value);
238
+ }
239
+ break;
240
+ default:
241
+ break;
242
+ }
243
+ return ESP_OK;
244
+ }
245
+
246
+ AudioReaderState AudioReader::file_read_() {
247
+ size_t remaining_bytes = this->current_audio_file_->length - (this->file_current_ - this->current_audio_file_->data);
248
+ if (remaining_bytes > 0) {
249
+ size_t bytes_written = this->file_ring_buffer_->write_without_replacement(this->file_current_, remaining_bytes,
250
+ pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
251
+ this->file_current_ += bytes_written;
252
+
253
+ return AudioReaderState::READING;
254
+ }
255
+
256
+ return AudioReaderState::FINISHED;
257
+ }
258
+
259
+ AudioReaderState AudioReader::http_read_() {
260
+ this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
261
+
262
+ if (esp_http_client_is_complete_data_received(this->client_)) {
263
+ if (this->output_transfer_buffer_->available() == 0) {
264
+ this->cleanup_connection_();
265
+ return AudioReaderState::FINISHED;
266
+ }
267
+ } else {
268
+ size_t bytes_to_read = this->output_transfer_buffer_->free();
269
+ int received_len =
270
+ esp_http_client_read(this->client_, (char *) this->output_transfer_buffer_->get_buffer_end(), bytes_to_read);
271
+
272
+ if (received_len > 0) {
273
+ this->output_transfer_buffer_->increase_buffer_length(received_len);
274
+
275
+ this->no_data_read_count_ = 0;
276
+ } else if (received_len < 0) {
277
+ // HTTP read error
278
+ this->cleanup_connection_();
279
+ return AudioReaderState::FAILED;
280
+ } else {
281
+ if (bytes_to_read > 0) {
282
+ // Read timed out
283
+ ++this->no_data_read_count_;
284
+ if (this->no_data_read_count_ >= ERROR_COUNT_NO_DATA_READ_TIMEOUT) {
285
+ // Timed out with no data read too many times, so the http read has failed
286
+ this->cleanup_connection_();
287
+ return AudioReaderState::FAILED;
288
+ }
289
+ delay(READ_WRITE_TIMEOUT_MS);
290
+ }
291
+ }
292
+ }
293
+
294
+ return AudioReaderState::READING;
295
+ }
296
+
297
+ void AudioReader::cleanup_connection_() {
298
+ if (this->client_ != nullptr) {
299
+ esp_http_client_close(this->client_);
300
+ esp_http_client_cleanup(this->client_);
301
+ this->client_ = nullptr;
302
+ }
303
+ }
304
+
305
+ } // namespace audio
306
+ } // namespace esphome
307
+
308
+ #endif
@@ -0,0 +1,85 @@
1
+ #pragma once
2
+
3
+ #ifdef USE_ESP_IDF
4
+
5
+ #include "audio.h"
6
+ #include "audio_transfer_buffer.h"
7
+
8
+ #include "esphome/core/ring_buffer.h"
9
+
10
+ #include "esp_err.h"
11
+
12
+ #include <esp_http_client.h>
13
+
14
+ namespace esphome {
15
+ namespace audio {
16
+
17
+ enum class AudioReaderState : uint8_t {
18
+ READING = 0, // More data is available to read
19
+ FINISHED, // All data has been read and transferred
20
+ FAILED, // Encountered an error
21
+ };
22
+
23
+ class AudioReader {
24
+ /*
25
+ * @brief Class that facilitates reading a raw audio file.
26
+ * Files can be read from flash (stored in a AudioFile struct) or from an http source.
27
+ * The file data is sent to a ring buffer sink.
28
+ */
29
+ public:
30
+ /// @brief Constructs an AudioReader object.
31
+ /// The transfer buffer isn't allocated here, but only if necessary (an http source) in the start function.
32
+ /// @param buffer_size Transfer buffer size in bytes.
33
+ AudioReader(size_t buffer_size) : buffer_size_(buffer_size) {}
34
+ ~AudioReader();
35
+
36
+ /// @brief Adds a sink ring buffer for audio data. Takes ownership of the ring buffer in a shared_ptr
37
+ /// @param output_ring_buffer weak_ptr of a shared_ptr of the sink ring buffer to transfer ownership
38
+ /// @return ESP_OK if successful, ESP_ERR_INVALID_STATE otherwise
39
+ esp_err_t add_sink(const std::weak_ptr<RingBuffer> &output_ring_buffer);
40
+
41
+ /// @brief Starts reading an audio file from an http source. The transfer buffer is allocated here.
42
+ /// @param uri Web url to the http file.
43
+ /// @param file_type AudioFileType variable passed-by-reference indicating the type of file being read.
44
+ /// @return ESP_OK if successful, an ESP_ERR* code otherwise.
45
+ esp_err_t start(const std::string &uri, AudioFileType &file_type);
46
+
47
+ /// @brief Starts reading an audio file from flash. No transfer buffer is allocated.
48
+ /// @param audio_file AudioFile struct containing the file.
49
+ /// @param file_type AudioFileType variable passed-by-reference indicating the type of file being read.
50
+ /// @return ESP_OK
51
+ esp_err_t start(AudioFile *audio_file, AudioFileType &file_type);
52
+
53
+ /// @brief Reads new file data from the source and sends to the ring buffer sink.
54
+ /// @return AudioReaderState
55
+ AudioReaderState read();
56
+
57
+ protected:
58
+ /// @brief Monitors the http client events to attempt determining the file type from the Content-Type header
59
+ static esp_err_t http_event_handler(esp_http_client_event_t *evt);
60
+
61
+ /// @brief Determines the audio file type from the http header's Content-Type key
62
+ /// @param content_type string with the Content-Type key
63
+ /// @return AudioFileType of the url, if it can be determined. If not, return AudioFileType::NONE.
64
+ static AudioFileType get_audio_type(const char *content_type);
65
+
66
+ AudioReaderState file_read_();
67
+ AudioReaderState http_read_();
68
+
69
+ std::shared_ptr<RingBuffer> file_ring_buffer_;
70
+ std::unique_ptr<AudioSinkTransferBuffer> output_transfer_buffer_;
71
+ void cleanup_connection_();
72
+
73
+ size_t buffer_size_;
74
+ uint32_t no_data_read_count_;
75
+
76
+ esp_http_client_handle_t client_{nullptr};
77
+
78
+ AudioFile *current_audio_file_{nullptr};
79
+ AudioFileType audio_file_type_{AudioFileType::NONE};
80
+ const uint8_t *file_current_{nullptr};
81
+ };
82
+ } // namespace audio
83
+ } // namespace esphome
84
+
85
+ #endif
@@ -0,0 +1,159 @@
1
+ #include "audio_resampler.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 READ_WRITE_TIMEOUT_MS = 20;
11
+
12
+ AudioResampler::AudioResampler(size_t input_buffer_size, size_t output_buffer_size)
13
+ : input_buffer_size_(input_buffer_size), output_buffer_size_(output_buffer_size) {
14
+ this->input_transfer_buffer_ = AudioSourceTransferBuffer::create(input_buffer_size);
15
+ this->output_transfer_buffer_ = AudioSinkTransferBuffer::create(output_buffer_size);
16
+ }
17
+
18
+ esp_err_t AudioResampler::add_source(std::weak_ptr<RingBuffer> &input_ring_buffer) {
19
+ if (this->input_transfer_buffer_ != nullptr) {
20
+ this->input_transfer_buffer_->set_source(input_ring_buffer);
21
+ return ESP_OK;
22
+ }
23
+ return ESP_ERR_NO_MEM;
24
+ }
25
+
26
+ esp_err_t AudioResampler::add_sink(std::weak_ptr<RingBuffer> &output_ring_buffer) {
27
+ if (this->output_transfer_buffer_ != nullptr) {
28
+ this->output_transfer_buffer_->set_sink(output_ring_buffer);
29
+ return ESP_OK;
30
+ }
31
+ return ESP_ERR_NO_MEM;
32
+ }
33
+
34
+ #ifdef USE_SPEAKER
35
+ esp_err_t AudioResampler::add_sink(speaker::Speaker *speaker) {
36
+ if (this->output_transfer_buffer_ != nullptr) {
37
+ this->output_transfer_buffer_->set_sink(speaker);
38
+ return ESP_OK;
39
+ }
40
+ return ESP_ERR_NO_MEM;
41
+ }
42
+ #endif
43
+
44
+ esp_err_t AudioResampler::start(AudioStreamInfo &input_stream_info, AudioStreamInfo &output_stream_info,
45
+ uint16_t number_of_taps, uint16_t number_of_filters) {
46
+ this->input_stream_info_ = input_stream_info;
47
+ this->output_stream_info_ = output_stream_info;
48
+
49
+ if ((this->input_transfer_buffer_ == nullptr) || (this->output_transfer_buffer_ == nullptr)) {
50
+ return ESP_ERR_NO_MEM;
51
+ }
52
+
53
+ if ((input_stream_info.get_bits_per_sample() > 32) || (output_stream_info.get_bits_per_sample() > 32) ||
54
+ (input_stream_info_.get_channels() != output_stream_info.get_channels())) {
55
+ return ESP_ERR_NOT_SUPPORTED;
56
+ }
57
+
58
+ if ((input_stream_info.get_sample_rate() != output_stream_info.get_sample_rate()) ||
59
+ (input_stream_info.get_bits_per_sample() != output_stream_info.get_bits_per_sample())) {
60
+ this->resampler_ = make_unique<esp_audio_libs::resampler::Resampler>(
61
+ input_stream_info.bytes_to_samples(this->input_buffer_size_),
62
+ output_stream_info.bytes_to_samples(this->output_buffer_size_));
63
+
64
+ // Use cascaded biquad filters when downsampling to avoid aliasing
65
+ bool use_pre_filter = output_stream_info.get_sample_rate() < input_stream_info.get_sample_rate();
66
+
67
+ esp_audio_libs::resampler::ResamplerConfiguration resample_config = {
68
+ .source_sample_rate = static_cast<float>(input_stream_info.get_sample_rate()),
69
+ .target_sample_rate = static_cast<float>(output_stream_info.get_sample_rate()),
70
+ .source_bits_per_sample = input_stream_info.get_bits_per_sample(),
71
+ .target_bits_per_sample = output_stream_info.get_bits_per_sample(),
72
+ .channels = input_stream_info_.get_channels(),
73
+ .use_pre_or_post_filter = use_pre_filter,
74
+ .subsample_interpolate = false, // Doubles the CPU load. Using more filters is a better alternative
75
+ .number_of_taps = number_of_taps,
76
+ .number_of_filters = number_of_filters,
77
+ };
78
+
79
+ if (!this->resampler_->initialize(resample_config)) {
80
+ // Failed to allocate the resampler's internal buffers
81
+ return ESP_ERR_NO_MEM;
82
+ }
83
+ }
84
+
85
+ return ESP_OK;
86
+ }
87
+
88
+ AudioResamplerState AudioResampler::resample(bool stop_gracefully, int32_t *ms_differential) {
89
+ if (stop_gracefully) {
90
+ if (!this->input_transfer_buffer_->has_buffered_data() && (this->output_transfer_buffer_->available() == 0)) {
91
+ return AudioResamplerState::FINISHED;
92
+ }
93
+ }
94
+
95
+ if (!this->pause_output_) {
96
+ // Move audio data to the sink
97
+ this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
98
+ } else {
99
+ // If paused, block to avoid wasting CPU resources
100
+ delay(READ_WRITE_TIMEOUT_MS);
101
+ }
102
+
103
+ this->input_transfer_buffer_->transfer_data_from_source(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
104
+
105
+ if (this->input_transfer_buffer_->available() == 0) {
106
+ // No samples available to process
107
+ return AudioResamplerState::RESAMPLING;
108
+ }
109
+
110
+ const size_t bytes_free = this->output_transfer_buffer_->free();
111
+ const uint32_t frames_free = this->output_stream_info_.bytes_to_frames(bytes_free);
112
+
113
+ const size_t bytes_available = this->input_transfer_buffer_->available();
114
+ const uint32_t frames_available = this->input_stream_info_.bytes_to_frames(bytes_available);
115
+
116
+ if ((this->input_stream_info_.get_sample_rate() != this->output_stream_info_.get_sample_rate()) ||
117
+ (this->input_stream_info_.get_bits_per_sample() != this->output_stream_info_.get_bits_per_sample())) {
118
+ esp_audio_libs::resampler::ResamplerResults results =
119
+ this->resampler_->resample(this->input_transfer_buffer_->get_buffer_start(),
120
+ this->output_transfer_buffer_->get_buffer_end(), frames_available, frames_free, -3);
121
+
122
+ this->input_transfer_buffer_->decrease_buffer_length(this->input_stream_info_.frames_to_bytes(results.frames_used));
123
+ this->output_transfer_buffer_->increase_buffer_length(
124
+ this->output_stream_info_.frames_to_bytes(results.frames_generated));
125
+
126
+ // Resampling causes slight differences in the durations used versus generated. Computes the difference in
127
+ // millisconds. The callback function passing the played audio duration uses the difference to convert from output
128
+ // duration to input duration.
129
+ this->accumulated_frames_used_ += results.frames_used;
130
+ this->accumulated_frames_generated_ += results.frames_generated;
131
+
132
+ const int32_t used_ms =
133
+ this->input_stream_info_.frames_to_milliseconds_with_remainder(&this->accumulated_frames_used_);
134
+ const int32_t generated_ms =
135
+ this->output_stream_info_.frames_to_milliseconds_with_remainder(&this->accumulated_frames_generated_);
136
+
137
+ *ms_differential = used_ms - generated_ms;
138
+
139
+ } else {
140
+ // No resampling required, copy samples directly to the output transfer buffer
141
+ *ms_differential = 0;
142
+
143
+ const size_t bytes_to_transfer = std::min(this->output_stream_info_.frames_to_bytes(frames_free),
144
+ this->input_stream_info_.frames_to_bytes(frames_available));
145
+
146
+ std::memcpy((void *) this->output_transfer_buffer_->get_buffer_end(),
147
+ (void *) this->input_transfer_buffer_->get_buffer_start(), bytes_to_transfer);
148
+
149
+ this->input_transfer_buffer_->decrease_buffer_length(bytes_to_transfer);
150
+ this->output_transfer_buffer_->increase_buffer_length(bytes_to_transfer);
151
+ }
152
+
153
+ return AudioResamplerState::RESAMPLING;
154
+ }
155
+
156
+ } // namespace audio
157
+ } // namespace esphome
158
+
159
+ #endif
@@ -0,0 +1,101 @@
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/ring_buffer.h"
10
+
11
+ #ifdef USE_SPEAKER
12
+ #include "esphome/components/speaker/speaker.h"
13
+ #endif
14
+
15
+ #include "esp_err.h"
16
+
17
+ #include <resampler.h> // esp-audio-libs
18
+
19
+ namespace esphome {
20
+ namespace audio {
21
+
22
+ enum class AudioResamplerState : uint8_t {
23
+ RESAMPLING, // More data is available to resample
24
+ FINISHED, // All file data has been resampled and transferred
25
+ FAILED, // Unused state included for consistency among Audio classes
26
+ };
27
+
28
+ class AudioResampler {
29
+ /*
30
+ * @brief Class that facilitates resampling audio.
31
+ * The audio data is read from a ring buffer source, resampled, and sent to an audio sink (ring buffer or speaker
32
+ * component). Also supports converting bits per sample.
33
+ */
34
+ public:
35
+ /// @brief Allocates the input and output transfer buffers
36
+ /// @param input_buffer_size Size of the input transfer buffer in bytes.
37
+ /// @param output_buffer_size Size of the output transfer buffer in bytes.
38
+ AudioResampler(size_t input_buffer_size, size_t output_buffer_size);
39
+
40
+ /// @brief Adds a source ring buffer for audio data. Takes ownership of the ring buffer in a shared_ptr.
41
+ /// @param input_ring_buffer weak_ptr of a shared_ptr of the sink ring buffer to transfer ownership
42
+ /// @return ESP_OK if successsful, ESP_ERR_NO_MEM if the transfer buffer wasn't allocated
43
+ esp_err_t add_source(std::weak_ptr<RingBuffer> &input_ring_buffer);
44
+
45
+ /// @brief Adds a sink ring buffer for resampled audio. Takes ownership of the ring buffer in a shared_ptr.
46
+ /// @param output_ring_buffer weak_ptr of a shared_ptr of the sink ring buffer to transfer ownership
47
+ /// @return ESP_OK if successsful, ESP_ERR_NO_MEM if the transfer buffer wasn't allocated
48
+ esp_err_t add_sink(std::weak_ptr<RingBuffer> &output_ring_buffer);
49
+
50
+ #ifdef USE_SPEAKER
51
+ /// @brief Adds a sink speaker for decoded audio.
52
+ /// @param speaker pointer to speaker component
53
+ /// @return ESP_OK if successsful, ESP_ERR_NO_MEM if the transfer buffer wasn't allocated
54
+ esp_err_t add_sink(speaker::Speaker *speaker);
55
+ #endif
56
+
57
+ /// @brief Sets up the class to resample.
58
+ /// @param input_stream_info The incoming sample rate, bits per sample, and number of channels
59
+ /// @param output_stream_info The desired outgoing sample rate, bits per sample, and number of channels
60
+ /// @param number_of_taps Number of taps per FIR filter
61
+ /// @param number_of_filters Number of FIR filters
62
+ /// @return ESP_OK if it is able to convert the incoming stream,
63
+ /// ESP_ERR_NO_MEM if the transfer buffers failed to allocate,
64
+ /// ESP_ERR_NOT_SUPPORTED if the stream can't be converted.
65
+ esp_err_t start(AudioStreamInfo &input_stream_info, AudioStreamInfo &output_stream_info, uint16_t number_of_taps,
66
+ uint16_t number_of_filters);
67
+
68
+ /// @brief Resamples audio from the ring buffer source and writes to the sink.
69
+ /// @param stop_gracefully If true, it indicates the file decoder is finished. The resampler will resample all the
70
+ /// remaining audio and then finish.
71
+ /// @param ms_differential Pointer to a (int32_t) variable that will store the difference, in milliseconds, between
72
+ /// the duration of input audio used and the duration of output audio generated.
73
+ /// @return AudioResamplerState
74
+ AudioResamplerState resample(bool stop_gracefully, int32_t *ms_differential);
75
+
76
+ /// @brief Pauses sending resampled audio to the sink. If paused, it will continue to process internal buffers.
77
+ /// @param pause_state If true, audio data is not sent to the sink.
78
+ void set_pause_output_state(bool pause_state) { this->pause_output_ = pause_state; }
79
+
80
+ protected:
81
+ std::unique_ptr<AudioSourceTransferBuffer> input_transfer_buffer_;
82
+ std::unique_ptr<AudioSinkTransferBuffer> output_transfer_buffer_;
83
+
84
+ size_t input_buffer_size_;
85
+ size_t output_buffer_size_;
86
+
87
+ uint32_t accumulated_frames_used_{0};
88
+ uint32_t accumulated_frames_generated_{0};
89
+
90
+ bool pause_output_{false};
91
+
92
+ AudioStreamInfo input_stream_info_;
93
+ AudioStreamInfo output_stream_info_;
94
+
95
+ std::unique_ptr<esp_audio_libs::resampler::Resampler> resampler_;
96
+ };
97
+
98
+ } // namespace audio
99
+ } // namespace esphome
100
+
101
+ #endif