esphome 2024.10.3__py3-none-any.whl → 2024.11.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.
- esphome/__main__.py +22 -4
- esphome/automation.py +29 -2
- esphome/components/animation/__init__.py +5 -8
- esphome/components/animation/animation.cpp +1 -1
- esphome/components/audio/__init__.py +9 -0
- esphome/components/audio/audio.h +21 -0
- esphome/components/axs15231/__init__.py +6 -0
- esphome/components/axs15231/touchscreen/__init__.py +36 -0
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +64 -0
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.h +27 -0
- esphome/components/bme68x_bsec2/__init__.py +1 -1
- esphome/components/bytebuffer/__init__.py +5 -0
- esphome/components/bytebuffer/bytebuffer.h +421 -0
- esphome/components/climate/__init__.py +14 -13
- esphome/components/datetime/__init__.py +3 -3
- esphome/components/debug/debug_esp32.cpp +16 -8
- esphome/components/dfplayer/dfplayer.cpp +132 -6
- esphome/components/dfplayer/dfplayer.h +19 -53
- esphome/components/display/display.cpp +142 -0
- esphome/components/display/display.h +7 -0
- esphome/components/es8311/__init__.py +0 -0
- esphome/components/es8311/audio_dac.py +70 -0
- esphome/components/es8311/es8311.cpp +227 -0
- esphome/components/es8311/es8311.h +135 -0
- esphome/components/es8311/es8311_const.h +195 -0
- esphome/components/esp32/boards.py +199 -1
- esphome/components/esp32/gpio.py +3 -1
- esphome/components/esp32_ble/const_esp32c6.h +7 -0
- esphome/components/esp32_ble_client/ble_client_base.h +1 -1
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +2 -2
- esphome/components/esp32_rmt_led_strip/led_strip.h +2 -0
- esphome/components/esp32_rmt_led_strip/light.py +3 -1
- esphome/components/esp8266/gpio.py +7 -5
- esphome/components/ethernet/__init__.py +55 -1
- esphome/components/ethernet/ethernet_component.cpp +14 -1
- esphome/components/ethernet/ethernet_component.h +7 -1
- esphome/components/font/__init__.py +213 -108
- esphome/components/gp8403/output/__init__.py +1 -1
- esphome/components/host/gpio.py +6 -4
- esphome/components/http_request/__init__.py +12 -0
- esphome/components/http_request/http_request.h +65 -3
- esphome/components/http_request/http_request_arduino.cpp +2 -3
- esphome/components/http_request/http_request_idf.cpp +6 -14
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +1 -1
- esphome/components/i2c_device/__init__.py +26 -0
- esphome/components/i2c_device/i2c_device.cpp +17 -0
- esphome/components/i2c_device/i2c_device.h +18 -0
- esphome/components/i2s_audio/__init__.py +1 -3
- esphome/components/i2s_audio/speaker/__init__.py +12 -4
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +432 -197
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +91 -32
- esphome/components/ili9xxx/display.py +5 -1
- esphome/components/image/__init__.py +5 -8
- esphome/components/image/image.cpp +14 -14
- esphome/components/image/image.h +20 -24
- esphome/components/internal_temperature/internal_temperature.cpp +51 -2
- esphome/components/internal_temperature/internal_temperature.h +1 -0
- esphome/components/libretiny/gpio.py +4 -2
- esphome/components/light/__init__.py +32 -1
- esphome/components/light/automation.py +39 -32
- esphome/components/light/effects.py +36 -36
- esphome/components/light/light_state.cpp +6 -16
- esphome/components/light/light_state.h +34 -0
- esphome/components/light/types.py +3 -1
- esphome/components/logger/logger_esp32.cpp +15 -0
- esphome/components/lvgl/__init__.py +202 -95
- esphome/components/lvgl/automation.py +42 -40
- esphome/components/lvgl/binary_sensor/__init__.py +8 -15
- esphome/components/lvgl/defines.py +14 -8
- esphome/components/lvgl/encoders.py +11 -8
- esphome/components/lvgl/keypads.py +77 -0
- esphome/components/lvgl/light/__init__.py +6 -8
- esphome/components/lvgl/lv_validation.py +2 -4
- esphome/components/lvgl/lvcode.py +3 -9
- esphome/components/lvgl/lvgl_esphome.cpp +210 -89
- esphome/components/lvgl/lvgl_esphome.h +113 -30
- esphome/components/lvgl/lvgl_proxy.h +17 -0
- esphome/components/lvgl/number/__init__.py +10 -15
- esphome/components/lvgl/schemas.py +4 -2
- esphome/components/lvgl/select/__init__.py +12 -37
- esphome/components/lvgl/select/lvgl_select.h +27 -33
- esphome/components/lvgl/sensor/__init__.py +8 -14
- esphome/components/lvgl/styles.py +3 -4
- esphome/components/lvgl/switch/__init__.py +8 -13
- esphome/components/lvgl/text/__init__.py +5 -6
- esphome/components/lvgl/text_sensor/__init__.py +15 -15
- esphome/components/lvgl/touchscreens.py +2 -3
- esphome/components/lvgl/trigger.py +7 -9
- esphome/components/lvgl/types.py +9 -3
- esphome/components/lvgl/widgets/__init__.py +32 -21
- esphome/components/lvgl/widgets/dropdown.py +22 -10
- esphome/components/lvgl/widgets/msgbox.py +6 -5
- esphome/components/lvgl/widgets/obj.py +4 -2
- esphome/components/lvgl/widgets/page.py +3 -2
- esphome/components/lvgl/widgets/qrcode.py +54 -0
- esphome/components/lvgl/widgets/roller.py +21 -14
- esphome/components/lvgl/widgets/tileview.py +2 -1
- esphome/components/max17043/__init__.py +1 -0
- esphome/components/max17043/automation.h +20 -0
- esphome/components/max17043/max17043.cpp +98 -0
- esphome/components/max17043/max17043.h +29 -0
- esphome/components/max17043/sensor.py +77 -0
- esphome/components/media_player/__init__.py +11 -0
- esphome/components/media_player/automation.h +10 -0
- esphome/components/media_player/media_player.cpp +4 -0
- esphome/components/midea/air_conditioner.cpp +17 -1
- esphome/components/mlx90393/sensor.py +1 -1
- esphome/components/modbus_controller/__init__.py +31 -1
- esphome/components/modbus_controller/automation.h +16 -0
- esphome/components/modbus_controller/const.py +2 -0
- esphome/components/modbus_controller/modbus_controller.cpp +14 -2
- esphome/components/modbus_controller/modbus_controller.h +9 -0
- esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +40 -21
- esphome/components/mopeka_pro_check/mopeka_pro_check.h +9 -2
- esphome/components/mopeka_pro_check/sensor.py +41 -0
- esphome/components/mqtt/__init__.py +36 -0
- esphome/components/mqtt/mqtt_client.cpp +27 -3
- esphome/components/mqtt/mqtt_client.h +27 -2
- esphome/components/mqtt/mqtt_climate.cpp +4 -2
- esphome/components/mqtt/mqtt_component.cpp +6 -0
- esphome/components/mqtt/mqtt_component.h +4 -0
- esphome/components/mqtt/mqtt_const.h +6 -0
- esphome/components/online_image/online_image.cpp +2 -8
- esphome/components/online_image/online_image.h +2 -6
- esphome/components/opentherm/__init__.py +35 -9
- esphome/components/opentherm/binary_sensor/__init__.py +33 -0
- esphome/components/opentherm/const.py +11 -0
- esphome/components/opentherm/generate.py +142 -0
- esphome/components/opentherm/hub.cpp +130 -24
- esphome/components/opentherm/hub.h +62 -9
- esphome/components/opentherm/input.h +18 -0
- esphome/components/opentherm/input.py +51 -0
- esphome/components/opentherm/number/__init__.py +74 -0
- esphome/components/opentherm/number/number.cpp +40 -0
- esphome/components/opentherm/number/number.h +31 -0
- esphome/components/opentherm/opentherm.cpp +30 -0
- esphome/components/opentherm/opentherm.h +34 -2
- esphome/components/opentherm/opentherm_macros.h +151 -0
- esphome/components/opentherm/output/__init__.py +47 -0
- esphome/components/opentherm/output/output.cpp +18 -0
- esphome/components/opentherm/output/output.h +33 -0
- esphome/components/opentherm/schema.py +814 -0
- esphome/components/opentherm/sensor/__init__.py +51 -0
- esphome/components/opentherm/switch/__init__.py +43 -0
- esphome/components/opentherm/switch/switch.cpp +28 -0
- esphome/components/opentherm/switch/switch.h +20 -0
- esphome/components/opentherm/validate.py +31 -0
- esphome/components/pcd8544/display.py +8 -4
- esphome/components/prometheus/prometheus_handler.cpp +176 -14
- esphome/components/prometheus/prometheus_handler.h +25 -7
- esphome/components/qspi_amoled/display.py +1 -141
- esphome/components/qspi_dbi/display.py +185 -0
- esphome/components/qspi_dbi/models.py +64 -0
- esphome/components/{qspi_amoled/qspi_amoled.cpp → qspi_dbi/qspi_dbi.cpp} +95 -46
- esphome/components/{qspi_amoled/qspi_amoled.h → qspi_dbi/qspi_dbi.h} +26 -15
- esphome/components/rp2040/__init__.py +6 -3
- esphome/components/rp2040/gpio.py +5 -3
- esphome/components/rtttl/rtttl.cpp +4 -1
- esphome/components/rtttl/rtttl.h +1 -0
- esphome/components/sdl/sdl_esphome.cpp +22 -5
- esphome/components/sdl/sdl_esphome.h +1 -0
- esphome/components/sensor/__init__.py +18 -8
- esphome/components/sensor/filter.cpp +19 -18
- esphome/components/sensor/filter.h +9 -10
- esphome/components/sgp4x/sgp4x.cpp +40 -74
- esphome/components/sgp4x/sgp4x.h +5 -3
- esphome/components/speaker/__init__.py +51 -5
- esphome/components/speaker/automation.h +25 -0
- esphome/components/speaker/speaker.h +72 -1
- esphome/components/spi/__init__.py +15 -14
- esphome/components/spi_device/__init__.py +4 -15
- esphome/components/ssd1306_spi/display.py +6 -2
- esphome/components/ssd1322_spi/display.py +6 -2
- esphome/components/ssd1325_spi/display.py +6 -2
- esphome/components/ssd1327_spi/display.py +6 -2
- esphome/components/ssd1331_spi/display.py +6 -2
- esphome/components/ssd1351_spi/display.py +6 -2
- esphome/components/st7567_spi/display.py +6 -2
- esphome/components/st7701s/display.py +5 -1
- esphome/components/st7735/display.py +10 -5
- esphome/components/st7789v/display.py +12 -7
- esphome/components/statsd/statsd.cpp +2 -0
- esphome/components/statsd/statsd.h +2 -0
- esphome/components/sun/sun.h +3 -0
- esphome/components/tc74/__init__.py +1 -0
- esphome/components/tc74/sensor.py +32 -0
- esphome/components/tc74/tc74.cpp +68 -0
- esphome/components/tc74/tc74.h +28 -0
- esphome/components/touchscreen/__init__.py +41 -50
- esphome/components/touchscreen/touchscreen.h +4 -8
- esphome/components/udp/udp_component.cpp +6 -3
- esphome/components/udp/udp_component.h +4 -2
- esphome/components/waveshare_epaper/display.py +6 -2
- esphome/components/web_server/web_server.cpp +22 -0
- esphome/components/web_server/web_server.h +3 -0
- esphome/components/weikai/weikai.h +2 -2
- esphome/components/wifi/wifi_component.cpp +2 -2
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +4 -4
- esphome/components/wifi/wifi_component_esp_idf.cpp +2 -2
- esphome/components/xpt2046/touchscreen/__init__.py +7 -32
- esphome/config_validation.py +3 -1
- esphome/const.py +8 -1
- esphome/core/defines.h +8 -2
- esphome/core/helpers.cpp +32 -17
- esphome/core/helpers.h +32 -16
- esphome/core/ring_buffer.cpp +2 -2
- esphome/core/ring_buffer.h +2 -2
- esphome/dashboard/core.py +25 -0
- esphome/dashboard/status/mdns.py +3 -4
- esphome/dashboard/web_server.py +54 -19
- esphome/espota2.py +36 -35
- esphome/helpers.py +68 -16
- esphome/mqtt.py +9 -2
- esphome/storage_json.py +4 -0
- esphome/writer.py +7 -18
- esphome/zeroconf.py +8 -6
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/METADATA +7 -5
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/RECORD +226 -180
- esphome/core/bytebuffer.cpp +0 -167
- esphome/core/bytebuffer.h +0 -144
- /esphome/components/{qspi_amoled → qspi_dbi}/__init__.py +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/LICENSE +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/WHEEL +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
#include <driver/i2s.h>
|
6
6
|
|
7
|
+
#include "esphome/components/audio/audio.h"
|
8
|
+
|
7
9
|
#include "esphome/core/application.h"
|
8
10
|
#include "esphome/core/hal.h"
|
9
11
|
#include "esphome/core/log.h"
|
@@ -11,186 +13,347 @@
|
|
11
13
|
namespace esphome {
|
12
14
|
namespace i2s_audio {
|
13
15
|
|
14
|
-
static const
|
16
|
+
static const uint8_t DMA_BUFFER_DURATION_MS = 15;
|
17
|
+
static const size_t DMA_BUFFERS_COUNT = 4;
|
18
|
+
|
19
|
+
static const size_t TASK_DELAY_MS = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT / 2;
|
20
|
+
|
21
|
+
static const size_t TASK_STACK_SIZE = 4096;
|
22
|
+
static const ssize_t TASK_PRIORITY = 23;
|
23
|
+
|
24
|
+
static const size_t I2S_EVENT_QUEUE_COUNT = DMA_BUFFERS_COUNT + 1;
|
15
25
|
|
16
26
|
static const char *const TAG = "i2s_audio.speaker";
|
17
27
|
|
28
|
+
enum SpeakerEventGroupBits : uint32_t {
|
29
|
+
COMMAND_START = (1 << 0), // starts the speaker task
|
30
|
+
COMMAND_STOP = (1 << 1), // stops the speaker task
|
31
|
+
COMMAND_STOP_GRACEFULLY = (1 << 2), // Stops the speaker task once all data has been written
|
32
|
+
STATE_STARTING = (1 << 10),
|
33
|
+
STATE_RUNNING = (1 << 11),
|
34
|
+
STATE_STOPPING = (1 << 12),
|
35
|
+
STATE_STOPPED = (1 << 13),
|
36
|
+
ERR_INVALID_FORMAT = (1 << 14),
|
37
|
+
ERR_TASK_FAILED_TO_START = (1 << 15),
|
38
|
+
ERR_ESP_INVALID_STATE = (1 << 16),
|
39
|
+
ERR_ESP_INVALID_ARG = (1 << 17),
|
40
|
+
ERR_ESP_INVALID_SIZE = (1 << 18),
|
41
|
+
ERR_ESP_NO_MEM = (1 << 19),
|
42
|
+
ERR_ESP_FAIL = (1 << 20),
|
43
|
+
ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | ERR_ESP_NO_MEM | ERR_ESP_FAIL,
|
44
|
+
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
45
|
+
};
|
46
|
+
|
47
|
+
// Translates a SpeakerEventGroupBits ERR_ESP bit to the coressponding esp_err_t
|
48
|
+
static esp_err_t err_bit_to_esp_err(uint32_t bit) {
|
49
|
+
switch (bit) {
|
50
|
+
case SpeakerEventGroupBits::ERR_ESP_INVALID_STATE:
|
51
|
+
return ESP_ERR_INVALID_STATE;
|
52
|
+
case SpeakerEventGroupBits::ERR_ESP_INVALID_ARG:
|
53
|
+
return ESP_ERR_INVALID_ARG;
|
54
|
+
case SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE:
|
55
|
+
return ESP_ERR_INVALID_SIZE;
|
56
|
+
case SpeakerEventGroupBits::ERR_ESP_NO_MEM:
|
57
|
+
return ESP_ERR_NO_MEM;
|
58
|
+
default:
|
59
|
+
return ESP_FAIL;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
/// @brief Multiplies the input array of Q15 numbers by a Q15 constant factor
|
64
|
+
///
|
65
|
+
/// Based on `dsps_mulc_s16_ansi` from the esp-dsp library:
|
66
|
+
/// https://github.com/espressif/esp-dsp/blob/master/modules/math/mulc/fixed/dsps_mulc_s16_ansi.c
|
67
|
+
/// (accessed on 2024-09-30).
|
68
|
+
/// @param input Array of Q15 numbers
|
69
|
+
/// @param output Array of Q15 numbers
|
70
|
+
/// @param len Length of array
|
71
|
+
/// @param c Q15 constant factor
|
72
|
+
static void q15_multiplication(const int16_t *input, int16_t *output, size_t len, int16_t c) {
|
73
|
+
for (int i = 0; i < len; i++) {
|
74
|
+
int32_t acc = (int32_t) input[i] * (int32_t) c;
|
75
|
+
output[i] = (int16_t) (acc >> 15);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
// Lists the Q15 fixed point scaling factor for volume reduction.
|
80
|
+
// Has 100 values representing silence and a reduction [49, 48.5, ... 0.5, 0] dB.
|
81
|
+
// dB to PCM scaling factor formula: floating_point_scale_factor = 2^(-db/6.014)
|
82
|
+
// float to Q15 fixed point formula: q15_scale_factor = floating_point_scale_factor * 2^(15)
|
83
|
+
static const std::vector<int16_t> Q15_VOLUME_SCALING_FACTORS = {
|
84
|
+
0, 116, 122, 130, 137, 146, 154, 163, 173, 183, 194, 206, 218, 231, 244,
|
85
|
+
259, 274, 291, 308, 326, 345, 366, 388, 411, 435, 461, 488, 517, 548, 580,
|
86
|
+
615, 651, 690, 731, 774, 820, 868, 920, 974, 1032, 1094, 1158, 1227, 1300, 1377,
|
87
|
+
1459, 1545, 1637, 1734, 1837, 1946, 2061, 2184, 2313, 2450, 2596, 2750, 2913, 3085, 3269,
|
88
|
+
3462, 3668, 3885, 4116, 4360, 4619, 4893, 5183, 5490, 5816, 6161, 6527, 6914, 7324, 7758,
|
89
|
+
8218, 8706, 9222, 9770, 10349, 10963, 11613, 12302, 13032, 13805, 14624, 15491, 16410, 17384, 18415,
|
90
|
+
19508, 20665, 21891, 23189, 24565, 26022, 27566, 29201, 30933, 32767};
|
91
|
+
|
18
92
|
void I2SAudioSpeaker::setup() {
|
19
93
|
ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker...");
|
20
94
|
|
21
|
-
this->
|
22
|
-
|
23
|
-
|
95
|
+
this->event_group_ = xEventGroupCreate();
|
96
|
+
|
97
|
+
if (this->event_group_ == nullptr) {
|
98
|
+
ESP_LOGE(TAG, "Failed to create event group");
|
24
99
|
this->mark_failed();
|
25
100
|
return;
|
26
101
|
}
|
27
102
|
|
28
|
-
this->
|
29
|
-
|
30
|
-
|
103
|
+
this->i2s_event_queue_ = xQueueCreate(I2S_EVENT_QUEUE_COUNT, sizeof(i2s_event_t));
|
104
|
+
|
105
|
+
if (this->i2s_event_queue_ == nullptr) {
|
106
|
+
ESP_LOGE(TAG, "Failed to create I2S event queue");
|
31
107
|
this->mark_failed();
|
32
108
|
return;
|
33
109
|
}
|
34
110
|
}
|
35
111
|
|
36
|
-
void I2SAudioSpeaker::
|
37
|
-
|
38
|
-
|
39
|
-
|
112
|
+
void I2SAudioSpeaker::loop() {
|
113
|
+
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
114
|
+
|
115
|
+
if (event_group_bits & SpeakerEventGroupBits::STATE_STARTING) {
|
116
|
+
ESP_LOGD(TAG, "Starting Speaker");
|
117
|
+
this->state_ = speaker::STATE_STARTING;
|
118
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
40
119
|
}
|
41
|
-
if (
|
42
|
-
|
43
|
-
|
120
|
+
if (event_group_bits & SpeakerEventGroupBits::STATE_RUNNING) {
|
121
|
+
ESP_LOGD(TAG, "Started Speaker");
|
122
|
+
this->state_ = speaker::STATE_RUNNING;
|
123
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
124
|
+
this->status_clear_warning();
|
125
|
+
this->status_clear_error();
|
44
126
|
}
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
return;
|
127
|
+
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPING) {
|
128
|
+
ESP_LOGD(TAG, "Stopping Speaker");
|
129
|
+
this->state_ = speaker::STATE_STOPPING;
|
130
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
50
131
|
}
|
51
|
-
if (
|
52
|
-
|
132
|
+
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPED) {
|
133
|
+
if (!this->task_created_) {
|
134
|
+
ESP_LOGD(TAG, "Stopped Speaker");
|
135
|
+
this->state_ = speaker::STATE_STOPPED;
|
136
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
|
137
|
+
this->speaker_task_handle_ = nullptr;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) {
|
142
|
+
this->status_set_error("Failed to start speaker task");
|
143
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
144
|
+
}
|
145
|
+
|
146
|
+
if (event_group_bits & SpeakerEventGroupBits::ERR_INVALID_FORMAT) {
|
147
|
+
this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
|
148
|
+
ESP_LOGE(TAG,
|
149
|
+
"Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
|
150
|
+
this->audio_stream_info_.sample_rate, this->audio_stream_info_.channels,
|
151
|
+
this->audio_stream_info_.bits_per_sample);
|
53
152
|
}
|
54
153
|
|
55
|
-
|
56
|
-
|
154
|
+
if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
|
155
|
+
uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
|
156
|
+
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
|
157
|
+
this->status_set_warning();
|
158
|
+
}
|
57
159
|
}
|
58
160
|
|
59
|
-
|
60
|
-
|
61
|
-
|
161
|
+
void I2SAudioSpeaker::set_volume(float volume) {
|
162
|
+
this->volume_ = volume;
|
163
|
+
#ifdef USE_AUDIO_DAC
|
164
|
+
if (this->audio_dac_ != nullptr) {
|
165
|
+
if (volume > 0.0) {
|
166
|
+
this->audio_dac_->set_mute_off();
|
167
|
+
}
|
168
|
+
this->audio_dac_->set_volume(volume);
|
169
|
+
} else
|
170
|
+
#endif
|
171
|
+
{
|
172
|
+
// Fallback to software volume control by using a Q15 fixed point scaling factor
|
173
|
+
ssize_t decibel_index = remap<ssize_t, float>(volume, 0.0f, 1.0f, 0, Q15_VOLUME_SCALING_FACTORS.size() - 1);
|
174
|
+
this->q15_volume_factor_ = Q15_VOLUME_SCALING_FACTORS[decibel_index];
|
62
175
|
}
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
176
|
+
}
|
177
|
+
|
178
|
+
void I2SAudioSpeaker::set_mute_state(bool mute_state) {
|
179
|
+
this->mute_state_ = mute_state;
|
180
|
+
#ifdef USE_AUDIO_DAC
|
181
|
+
if (this->audio_dac_) {
|
182
|
+
if (mute_state) {
|
183
|
+
this->audio_dac_->set_mute_on();
|
184
|
+
} else {
|
185
|
+
this->audio_dac_->set_mute_off();
|
186
|
+
}
|
187
|
+
} else
|
188
|
+
#endif
|
189
|
+
{
|
190
|
+
if (mute_state) {
|
191
|
+
// Fallback to software volume control and scale by 0
|
192
|
+
this->q15_volume_factor_ = 0;
|
193
|
+
} else {
|
194
|
+
// Revert to previous volume when unmuting
|
195
|
+
this->set_volume(this->volume_);
|
196
|
+
}
|
69
197
|
}
|
70
|
-
bytes *= (sizeof(b) / sizeof(a)) * (repeat ? 2 : 1); // NOLINT
|
71
|
-
return reinterpret_cast<const uint8_t *>(result);
|
72
198
|
}
|
73
199
|
|
74
|
-
|
75
|
-
|
200
|
+
size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
|
201
|
+
if (this->is_failed()) {
|
202
|
+
ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup");
|
203
|
+
return 0;
|
204
|
+
}
|
205
|
+
if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) {
|
206
|
+
this->start();
|
207
|
+
}
|
76
208
|
|
77
|
-
|
78
|
-
|
79
|
-
|
209
|
+
size_t bytes_written = 0;
|
210
|
+
if ((this->state_ == speaker::STATE_RUNNING) && (this->audio_ring_buffer_.use_count() == 1)) {
|
211
|
+
// Only one owner of the ring buffer (the speaker task), so the ring buffer is allocated and no other components are
|
212
|
+
// attempting to write to it.
|
80
213
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
.bits_per_sample = this_speaker->bits_per_sample_,
|
85
|
-
.channel_format = this_speaker->channel_,
|
86
|
-
.communication_format = this_speaker->i2s_comm_fmt_,
|
87
|
-
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
88
|
-
.dma_buf_count = 8,
|
89
|
-
.dma_buf_len = 256,
|
90
|
-
.use_apll = this_speaker->use_apll_,
|
91
|
-
.tx_desc_auto_clear = true,
|
92
|
-
.fixed_mclk = 0,
|
93
|
-
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
|
94
|
-
.bits_per_chan = this_speaker->bits_per_channel_,
|
95
|
-
};
|
96
|
-
#if SOC_I2S_SUPPORTS_DAC
|
97
|
-
if (this_speaker->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) {
|
98
|
-
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN);
|
214
|
+
// Temporarily share ownership of the ring buffer so it won't be deallocated while writing
|
215
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer = this->audio_ring_buffer_;
|
216
|
+
bytes_written = temp_ring_buffer->write_without_replacement((void *) data, length, ticks_to_wait);
|
99
217
|
}
|
100
|
-
#endif
|
101
218
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
xQueueSend(this_speaker->event_queue_, &event, 0);
|
109
|
-
while (true) {
|
110
|
-
delay(10);
|
111
|
-
}
|
219
|
+
return bytes_written;
|
220
|
+
}
|
221
|
+
|
222
|
+
bool I2SAudioSpeaker::has_buffered_data() const {
|
223
|
+
if (this->audio_ring_buffer_ != nullptr) {
|
224
|
+
return this->audio_ring_buffer_->available() > 0;
|
112
225
|
}
|
226
|
+
return false;
|
227
|
+
}
|
113
228
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
229
|
+
void I2SAudioSpeaker::speaker_task(void *params) {
|
230
|
+
I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params;
|
231
|
+
uint32_t event_group_bits =
|
232
|
+
xEventGroupWaitBits(this_speaker->event_group_,
|
233
|
+
SpeakerEventGroupBits::COMMAND_START | SpeakerEventGroupBits::COMMAND_STOP |
|
234
|
+
SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY, // Bit message to read
|
235
|
+
pdTRUE, // Clear the bits on exit
|
236
|
+
pdFALSE, // Don't wait for all the bits,
|
237
|
+
portMAX_DELAY); // Block indefinitely until a bit is set
|
238
|
+
|
239
|
+
if (event_group_bits & (SpeakerEventGroupBits::COMMAND_STOP | SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY)) {
|
240
|
+
// Received a stop signal before the task was requested to start
|
241
|
+
this_speaker->delete_task_(0);
|
242
|
+
}
|
119
243
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
244
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
245
|
+
|
246
|
+
audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_;
|
247
|
+
const ssize_t bytes_per_sample = audio_stream_info.get_bytes_per_sample();
|
248
|
+
const uint8_t number_of_channels = audio_stream_info.channels;
|
249
|
+
|
250
|
+
const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * this_speaker->sample_rate_ / 1000 *
|
251
|
+
bytes_per_sample * number_of_channels;
|
252
|
+
const size_t ring_buffer_size =
|
253
|
+
this_speaker->buffer_duration_ms_ * this_speaker->sample_rate_ / 1000 * bytes_per_sample * number_of_channels;
|
254
|
+
|
255
|
+
if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) {
|
256
|
+
// Failed to allocate buffers
|
257
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
258
|
+
this_speaker->delete_task_(dma_buffers_size);
|
124
259
|
}
|
125
|
-
#endif
|
126
260
|
|
127
|
-
|
261
|
+
if (this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_())) {
|
262
|
+
// Failed to start I2S driver
|
263
|
+
this_speaker->delete_task_(dma_buffers_size);
|
264
|
+
}
|
128
265
|
|
129
|
-
|
130
|
-
|
266
|
+
if (!this_speaker->send_esp_err_to_event_group_(this_speaker->reconfigure_i2s_stream_info_(audio_stream_info))) {
|
267
|
+
// Successfully set the I2S stream info, ready to write audio data to the I2S port
|
131
268
|
|
132
|
-
|
269
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
133
270
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
break; // End of audio from main thread
|
138
|
-
}
|
139
|
-
if (data_event.stop) {
|
140
|
-
// Stop signal from main thread
|
141
|
-
xQueueReset(this_speaker->buffer_queue_); // Flush queue
|
142
|
-
break;
|
143
|
-
}
|
271
|
+
bool stop_gracefully = false;
|
272
|
+
uint32_t last_data_received_time = millis();
|
273
|
+
bool tx_dma_underflow = false;
|
144
274
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
data = convert_data_format(reinterpret_cast<const int16_t *>(data), reinterpret_cast<int16_t *>(buffer),
|
151
|
-
remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT);
|
275
|
+
while (!this_speaker->timeout_.has_value() ||
|
276
|
+
(millis() - last_data_received_time) <= this_speaker->timeout_.value()) {
|
277
|
+
event_group_bits = xEventGroupGetBits(this_speaker->event_group_);
|
278
|
+
|
279
|
+
if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP) {
|
152
280
|
break;
|
153
281
|
}
|
154
|
-
|
155
|
-
|
156
|
-
data = convert_data_format(reinterpret_cast<const int16_t *>(data), reinterpret_cast<int32_t *>(buffer),
|
157
|
-
remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT);
|
158
|
-
break;
|
282
|
+
if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY) {
|
283
|
+
stop_gracefully = true;
|
159
284
|
}
|
160
|
-
}
|
161
285
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
if (err != ESP_OK) {
|
167
|
-
event = {.type = TaskEventType::WARNING, .err = err};
|
168
|
-
if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
|
169
|
-
ESP_LOGW(TAG, "Failed to send WARNING event");
|
286
|
+
i2s_event_t i2s_event;
|
287
|
+
while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
|
288
|
+
if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
|
289
|
+
tx_dma_underflow = true;
|
170
290
|
}
|
171
|
-
continue;
|
172
291
|
}
|
173
|
-
data += bytes_written;
|
174
|
-
remaining -= bytes_written;
|
175
|
-
}
|
176
|
-
}
|
177
292
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
293
|
+
size_t bytes_to_read = dma_buffers_size;
|
294
|
+
size_t bytes_read = this_speaker->audio_ring_buffer_->read((void *) this_speaker->data_buffer_, bytes_to_read,
|
295
|
+
pdMS_TO_TICKS(TASK_DELAY_MS));
|
296
|
+
|
297
|
+
if (bytes_read > 0) {
|
298
|
+
size_t bytes_written = 0;
|
299
|
+
|
300
|
+
if ((audio_stream_info.bits_per_sample == 16) && (this_speaker->q15_volume_factor_ < INT16_MAX)) {
|
301
|
+
// Scale samples by the volume factor in place
|
302
|
+
q15_multiplication((int16_t *) this_speaker->data_buffer_, (int16_t *) this_speaker->data_buffer_,
|
303
|
+
bytes_read / sizeof(int16_t), this_speaker->q15_volume_factor_);
|
304
|
+
}
|
182
305
|
|
306
|
+
if (audio_stream_info.bits_per_sample == (uint8_t) this_speaker->bits_per_sample_) {
|
307
|
+
i2s_write(this_speaker->parent_->get_port(), this_speaker->data_buffer_, bytes_read, &bytes_written,
|
308
|
+
portMAX_DELAY);
|
309
|
+
} else if (audio_stream_info.bits_per_sample < (uint8_t) this_speaker->bits_per_sample_) {
|
310
|
+
i2s_write_expand(this_speaker->parent_->get_port(), this_speaker->data_buffer_, bytes_read,
|
311
|
+
audio_stream_info.bits_per_sample, this_speaker->bits_per_sample_, &bytes_written,
|
312
|
+
portMAX_DELAY);
|
313
|
+
}
|
314
|
+
|
315
|
+
if (bytes_written != bytes_read) {
|
316
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE);
|
317
|
+
}
|
318
|
+
tx_dma_underflow = false;
|
319
|
+
last_data_received_time = millis();
|
320
|
+
} else {
|
321
|
+
// No data received
|
322
|
+
if (stop_gracefully && tx_dma_underflow) {
|
323
|
+
break;
|
324
|
+
}
|
325
|
+
}
|
326
|
+
}
|
327
|
+
} else {
|
328
|
+
// Couldn't configure the I2S port to be compatible with the incoming audio
|
329
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_INVALID_FORMAT);
|
330
|
+
}
|
183
331
|
i2s_zero_dma_buffer(this_speaker->parent_->get_port());
|
184
332
|
|
333
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
334
|
+
|
185
335
|
i2s_driver_uninstall(this_speaker->parent_->get_port());
|
186
336
|
|
187
|
-
|
188
|
-
|
189
|
-
|
337
|
+
this_speaker->parent_->unlock();
|
338
|
+
this_speaker->delete_task_(dma_buffers_size);
|
339
|
+
}
|
340
|
+
|
341
|
+
void I2SAudioSpeaker::start() {
|
342
|
+
if (this->is_failed() || this->status_has_error())
|
343
|
+
return;
|
344
|
+
if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING))
|
345
|
+
return;
|
346
|
+
|
347
|
+
if (this->speaker_task_handle_ == nullptr) {
|
348
|
+
xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
|
349
|
+
&this->speaker_task_handle_);
|
190
350
|
}
|
191
351
|
|
192
|
-
|
193
|
-
|
352
|
+
if (this->speaker_task_handle_ != nullptr) {
|
353
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
|
354
|
+
this->task_created_ = true;
|
355
|
+
} else {
|
356
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
194
357
|
}
|
195
358
|
}
|
196
359
|
|
@@ -203,92 +366,164 @@ void I2SAudioSpeaker::stop_(bool wait_on_empty) {
|
|
203
366
|
return;
|
204
367
|
if (this->state_ == speaker::STATE_STOPPED)
|
205
368
|
return;
|
206
|
-
|
207
|
-
this->state_ = speaker::STATE_STOPPED;
|
208
|
-
return;
|
209
|
-
}
|
210
|
-
this->state_ = speaker::STATE_STOPPING;
|
211
|
-
DataEvent data;
|
212
|
-
data.stop = true;
|
369
|
+
|
213
370
|
if (wait_on_empty) {
|
214
|
-
|
371
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
|
215
372
|
} else {
|
216
|
-
|
373
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP);
|
217
374
|
}
|
218
375
|
}
|
219
376
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
this->player_task_handle_ = nullptr;
|
240
|
-
this->parent_->unlock();
|
241
|
-
xQueueReset(this->buffer_queue_);
|
242
|
-
ESP_LOGD(TAG, "Stopped I2S Audio Speaker");
|
243
|
-
break;
|
244
|
-
case TaskEventType::WARNING:
|
245
|
-
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err));
|
246
|
-
this->status_set_warning();
|
247
|
-
break;
|
248
|
-
}
|
377
|
+
bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) {
|
378
|
+
switch (err) {
|
379
|
+
case ESP_OK:
|
380
|
+
return false;
|
381
|
+
case ESP_ERR_INVALID_STATE:
|
382
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_STATE);
|
383
|
+
return true;
|
384
|
+
case ESP_ERR_INVALID_ARG:
|
385
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_ARG);
|
386
|
+
return true;
|
387
|
+
case ESP_ERR_INVALID_SIZE:
|
388
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE);
|
389
|
+
return true;
|
390
|
+
case ESP_ERR_NO_MEM:
|
391
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
392
|
+
return true;
|
393
|
+
default:
|
394
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
|
395
|
+
return true;
|
249
396
|
}
|
250
397
|
}
|
251
398
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
case speaker::STATE_RUNNING:
|
258
|
-
case speaker::STATE_STOPPING:
|
259
|
-
this->watch_();
|
260
|
-
break;
|
261
|
-
case speaker::STATE_STOPPED:
|
262
|
-
break;
|
399
|
+
esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size) {
|
400
|
+
if (this->data_buffer_ == nullptr) {
|
401
|
+
// Allocate data buffer for temporarily storing audio from the ring buffer before writing to the I2S bus
|
402
|
+
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
403
|
+
this->data_buffer_ = allocator.allocate(data_buffer_size);
|
263
404
|
}
|
405
|
+
|
406
|
+
if (this->data_buffer_ == nullptr) {
|
407
|
+
return ESP_ERR_NO_MEM;
|
408
|
+
}
|
409
|
+
|
410
|
+
if (this->audio_ring_buffer_.use_count() == 0) {
|
411
|
+
// Allocate ring buffer. Uses a shared_ptr to ensure it isn't improperly deallocated.
|
412
|
+
this->audio_ring_buffer_ = RingBuffer::create(ring_buffer_size);
|
413
|
+
}
|
414
|
+
|
415
|
+
if (this->audio_ring_buffer_ == nullptr) {
|
416
|
+
return ESP_ERR_NO_MEM;
|
417
|
+
}
|
418
|
+
|
419
|
+
return ESP_OK;
|
264
420
|
}
|
265
421
|
|
266
|
-
|
267
|
-
if (this->
|
268
|
-
|
269
|
-
return 0;
|
422
|
+
esp_err_t I2SAudioSpeaker::start_i2s_driver_() {
|
423
|
+
if (!this->parent_->try_lock()) {
|
424
|
+
return ESP_ERR_INVALID_STATE;
|
270
425
|
}
|
271
|
-
|
272
|
-
|
426
|
+
|
427
|
+
int dma_buffer_length = DMA_BUFFER_DURATION_MS * this->sample_rate_ / 1000;
|
428
|
+
|
429
|
+
i2s_driver_config_t config = {
|
430
|
+
.mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
|
431
|
+
.sample_rate = this->sample_rate_,
|
432
|
+
.bits_per_sample = this->bits_per_sample_,
|
433
|
+
.channel_format = this->channel_,
|
434
|
+
.communication_format = this->i2s_comm_fmt_,
|
435
|
+
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
436
|
+
.dma_buf_count = DMA_BUFFERS_COUNT,
|
437
|
+
.dma_buf_len = dma_buffer_length,
|
438
|
+
.use_apll = this->use_apll_,
|
439
|
+
.tx_desc_auto_clear = true,
|
440
|
+
.fixed_mclk = I2S_PIN_NO_CHANGE,
|
441
|
+
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
|
442
|
+
.bits_per_chan = this->bits_per_channel_,
|
443
|
+
#if SOC_I2S_SUPPORTS_TDM
|
444
|
+
.chan_mask = (i2s_channel_t) (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1),
|
445
|
+
.total_chan = 2,
|
446
|
+
.left_align = false,
|
447
|
+
.big_edin = false,
|
448
|
+
.bit_order_msb = false,
|
449
|
+
.skip_msk = false,
|
450
|
+
#endif
|
451
|
+
};
|
452
|
+
#if SOC_I2S_SUPPORTS_DAC
|
453
|
+
if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) {
|
454
|
+
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN);
|
273
455
|
}
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
456
|
+
#endif
|
457
|
+
|
458
|
+
esp_err_t err =
|
459
|
+
i2s_driver_install(this->parent_->get_port(), &config, I2S_EVENT_QUEUE_COUNT, &this->i2s_event_queue_);
|
460
|
+
if (err != ESP_OK) {
|
461
|
+
// Failed to install the driver, so unlock the I2S port
|
462
|
+
this->parent_->unlock();
|
463
|
+
return err;
|
464
|
+
}
|
465
|
+
|
466
|
+
#if SOC_I2S_SUPPORTS_DAC
|
467
|
+
if (this->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) {
|
468
|
+
#endif
|
469
|
+
i2s_pin_config_t pin_config = this->parent_->get_pin_config();
|
470
|
+
pin_config.data_out_num = this->dout_pin_;
|
471
|
+
|
472
|
+
err = i2s_set_pin(this->parent_->get_port(), &pin_config);
|
473
|
+
#if SOC_I2S_SUPPORTS_DAC
|
474
|
+
} else {
|
475
|
+
i2s_set_dac_mode(this->internal_dac_mode_);
|
287
476
|
}
|
288
|
-
|
477
|
+
#endif
|
478
|
+
|
479
|
+
if (err != ESP_OK) {
|
480
|
+
// Failed to set the data out pin, so uninstall the driver and unlock the I2S port
|
481
|
+
i2s_driver_uninstall(this->parent_->get_port());
|
482
|
+
this->parent_->unlock();
|
483
|
+
}
|
484
|
+
|
485
|
+
return err;
|
486
|
+
}
|
487
|
+
|
488
|
+
esp_err_t I2SAudioSpeaker::reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info) {
|
489
|
+
if (this->i2s_mode_ & I2S_MODE_MASTER) {
|
490
|
+
// ESP controls for the the I2S bus, so adjust the sample rate and bits per sample to match the incoming audio
|
491
|
+
this->sample_rate_ = audio_stream_info.sample_rate;
|
492
|
+
this->bits_per_sample_ = (i2s_bits_per_sample_t) audio_stream_info.bits_per_sample;
|
493
|
+
} else if (this->sample_rate_ != audio_stream_info.sample_rate) {
|
494
|
+
// Can't reconfigure I2S bus, so the sample rate must match the configured value
|
495
|
+
return ESP_ERR_INVALID_ARG;
|
496
|
+
}
|
497
|
+
|
498
|
+
if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) {
|
499
|
+
// Currently can't handle the case when the incoming audio has more bits per sample than the configured value
|
500
|
+
return ESP_ERR_INVALID_ARG;
|
501
|
+
}
|
502
|
+
|
503
|
+
if (audio_stream_info.channels == 1) {
|
504
|
+
return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_MONO);
|
505
|
+
} else if (audio_stream_info.channels == 2) {
|
506
|
+
return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_STEREO);
|
507
|
+
}
|
508
|
+
|
509
|
+
return ESP_ERR_INVALID_ARG;
|
289
510
|
}
|
290
511
|
|
291
|
-
|
512
|
+
void I2SAudioSpeaker::delete_task_(size_t buffer_size) {
|
513
|
+
this->audio_ring_buffer_.reset(); // Releases onwership of the shared_ptr
|
514
|
+
|
515
|
+
if (this->data_buffer_ != nullptr) {
|
516
|
+
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
517
|
+
allocator.deallocate(this->data_buffer_, buffer_size);
|
518
|
+
this->data_buffer_ = nullptr;
|
519
|
+
}
|
520
|
+
|
521
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPED);
|
522
|
+
xQueueReset(this->i2s_event_queue_);
|
523
|
+
|
524
|
+
this->task_created_ = false;
|
525
|
+
vTaskDelete(nullptr);
|
526
|
+
}
|
292
527
|
|
293
528
|
} // namespace i2s_audio
|
294
529
|
} // namespace esphome
|