esphome 2024.12.4__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.4.dist-info → esphome-2025.2.0b1.dist-info}/METADATA +12 -7
  329. {esphome-2024.12.4.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.4.dist-info → esphome-2025.2.0b1.dist-info}/LICENSE +0 -0
  353. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/WHEEL +0 -0
  354. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/entry_points.txt +0 -0
  355. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,568 @@
1
+ #include "audio_pipeline.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
+ #include "esphome/core/log.h"
9
+
10
+ namespace esphome {
11
+ namespace speaker {
12
+
13
+ static const uint32_t INITIAL_BUFFER_MS = 1000; // Start playback after buffering this duration of the file
14
+
15
+ static const uint32_t READ_TASK_STACK_SIZE = 5 * 1024;
16
+ static const uint32_t DECODE_TASK_STACK_SIZE = 3 * 1024;
17
+
18
+ static const uint32_t INFO_ERROR_QUEUE_COUNT = 5;
19
+
20
+ static const char *const TAG = "speaker_media_player.pipeline";
21
+
22
+ enum EventGroupBits : uint32_t {
23
+ // MESSAGE_* bits are only set by their respective tasks
24
+
25
+ // Stops all activity in the pipeline elements; cleared by process_state() and set by stop() or by each task
26
+ PIPELINE_COMMAND_STOP = (1 << 0),
27
+
28
+ // Read audio from an HTTP source; cleared by reader task and set by start_url
29
+ READER_COMMAND_INIT_HTTP = (1 << 4),
30
+ // Read audio from an audio file from the flash; cleared by reader task and set by start_file
31
+ READER_COMMAND_INIT_FILE = (1 << 5),
32
+
33
+ // Audio file type is read after checking it is supported; cleared by decoder task
34
+ READER_MESSAGE_LOADED_MEDIA_TYPE = (1 << 6),
35
+ // Reader is done (either through a failure or just end of the stream); cleared by reader task
36
+ READER_MESSAGE_FINISHED = (1 << 7),
37
+ // Error reading the file; cleared by process_state()
38
+ READER_MESSAGE_ERROR = (1 << 8),
39
+
40
+ // Decoder is done (either through a faiilure or the end of the stream); cleared by decoder task
41
+ DECODER_MESSAGE_FINISHED = (1 << 12),
42
+ // Error decoding the file; cleared by process_state() by decoder task
43
+ DECODER_MESSAGE_ERROR = (1 << 13),
44
+ };
45
+
46
+ AudioPipeline::AudioPipeline(speaker::Speaker *speaker, size_t buffer_size, bool task_stack_in_psram,
47
+ std::string base_name, UBaseType_t priority)
48
+ : base_name_(std::move(base_name)),
49
+ priority_(priority),
50
+ task_stack_in_psram_(task_stack_in_psram),
51
+ speaker_(speaker),
52
+ buffer_size_(buffer_size) {
53
+ this->allocate_communications_();
54
+ this->transfer_buffer_size_ = std::min(buffer_size_ / 4, DEFAULT_TRANSFER_BUFFER_SIZE);
55
+ }
56
+
57
+ void AudioPipeline::start_url(const std::string &uri) {
58
+ if (this->is_playing_) {
59
+ xEventGroupSetBits(this->event_group_, PIPELINE_COMMAND_STOP);
60
+ }
61
+ this->current_uri_ = uri;
62
+ this->pending_url_ = true;
63
+ }
64
+
65
+ void AudioPipeline::start_file(audio::AudioFile *audio_file) {
66
+ if (this->is_playing_) {
67
+ xEventGroupSetBits(this->event_group_, PIPELINE_COMMAND_STOP);
68
+ }
69
+ this->current_audio_file_ = audio_file;
70
+ this->pending_file_ = true;
71
+ }
72
+
73
+ esp_err_t AudioPipeline::stop() {
74
+ xEventGroupSetBits(this->event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
75
+
76
+ return ESP_OK;
77
+ }
78
+ void AudioPipeline::set_pause_state(bool pause_state) {
79
+ this->speaker_->set_pause_state(pause_state);
80
+
81
+ this->pause_state_ = pause_state;
82
+ }
83
+
84
+ void AudioPipeline::suspend_tasks() {
85
+ if (this->read_task_handle_ != nullptr) {
86
+ vTaskSuspend(this->read_task_handle_);
87
+ }
88
+ if (this->decode_task_handle_ != nullptr) {
89
+ vTaskSuspend(this->decode_task_handle_);
90
+ }
91
+ }
92
+
93
+ void AudioPipeline::resume_tasks() {
94
+ if (this->read_task_handle_ != nullptr) {
95
+ vTaskResume(this->read_task_handle_);
96
+ }
97
+ if (this->decode_task_handle_ != nullptr) {
98
+ vTaskResume(this->decode_task_handle_);
99
+ }
100
+ }
101
+
102
+ AudioPipelineState AudioPipeline::process_state() {
103
+ /*
104
+ * Log items from info error queue
105
+ */
106
+ InfoErrorEvent event;
107
+ if (this->info_error_queue_ != nullptr) {
108
+ while (xQueueReceive(this->info_error_queue_, &event, 0)) {
109
+ switch (event.source) {
110
+ case InfoErrorSource::READER:
111
+ if (event.err.has_value()) {
112
+ ESP_LOGE(TAG, "Media reader encountered an error: %s", esp_err_to_name(event.err.value()));
113
+ } else if (event.file_type.has_value()) {
114
+ ESP_LOGD(TAG, "Reading %s file type", audio_file_type_to_string(event.file_type.value()));
115
+ }
116
+
117
+ break;
118
+ case InfoErrorSource::DECODER:
119
+ if (event.err.has_value()) {
120
+ ESP_LOGE(TAG, "Decoder encountered an error: %s", esp_err_to_name(event.err.value()));
121
+ }
122
+
123
+ if (event.audio_stream_info.has_value()) {
124
+ ESP_LOGD(TAG, "Decoded audio has %d channels, %" PRId32 " Hz sample rate, and %d bits per sample",
125
+ event.audio_stream_info.value().get_channels(), event.audio_stream_info.value().get_sample_rate(),
126
+ event.audio_stream_info.value().get_bits_per_sample());
127
+ }
128
+
129
+ if (event.decoding_err.has_value()) {
130
+ switch (event.decoding_err.value()) {
131
+ case DecodingError::FAILED_HEADER:
132
+ ESP_LOGE(TAG, "Failed to parse the file's header.");
133
+ break;
134
+ case DecodingError::INCOMPATIBLE_BITS_PER_SAMPLE:
135
+ ESP_LOGE(TAG, "Incompatible bits per sample. Only 16 bits per sample is supported");
136
+ break;
137
+ case DecodingError::INCOMPATIBLE_CHANNELS:
138
+ ESP_LOGE(TAG, "Incompatible number of channels. Only 1 or 2 channel audio is supported.");
139
+ break;
140
+ }
141
+ }
142
+ break;
143
+ }
144
+ }
145
+ }
146
+
147
+ /*
148
+ * Determine the current state based on the event group bits and tasks' status
149
+ */
150
+
151
+ EventBits_t event_bits = xEventGroupGetBits(this->event_group_);
152
+
153
+ if (this->pending_url_ || this->pending_file_) {
154
+ // Init command pending
155
+ if (!(event_bits & EventGroupBits::PIPELINE_COMMAND_STOP)) {
156
+ // Only start if there is no pending stop command
157
+ if ((this->read_task_handle_ == nullptr) || (this->decode_task_handle_ == nullptr)) {
158
+ // At least one task isn't running
159
+ this->start_tasks_();
160
+ }
161
+
162
+ if (this->pending_url_) {
163
+ xEventGroupSetBits(this->event_group_, EventGroupBits::READER_COMMAND_INIT_HTTP);
164
+ this->playback_ms_ = 0;
165
+ this->pending_url_ = false;
166
+ } else if (this->pending_file_) {
167
+ xEventGroupSetBits(this->event_group_, EventGroupBits::READER_COMMAND_INIT_FILE);
168
+ this->playback_ms_ = 0;
169
+ this->pending_file_ = false;
170
+ }
171
+
172
+ this->is_playing_ = true;
173
+ return AudioPipelineState::PLAYING;
174
+ }
175
+ }
176
+
177
+ if ((event_bits & EventGroupBits::READER_MESSAGE_FINISHED) &&
178
+ (!(event_bits & EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE) &&
179
+ (event_bits & EventGroupBits::DECODER_MESSAGE_FINISHED))) {
180
+ // Tasks are finished and there's no media in between the reader and decoder
181
+
182
+ if (event_bits & EventGroupBits::PIPELINE_COMMAND_STOP) {
183
+ // Stop command is fully processed, so clear the command bit
184
+ xEventGroupClearBits(this->event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
185
+ this->hard_stop_ = true;
186
+ }
187
+
188
+ if (!this->is_playing_) {
189
+ // The tasks have been stopped for two ``process_state`` calls in a row, so delete the tasks
190
+ if ((this->read_task_handle_ != nullptr) || (this->decode_task_handle_ != nullptr)) {
191
+ this->delete_tasks_();
192
+ if (this->hard_stop_) {
193
+ // Stop command was sent, so immediately end of the playback
194
+ this->speaker_->stop();
195
+ this->hard_stop_ = false;
196
+ } else {
197
+ // Decoded all the audio, so let the speaker finish playing before stopping
198
+ this->speaker_->finish();
199
+ }
200
+ }
201
+ }
202
+ this->is_playing_ = false;
203
+ return AudioPipelineState::STOPPED;
204
+ }
205
+
206
+ if ((event_bits & EventGroupBits::READER_MESSAGE_ERROR)) {
207
+ xEventGroupClearBits(this->event_group_, EventGroupBits::READER_MESSAGE_ERROR);
208
+ return AudioPipelineState::ERROR_READING;
209
+ }
210
+
211
+ if ((event_bits & EventGroupBits::DECODER_MESSAGE_ERROR)) {
212
+ xEventGroupClearBits(this->event_group_, EventGroupBits::DECODER_MESSAGE_ERROR);
213
+ return AudioPipelineState::ERROR_DECODING;
214
+ }
215
+
216
+ if (this->pause_state_) {
217
+ return AudioPipelineState::PAUSED;
218
+ }
219
+
220
+ if ((this->read_task_handle_ == nullptr) && (this->decode_task_handle_ == nullptr)) {
221
+ // No tasks are running, so the pipeline is stopped.
222
+ xEventGroupClearBits(this->event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
223
+ return AudioPipelineState::STOPPED;
224
+ }
225
+
226
+ this->is_playing_ = true;
227
+ return AudioPipelineState::PLAYING;
228
+ }
229
+
230
+ esp_err_t AudioPipeline::allocate_communications_() {
231
+ if (this->event_group_ == nullptr)
232
+ this->event_group_ = xEventGroupCreate();
233
+
234
+ if (this->event_group_ == nullptr) {
235
+ return ESP_ERR_NO_MEM;
236
+ }
237
+
238
+ if (this->info_error_queue_ == nullptr)
239
+ this->info_error_queue_ = xQueueCreate(INFO_ERROR_QUEUE_COUNT, sizeof(InfoErrorEvent));
240
+
241
+ if (this->info_error_queue_ == nullptr)
242
+ return ESP_ERR_NO_MEM;
243
+
244
+ return ESP_OK;
245
+ }
246
+
247
+ esp_err_t AudioPipeline::start_tasks_() {
248
+ if (this->read_task_handle_ == nullptr) {
249
+ if (this->read_task_stack_buffer_ == nullptr) {
250
+ if (this->task_stack_in_psram_) {
251
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_EXTERNAL);
252
+ this->read_task_stack_buffer_ = stack_allocator.allocate(READ_TASK_STACK_SIZE);
253
+ } else {
254
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_INTERNAL);
255
+ this->read_task_stack_buffer_ = stack_allocator.allocate(READ_TASK_STACK_SIZE);
256
+ }
257
+ }
258
+
259
+ if (this->read_task_stack_buffer_ == nullptr) {
260
+ return ESP_ERR_NO_MEM;
261
+ }
262
+
263
+ if (this->read_task_handle_ == nullptr) {
264
+ this->read_task_handle_ =
265
+ xTaskCreateStatic(read_task, (this->base_name_ + "_read").c_str(), READ_TASK_STACK_SIZE, (void *) this,
266
+ this->priority_, this->read_task_stack_buffer_, &this->read_task_stack_);
267
+ }
268
+
269
+ if (this->read_task_handle_ == nullptr) {
270
+ return ESP_ERR_INVALID_STATE;
271
+ }
272
+ }
273
+
274
+ if (this->decode_task_handle_ == nullptr) {
275
+ if (this->decode_task_stack_buffer_ == nullptr) {
276
+ if (this->task_stack_in_psram_) {
277
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_EXTERNAL);
278
+ this->decode_task_stack_buffer_ = stack_allocator.allocate(DECODE_TASK_STACK_SIZE);
279
+ } else {
280
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_INTERNAL);
281
+ this->decode_task_stack_buffer_ = stack_allocator.allocate(DECODE_TASK_STACK_SIZE);
282
+ }
283
+ }
284
+
285
+ if (this->decode_task_stack_buffer_ == nullptr) {
286
+ return ESP_ERR_NO_MEM;
287
+ }
288
+
289
+ if (this->decode_task_handle_ == nullptr) {
290
+ this->decode_task_handle_ =
291
+ xTaskCreateStatic(decode_task, (this->base_name_ + "_decode").c_str(), DECODE_TASK_STACK_SIZE, (void *) this,
292
+ this->priority_, this->decode_task_stack_buffer_, &this->decode_task_stack_);
293
+ }
294
+
295
+ if (this->decode_task_handle_ == nullptr) {
296
+ return ESP_ERR_INVALID_STATE;
297
+ }
298
+ }
299
+
300
+ return ESP_OK;
301
+ }
302
+
303
+ void AudioPipeline::delete_tasks_() {
304
+ if (this->read_task_handle_ != nullptr) {
305
+ vTaskDelete(this->read_task_handle_);
306
+
307
+ if (this->read_task_stack_buffer_ != nullptr) {
308
+ if (this->task_stack_in_psram_) {
309
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_EXTERNAL);
310
+ stack_allocator.deallocate(this->read_task_stack_buffer_, READ_TASK_STACK_SIZE);
311
+ } else {
312
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_INTERNAL);
313
+ stack_allocator.deallocate(this->read_task_stack_buffer_, READ_TASK_STACK_SIZE);
314
+ }
315
+
316
+ this->read_task_stack_buffer_ = nullptr;
317
+ this->read_task_handle_ = nullptr;
318
+ }
319
+ }
320
+
321
+ if (this->decode_task_handle_ != nullptr) {
322
+ vTaskDelete(this->decode_task_handle_);
323
+
324
+ if (this->decode_task_stack_buffer_ != nullptr) {
325
+ if (this->task_stack_in_psram_) {
326
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_EXTERNAL);
327
+ stack_allocator.deallocate(this->decode_task_stack_buffer_, DECODE_TASK_STACK_SIZE);
328
+ } else {
329
+ RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_INTERNAL);
330
+ stack_allocator.deallocate(this->decode_task_stack_buffer_, DECODE_TASK_STACK_SIZE);
331
+ }
332
+
333
+ this->decode_task_stack_buffer_ = nullptr;
334
+ this->decode_task_handle_ = nullptr;
335
+ }
336
+ }
337
+ }
338
+
339
+ void AudioPipeline::read_task(void *params) {
340
+ AudioPipeline *this_pipeline = (AudioPipeline *) params;
341
+
342
+ while (true) {
343
+ xEventGroupSetBits(this_pipeline->event_group_, EventGroupBits::READER_MESSAGE_FINISHED);
344
+
345
+ // Wait until the pipeline notifies us the source of the media file
346
+ EventBits_t event_bits =
347
+ xEventGroupWaitBits(this_pipeline->event_group_,
348
+ EventGroupBits::READER_COMMAND_INIT_FILE | EventGroupBits::READER_COMMAND_INIT_HTTP |
349
+ EventGroupBits::PIPELINE_COMMAND_STOP, // Bit message to read
350
+ pdFALSE, // Clear the bit on exit
351
+ pdFALSE, // Wait for all the bits,
352
+ portMAX_DELAY); // Block indefinitely until bit is set
353
+
354
+ if (!(event_bits & EventGroupBits::PIPELINE_COMMAND_STOP)) {
355
+ xEventGroupClearBits(this_pipeline->event_group_, EventGroupBits::READER_MESSAGE_FINISHED |
356
+ EventGroupBits::READER_COMMAND_INIT_FILE |
357
+ EventGroupBits::READER_COMMAND_INIT_HTTP);
358
+ InfoErrorEvent event;
359
+ event.source = InfoErrorSource::READER;
360
+ esp_err_t err = ESP_OK;
361
+
362
+ std::unique_ptr<audio::AudioReader> reader =
363
+ make_unique<audio::AudioReader>(this_pipeline->transfer_buffer_size_);
364
+
365
+ if (event_bits & EventGroupBits::READER_COMMAND_INIT_FILE) {
366
+ err = reader->start(this_pipeline->current_audio_file_, this_pipeline->current_audio_file_type_);
367
+ } else {
368
+ err = reader->start(this_pipeline->current_uri_, this_pipeline->current_audio_file_type_);
369
+ }
370
+
371
+ if (err == ESP_OK) {
372
+ size_t file_ring_buffer_size = this_pipeline->buffer_size_;
373
+
374
+ std::shared_ptr<RingBuffer> temp_ring_buffer;
375
+
376
+ if (!this_pipeline->raw_file_ring_buffer_.use_count()) {
377
+ temp_ring_buffer = RingBuffer::create(file_ring_buffer_size);
378
+ this_pipeline->raw_file_ring_buffer_ = temp_ring_buffer;
379
+ }
380
+
381
+ if (!this_pipeline->raw_file_ring_buffer_.use_count()) {
382
+ err = ESP_ERR_NO_MEM;
383
+ } else {
384
+ reader->add_sink(this_pipeline->raw_file_ring_buffer_);
385
+ }
386
+ }
387
+
388
+ if (err != ESP_OK) {
389
+ // Send specific error message
390
+ event.err = err;
391
+ xQueueSend(this_pipeline->info_error_queue_, &event, portMAX_DELAY);
392
+
393
+ // Setting up the reader failed, stop the pipeline
394
+ xEventGroupSetBits(this_pipeline->event_group_,
395
+ EventGroupBits::READER_MESSAGE_ERROR | EventGroupBits::PIPELINE_COMMAND_STOP);
396
+ } else {
397
+ // Send the file type to the pipeline
398
+ event.file_type = this_pipeline->current_audio_file_type_;
399
+ xQueueSend(this_pipeline->info_error_queue_, &event, portMAX_DELAY);
400
+ xEventGroupSetBits(this_pipeline->event_group_, EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE);
401
+ }
402
+
403
+ while (true) {
404
+ event_bits = xEventGroupGetBits(this_pipeline->event_group_);
405
+
406
+ if (event_bits & EventGroupBits::PIPELINE_COMMAND_STOP) {
407
+ break;
408
+ }
409
+
410
+ audio::AudioReaderState reader_state = reader->read();
411
+
412
+ if (reader_state == audio::AudioReaderState::FINISHED) {
413
+ break;
414
+ } else if (reader_state == audio::AudioReaderState::FAILED) {
415
+ xEventGroupSetBits(this_pipeline->event_group_,
416
+ EventGroupBits::READER_MESSAGE_ERROR | EventGroupBits::PIPELINE_COMMAND_STOP);
417
+ break;
418
+ }
419
+ }
420
+ event_bits = xEventGroupGetBits(this_pipeline->event_group_);
421
+ if ((event_bits & EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE) ||
422
+ (this_pipeline->raw_file_ring_buffer_.use_count() == 1)) {
423
+ // Decoder task hasn't started yet, so delay a bit before releasing ownership of the ring buffer
424
+ delay(10);
425
+ }
426
+ }
427
+ }
428
+ }
429
+
430
+ void AudioPipeline::decode_task(void *params) {
431
+ AudioPipeline *this_pipeline = (AudioPipeline *) params;
432
+
433
+ while (true) {
434
+ xEventGroupSetBits(this_pipeline->event_group_, EventGroupBits::DECODER_MESSAGE_FINISHED);
435
+
436
+ // Wait until the reader notifies us that the media type is available
437
+ EventBits_t event_bits = xEventGroupWaitBits(this_pipeline->event_group_,
438
+ EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE |
439
+ EventGroupBits::PIPELINE_COMMAND_STOP, // Bit message to read
440
+ pdFALSE, // Clear the bit on exit
441
+ pdFALSE, // Wait for all the bits,
442
+ portMAX_DELAY); // Block indefinitely until bit is set
443
+
444
+ if (!(event_bits & EventGroupBits::PIPELINE_COMMAND_STOP)) {
445
+ xEventGroupClearBits(this_pipeline->event_group_,
446
+ EventGroupBits::DECODER_MESSAGE_FINISHED | EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE);
447
+ InfoErrorEvent event;
448
+ event.source = InfoErrorSource::DECODER;
449
+
450
+ std::unique_ptr<audio::AudioDecoder> decoder =
451
+ make_unique<audio::AudioDecoder>(this_pipeline->transfer_buffer_size_, this_pipeline->transfer_buffer_size_);
452
+
453
+ esp_err_t err = decoder->start(this_pipeline->current_audio_file_type_);
454
+ decoder->add_source(this_pipeline->raw_file_ring_buffer_);
455
+
456
+ if (err != ESP_OK) {
457
+ // Send specific error message
458
+ event.err = err;
459
+ xQueueSend(this_pipeline->info_error_queue_, &event, portMAX_DELAY);
460
+
461
+ // Setting up the decoder failed, stop the pipeline
462
+ xEventGroupSetBits(this_pipeline->event_group_,
463
+ EventGroupBits::DECODER_MESSAGE_ERROR | EventGroupBits::PIPELINE_COMMAND_STOP);
464
+ }
465
+
466
+ bool has_stream_info = false;
467
+ bool started_playback = false;
468
+
469
+ size_t initial_bytes_to_buffer = 0;
470
+
471
+ while (true) {
472
+ event_bits = xEventGroupGetBits(this_pipeline->event_group_);
473
+
474
+ if (event_bits & EventGroupBits::PIPELINE_COMMAND_STOP) {
475
+ break;
476
+ }
477
+
478
+ // Update pause state
479
+ if (!started_playback) {
480
+ if (!(event_bits & EventGroupBits::READER_MESSAGE_FINISHED)) {
481
+ decoder->set_pause_output_state(true);
482
+ } else {
483
+ started_playback = true;
484
+ }
485
+ } else {
486
+ decoder->set_pause_output_state(this_pipeline->pause_state_);
487
+ }
488
+
489
+ // Stop gracefully if the reader has finished
490
+ audio::AudioDecoderState decoder_state = decoder->decode(event_bits & EventGroupBits::READER_MESSAGE_FINISHED);
491
+
492
+ if ((decoder_state == audio::AudioDecoderState::DECODING) ||
493
+ (decoder_state == audio::AudioDecoderState::FINISHED)) {
494
+ this_pipeline->playback_ms_ = decoder->get_playback_ms();
495
+ }
496
+
497
+ if (decoder_state == audio::AudioDecoderState::FINISHED) {
498
+ break;
499
+ } else if (decoder_state == audio::AudioDecoderState::FAILED) {
500
+ if (!has_stream_info) {
501
+ event.decoding_err = DecodingError::FAILED_HEADER;
502
+ xQueueSend(this_pipeline->info_error_queue_, &event, portMAX_DELAY);
503
+ }
504
+ xEventGroupSetBits(this_pipeline->event_group_,
505
+ EventGroupBits::DECODER_MESSAGE_ERROR | EventGroupBits::PIPELINE_COMMAND_STOP);
506
+ break;
507
+ }
508
+
509
+ if (!has_stream_info && decoder->get_audio_stream_info().has_value()) {
510
+ has_stream_info = true;
511
+
512
+ this_pipeline->current_audio_stream_info_ = decoder->get_audio_stream_info().value();
513
+
514
+ // Send the stream information to the pipeline
515
+ event.audio_stream_info = this_pipeline->current_audio_stream_info_;
516
+
517
+ if (this_pipeline->current_audio_stream_info_.get_bits_per_sample() != 16) {
518
+ // Error state, incompatible bits per sample
519
+ event.decoding_err = DecodingError::INCOMPATIBLE_BITS_PER_SAMPLE;
520
+ xEventGroupSetBits(this_pipeline->event_group_,
521
+ EventGroupBits::DECODER_MESSAGE_ERROR | EventGroupBits::PIPELINE_COMMAND_STOP);
522
+ } else if ((this_pipeline->current_audio_stream_info_.get_channels() > 2)) {
523
+ // Error state, incompatible number of channels
524
+ event.decoding_err = DecodingError::INCOMPATIBLE_CHANNELS;
525
+ xEventGroupSetBits(this_pipeline->event_group_,
526
+ EventGroupBits::DECODER_MESSAGE_ERROR | EventGroupBits::PIPELINE_COMMAND_STOP);
527
+ } else {
528
+ // Send audio directly to the speaker
529
+ this_pipeline->speaker_->set_audio_stream_info(this_pipeline->current_audio_stream_info_);
530
+ decoder->add_sink(this_pipeline->speaker_);
531
+ }
532
+
533
+ initial_bytes_to_buffer = std::min(this_pipeline->current_audio_stream_info_.ms_to_bytes(INITIAL_BUFFER_MS),
534
+ this_pipeline->buffer_size_ * 3 / 4);
535
+
536
+ switch (this_pipeline->current_audio_file_type_) {
537
+ #ifdef USE_AUDIO_MP3_SUPPORT
538
+ case audio::AudioFileType::MP3:
539
+ initial_bytes_to_buffer /= 8; // Estimate the MP3 compression factor is 8
540
+ break;
541
+ #endif
542
+ #ifdef USE_AUDIO_FLAC_SUPPORT
543
+ case audio::AudioFileType::FLAC:
544
+ initial_bytes_to_buffer /= 2; // Estimate the FLAC compression factor is 2
545
+ break;
546
+ #endif
547
+ default:
548
+ break;
549
+ }
550
+ xQueueSend(this_pipeline->info_error_queue_, &event, portMAX_DELAY);
551
+ }
552
+
553
+ if (!started_playback && has_stream_info) {
554
+ // Verify enough data is available before starting playback
555
+ std::shared_ptr<RingBuffer> temp_ring_buffer = this_pipeline->raw_file_ring_buffer_.lock();
556
+ if (temp_ring_buffer->available() >= initial_bytes_to_buffer) {
557
+ started_playback = true;
558
+ }
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }
564
+
565
+ } // namespace speaker
566
+ } // namespace esphome
567
+
568
+ #endif