diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fc1404b..a2cd7d4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: rev: v1.1.1 hooks: - id: clang-format - args: [-i, --style=GNU] + args: [-i, --style=Google] # args: [-i, --style=Google] # - id: clang-tidy # args: [-checks=clang-diagnostic-return-type] diff --git a/components/lightsnapcast/include/player.h b/components/lightsnapcast/include/player.h index a2c180f..980312c 100644 --- a/components/lightsnapcast/include/player.h +++ b/components/lightsnapcast/include/player.h @@ -9,36 +9,28 @@ #define I2S_PORT I2S_NUM_0 -#define LATENCY_MEDIAN_FILTER_LEN 29 // 99 +#define CHNK_CTRL_CNT 3 + +#define LATENCY_MEDIAN_FILTER_LEN 29 // 99 #define SHORT_BUFFER_LEN 9 typedef struct pcm_chunk_fragment pcm_chunk_fragment_t; -struct pcm_chunk_fragment -{ +struct pcm_chunk_fragment { size_t size; char *payload; pcm_chunk_fragment_t *nextFragment; }; -typedef struct pcmData -{ +typedef struct pcmData { tv_t timestamp; uint32_t totalSize; pcm_chunk_fragment_t *fragment; } pcm_chunk_message_t; -typedef enum codec_type_e -{ - NONE = 0, - PCM, - FLAC, - OGG, - OPUS -} codec_type_t; +typedef enum codec_type_e { NONE = 0, PCM, FLAC, OGG, OPUS } codec_type_t; -typedef struct snapcastSetting_s -{ +typedef struct snapcastSetting_s { uint32_t buf_ms; uint32_t chkDur_ms; int32_t cDacLat_ms; @@ -55,22 +47,21 @@ typedef struct snapcastSetting_s uint32_t pcmBufSize; } snapcastSetting_t; -int init_player (void); -int deinit_player (void); +int init_player(void); +int deinit_player(void); -int8_t allocate_pcm_chunk_memory (pcm_chunk_message_t **pcmChunk, - size_t bytes); -int8_t insert_pcm_chunk (pcm_chunk_message_t *pcmChunk); +int8_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk, size_t bytes); +int8_t insert_pcm_chunk(pcm_chunk_message_t *pcmChunk); // int8_t insert_pcm_chunk (wire_chunk_message_t *decodedWireChunk); -int8_t free_pcm_chunk (pcm_chunk_message_t *pcmChunk); +int8_t free_pcm_chunk(pcm_chunk_message_t *pcmChunk); -int8_t player_latency_insert (int64_t newValue); -int8_t player_send_snapcast_setting (snapcastSetting_t *setting); +int8_t player_latency_insert(int64_t newValue); +int8_t player_send_snapcast_setting(snapcastSetting_t *setting); -int8_t reset_latency_buffer (void); -int8_t latency_buffer_full (void); -int8_t get_diff_to_server (int64_t *tDiff); -int8_t server_now (int64_t *sNow); +int8_t reset_latency_buffer(void); +int8_t latency_buffer_full(void); +int8_t get_diff_to_server(int64_t *tDiff); +int8_t server_now(int64_t *sNow); -#endif // __PLAYER_H__ +#endif // __PLAYER_H__ diff --git a/components/lightsnapcast/player.c b/components/lightsnapcast/player.c index 1afd69d..62cdb54 100644 --- a/components/lightsnapcast/player.c +++ b/components/lightsnapcast/player.c @@ -25,10 +25,10 @@ #include "player.h" #include "snapcast.h" -#include "i2s.h" // use custom i2s driver instead of IDF version +#include "i2s.h" // use custom i2s driver instead of IDF version #define SYNC_TASK_PRIORITY (configMAX_PRIORITIES - 1) -#define SYNC_TASK_CORE_ID 1 // tskNO_AFFINITY +#define SYNC_TASK_CORE_ID 1 // tskNO_AFFINITY static const char *TAG = "PLAYER"; @@ -39,9 +39,8 @@ static const char *TAG = "PLAYER"; * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + * 2) * 2) I2S bit clock is (apll_freq / 16) */ -static int apll_normal_predefine[6] = { 0, 0, 0, 0, 0, 0 }; -static int apll_corr_predefine[][6] - = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; +static int apll_normal_predefine[6] = {0, 0, 0, 0, 0, 0}; +static int apll_corr_predefine[][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; static SemaphoreHandle_t latencyBufSemaphoreHandle = NULL; @@ -55,7 +54,7 @@ static int64_t latencyToServer = 0; static sMedianFilter_t shortMedianFilter; static sMedianNode_t shortMedianBuffer[SHORT_BUFFER_LEN]; -static int8_t currentDir = 0; //!< current apll direction, see apll_adjust() +static int8_t currentDir = 0; //!< current apll direction, see apll_adjust() static QueueHandle_t pcmChkQHdl = NULL; @@ -76,9 +75,9 @@ static uint32_t i2sDmaBufMaxLen; static SemaphoreHandle_t snapcastSettingsMux = NULL; static snapcastSetting_t currentSnapcastSetting; -static void tg0_timer_init (void); -static void tg0_timer_deinit (void); -static void player_task (void *pvParameters); +static void tg0_timer_init(void); +static void tg0_timer_deinit(void); +static void player_task(void *pvParameters); /* #define CONFIG_MASTER_I2S_BCK_PIN 5 @@ -89,99 +88,87 @@ static void player_task (void *pvParameters); #define CONFIG_SLAVE_I2S_DATAOUT_PIN 5 */ -static esp_err_t -player_setup_i2s (i2s_port_t i2sNum, snapcastSetting_t *setting) -{ +static esp_err_t player_setup_i2s(i2s_port_t i2sNum, + snapcastSetting_t *setting) { int chunkInFrames; int __dmaBufCnt; int __dmaBufLen; const int __dmaBufMaxLen = 1024; int m_scale = 8, fi2s_clk; - chkInBytes - = (setting->chkDur_ms * setting->sr * setting->ch * (setting->bits / 8)) - / 1000; + chkInBytes = + (setting->chkDur_ms * setting->sr * setting->ch * (setting->bits / 8)) / + 1000; chunkInFrames = chkInBytes / (setting->ch * (setting->bits / 8)); __dmaBufCnt = 1; __dmaBufLen = chunkInFrames; - while ((__dmaBufLen >= __dmaBufMaxLen) || (__dmaBufCnt <= 1)) - { - if ((__dmaBufLen % 2) == 0) - { - __dmaBufCnt *= 2; - __dmaBufLen /= 2; - } - else - { - ESP_LOGE ( - TAG, - "player_setup_i2s: Can't setup i2s with this configuration"); + while ((__dmaBufLen >= __dmaBufMaxLen) || (__dmaBufCnt <= 1)) { + if ((__dmaBufLen % 2) == 0) { + __dmaBufCnt *= 2; + __dmaBufLen /= 2; + } else { + ESP_LOGE(TAG, + "player_setup_i2s: Can't setup i2s with this configuration"); - return -1; - } + return -1; } + } - i2sDmaBufCnt = __dmaBufCnt; + i2sDmaBufCnt = __dmaBufCnt * CHNK_CTRL_CNT; i2sDmaBufMaxLen = __dmaBufLen; fi2s_clk = setting->sr * setting->ch * setting->bits * m_scale; apll_normal_predefine[0] = setting->bits; apll_normal_predefine[1] = setting->sr; - if (i2s_apll_calculate_fi2s ( + if (i2s_apll_calculate_fi2s( fi2s_clk, setting->bits, &apll_normal_predefine[2], &apll_normal_predefine[3], &apll_normal_predefine[4], - &apll_normal_predefine[5]) - != ESP_OK) - { - ESP_LOGE (TAG, "ERROR, fi2s_clk"); - } + &apll_normal_predefine[5]) != ESP_OK) { + ESP_LOGE(TAG, "ERROR, fi2s_clk"); + } apll_corr_predefine[0][0] = setting->bits; apll_corr_predefine[0][1] = setting->sr * 1.001; - if (i2s_apll_calculate_fi2s ( + if (i2s_apll_calculate_fi2s( fi2s_clk * 1.001, setting->bits, &apll_corr_predefine[0][2], &apll_corr_predefine[0][3], &apll_corr_predefine[0][4], - &apll_corr_predefine[0][5]) - != ESP_OK) - { - ESP_LOGE (TAG, "ERROR, fi2s_clk * 1.001"); - } + &apll_corr_predefine[0][5]) != ESP_OK) { + ESP_LOGE(TAG, "ERROR, fi2s_clk * 1.001"); + } apll_corr_predefine[1][0] = setting->bits; apll_corr_predefine[1][1] = setting->sr * 0.999; - if (i2s_apll_calculate_fi2s ( + if (i2s_apll_calculate_fi2s( fi2s_clk * 0.999, setting->bits, &apll_corr_predefine[1][2], &apll_corr_predefine[1][3], &apll_corr_predefine[1][4], - &apll_corr_predefine[1][5]) - != ESP_OK) - { - ESP_LOGE (TAG, "ERROR, fi2s_clk * 0.999"); - } + &apll_corr_predefine[1][5]) != ESP_OK) { + ESP_LOGE(TAG, "ERROR, fi2s_clk * 0.999"); + } - ESP_LOGI (TAG, "player_setup_i2s: dma_buf_len is %d, dma_buf_count is %d", - i2sDmaBufMaxLen, i2sDmaBufCnt); + ESP_LOGI(TAG, "player_setup_i2s: dma_buf_len is %d, dma_buf_count is %d", + i2sDmaBufMaxLen, i2sDmaBufCnt); i2s_config_t i2s_config0 = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX - .sample_rate = setting->sr, - .bits_per_sample = setting->bits, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // 2-channels - .communication_format = I2S_COMM_FORMAT_STAND_I2S, - .dma_buf_count = i2sDmaBufCnt, - .dma_buf_len = i2sDmaBufMaxLen, - .intr_alloc_flags = 1, // Default interrupt priority - .use_apll = true, - .fixed_mclk = 0, - .tx_desc_auto_clear = true // Auto clear tx descriptor on underflow + .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX + .sample_rate = setting->sr, + .bits_per_sample = setting->bits, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // 2-channels + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .dma_buf_count = i2sDmaBufCnt, + .dma_buf_len = i2sDmaBufMaxLen, + .intr_alloc_flags = 1, // Default interrupt priority + .use_apll = true, + .fixed_mclk = 0, + .tx_desc_auto_clear = true // Auto clear tx descriptor on underflow }; i2s_pin_config_t pin_config0; - get_i2s_pins (i2sNum, &pin_config0); + get_i2s_pins(i2sNum, &pin_config0); - i2s_custom_driver_uninstall (i2sNum); - i2s_custom_driver_install (i2sNum, &i2s_config0, 0, NULL); - i2s_custom_set_pin (i2sNum, &pin_config0); + i2s_custom_driver_uninstall(i2sNum); + i2s_custom_driver_install(i2sNum, &i2s_config0, 0, NULL); + i2s_custom_set_pin(i2sNum, &pin_config0); return 0; } @@ -189,79 +176,62 @@ player_setup_i2s (i2s_port_t i2sNum, snapcastSetting_t *setting) /** * */ -static int -destroy_pcm_queue (QueueHandle_t *queueHandle) -{ +static int destroy_pcm_queue(QueueHandle_t *queueHandle) { int ret = pdPASS; pcm_chunk_message_t *chnk = NULL; - if (*queueHandle == NULL) - { - ESP_LOGW (TAG, "no pcm chunk queue created?"); - ret = pdFAIL; - } - else - { - // free all allocated memory - while (uxQueueMessagesWaiting (*queueHandle)) - { - ret = xQueueReceive (*queueHandle, &chnk, pdMS_TO_TICKS (2000)); - if (ret != pdFAIL) - { - if (chnk != NULL) - { - free_pcm_chunk (chnk); - } - } + if (*queueHandle == NULL) { + ESP_LOGW(TAG, "no pcm chunk queue created?"); + ret = pdFAIL; + } else { + // free all allocated memory + while (uxQueueMessagesWaiting(*queueHandle)) { + ret = xQueueReceive(*queueHandle, &chnk, pdMS_TO_TICKS(2000)); + if (ret != pdFAIL) { + if (chnk != NULL) { + free_pcm_chunk(chnk); } - - // delete the queue - vQueueDelete (*queueHandle); - *queueHandle = NULL; - - ret = pdPASS; + } } + // delete the queue + vQueueDelete(*queueHandle); + *queueHandle = NULL; + + ret = pdPASS; + } + return ret; } // ensure this is called after http_task was killed! -int -deinit_player (void) -{ +int deinit_player(void) { int ret = 0; // stop the task - if (syncTaskHandle == NULL) - { - ESP_LOGW (TAG, "no sync task created?"); - } - else - { - vTaskDelete (syncTaskHandle); - } + if (syncTaskHandle == NULL) { + ESP_LOGW(TAG, "no sync task created?"); + } else { + vTaskDelete(syncTaskHandle); + } - if (snapcastSettingsMux != NULL) - { - vSemaphoreDelete (snapcastSettingsMux); - snapcastSettingsMux = NULL; - } + if (snapcastSettingsMux != NULL) { + vSemaphoreDelete(snapcastSettingsMux); + snapcastSettingsMux = NULL; + } - ret = destroy_pcm_queue (&pcmChkQHdl); + ret = destroy_pcm_queue(&pcmChkQHdl); - if (latencyBufSemaphoreHandle == NULL) - { - ESP_LOGW (TAG, "no latency buffer semaphore created?"); - } - else - { - vSemaphoreDelete (latencyBufSemaphoreHandle); - latencyBufSemaphoreHandle = NULL; - } + if (latencyBufSemaphoreHandle == NULL) { + ESP_LOGW(TAG, "no latency buffer semaphore created?"); + } else { + vSemaphoreDelete(latencyBufSemaphoreHandle); + latencyBufSemaphoreHandle = NULL; + } - tg0_timer_deinit (); + tg0_timer_deinit(); - ESP_LOGI (TAG, "deinit player done"); + ESP_LOGI(TAG, "deinit player done"); return ret; } @@ -269,9 +239,7 @@ deinit_player (void) /** * call before http task creation! */ -int -init_player (void) -{ +int init_player(void) { int ret = 0; currentSnapcastSetting.buf_ms = 1000; @@ -283,162 +251,138 @@ init_player (void) currentSnapcastSetting.muted = false; currentSnapcastSetting.volume = 70; - if (snapcastSettingsMux == NULL) - { - snapcastSettingsMux = xSemaphoreCreateMutex (); - xSemaphoreGive (snapcastSettingsMux); - } + if (snapcastSettingsMux == NULL) { + snapcastSettingsMux = xSemaphoreCreateMutex(); + xSemaphoreGive(snapcastSettingsMux); + } - ret = player_setup_i2s (I2S_NUM_0, ¤tSnapcastSetting); - if (ret < 0) - { - ESP_LOGE (TAG, "player_setup_i2s failed: %d", ret); + ret = player_setup_i2s(I2S_NUM_0, ¤tSnapcastSetting); + if (ret < 0) { + ESP_LOGE(TAG, "player_setup_i2s failed: %d", ret); - return -1; - } + return -1; + } // create semaphore for time diff buffer to server - if (latencyBufSemaphoreHandle == NULL) - { - latencyBufSemaphoreHandle = xSemaphoreCreateMutex (); - } + if (latencyBufSemaphoreHandle == NULL) { + latencyBufSemaphoreHandle = xSemaphoreCreateMutex(); + } // init diff buff median filter latencyMedianFilterLong.numNodes = LATENCY_MEDIAN_FILTER_LEN; latencyMedianFilterLong.medianBuffer = latencyMedianLongBuffer; - reset_latency_buffer (); + reset_latency_buffer(); - tg0_timer_init (); + tg0_timer_init(); - if (syncTaskHandle == NULL) - { - ESP_LOGI (TAG, "Start player_task"); + if (syncTaskHandle == NULL) { + ESP_LOGI(TAG, "Start player_task"); - xTaskCreatePinnedToCore (player_task, "player", 2048 + 512, NULL, - SYNC_TASK_PRIORITY, &syncTaskHandle, - SYNC_TASK_CORE_ID); - } + xTaskCreatePinnedToCore(player_task, "player", 2048 + 512, NULL, + SYNC_TASK_PRIORITY, &syncTaskHandle, + SYNC_TASK_CORE_ID); + } - ESP_LOGI (TAG, "init player done"); + ESP_LOGI(TAG, "init player done"); return 0; } -int8_t -player_set_snapcast_settings (snapcastSetting_t *setting) -{ +int8_t player_set_snapcast_settings(snapcastSetting_t *setting) { int8_t ret = pdPASS; - xSemaphoreTake (snapcastSettingsMux, portMAX_DELAY); + xSemaphoreTake(snapcastSettingsMux, portMAX_DELAY); - memcpy (¤tSnapcastSetting, setting, sizeof (snapcastSetting_t)); + memcpy(¤tSnapcastSetting, setting, sizeof(snapcastSetting_t)); - xSemaphoreGive (snapcastSettingsMux); + xSemaphoreGive(snapcastSettingsMux); return ret; } -int8_t -player_get_snapcast_settings (snapcastSetting_t *setting) -{ +int8_t player_get_snapcast_settings(snapcastSetting_t *setting) { int8_t ret = pdPASS; - xSemaphoreTake (snapcastSettingsMux, portMAX_DELAY); + xSemaphoreTake(snapcastSettingsMux, portMAX_DELAY); - memcpy (setting, ¤tSnapcastSetting, sizeof (snapcastSetting_t)); + memcpy(setting, ¤tSnapcastSetting, sizeof(snapcastSetting_t)); - xSemaphoreGive (snapcastSettingsMux); + xSemaphoreGive(snapcastSettingsMux); return ret; } -int8_t -player_latency_insert (int64_t newValue) -{ +int8_t player_latency_insert(int64_t newValue) { int64_t medianValue; - medianValue = MEDIANFILTER_Insert (&latencyMedianFilterLong, newValue); - if (xSemaphoreTake (latencyBufSemaphoreHandle, pdMS_TO_TICKS (5)) == pdTRUE) - { - if (MEDIANFILTER_isFull (&latencyMedianFilterLong)) - { - latencyBuffFull = true; - } - - latencyToServer = medianValue; - - xSemaphoreGive (latencyBufSemaphoreHandle); - } - else - { - ESP_LOGW (TAG, "couldn't set latencyToServer = medianValue"); + medianValue = MEDIANFILTER_Insert(&latencyMedianFilterLong, newValue); + if (xSemaphoreTake(latencyBufSemaphoreHandle, pdMS_TO_TICKS(5)) == pdTRUE) { + if (MEDIANFILTER_isFull(&latencyMedianFilterLong)) { + latencyBuffFull = true; } + latencyToServer = medianValue; + + xSemaphoreGive(latencyBufSemaphoreHandle); + } else { + ESP_LOGW(TAG, "couldn't set latencyToServer = medianValue"); + } + return 0; } /** * */ -int8_t -player_send_snapcast_setting (snapcastSetting_t *setting) -{ +int8_t player_send_snapcast_setting(snapcastSetting_t *setting) { int ret; snapcastSetting_t curSet; uint8_t settingChanged = 1; - if ((syncTaskHandle == NULL) || (snapcastSettingQueueHandle == NULL)) - { - return pdFAIL; - } + if ((syncTaskHandle == NULL) || (snapcastSettingQueueHandle == NULL)) { + return pdFAIL; + } - ret = player_get_snapcast_settings (&curSet); + ret = player_get_snapcast_settings(&curSet); - if ((curSet.bits != setting->bits) || (curSet.buf_ms != setting->buf_ms) - || (curSet.ch != setting->ch) || (curSet.chkDur_ms != setting->chkDur_ms) - || (curSet.codec != setting->codec) || (curSet.muted != setting->muted) - || (curSet.sr != setting->sr) || (curSet.volume != setting->volume) - || (curSet.cDacLat_ms != setting->cDacLat_ms)) - { - // check if it is only volume / mute related setting, which is handled by - // http_get_task() - if (((curSet.muted != setting->muted) - || (curSet.volume != setting->volume)) - && ((curSet.bits == setting->bits) - && (curSet.buf_ms == setting->buf_ms) - && (curSet.ch == setting->ch) - && (curSet.chkDur_ms == setting->chkDur_ms) - && (curSet.codec == setting->codec) && (curSet.sr == setting->sr) - && (curSet.cDacLat_ms == setting->cDacLat_ms))) - { - // no notify needed, only set changed parameters - ret = player_set_snapcast_settings (setting); - if (ret != pdPASS) - { - ESP_LOGE (TAG, "player_send_snapcast_setting: couldn't change " - "snapcast setting"); - } - } - else - { - ret = xQueueOverwrite (snapcastSettingQueueHandle, &settingChanged); - if (ret != pdPASS) - { - ESP_LOGE (TAG, "player_send_snapcast_setting: couldn't notify " - "snapcast setting"); - } - else - { - // notify successful, so change parameters - ret = player_set_snapcast_settings (setting); - if (ret != pdPASS) - { - ESP_LOGE (TAG, "player_send_snapcast_setting: couldn't " - "change snapcast setting"); - } - } + if ((curSet.bits != setting->bits) || (curSet.buf_ms != setting->buf_ms) || + (curSet.ch != setting->ch) || (curSet.chkDur_ms != setting->chkDur_ms) || + (curSet.codec != setting->codec) || (curSet.muted != setting->muted) || + (curSet.sr != setting->sr) || (curSet.volume != setting->volume) || + (curSet.cDacLat_ms != setting->cDacLat_ms)) { + // check if it is only volume / mute related setting, which is handled by + // http_get_task() + if (((curSet.muted != setting->muted) || + (curSet.volume != setting->volume)) && + ((curSet.bits == setting->bits) && (curSet.buf_ms == setting->buf_ms) && + (curSet.ch == setting->ch) && + (curSet.chkDur_ms == setting->chkDur_ms) && + (curSet.codec == setting->codec) && (curSet.sr == setting->sr) && + (curSet.cDacLat_ms == setting->cDacLat_ms))) { + // no notify needed, only set changed parameters + ret = player_set_snapcast_settings(setting); + if (ret != pdPASS) { + ESP_LOGE(TAG, + "player_send_snapcast_setting: couldn't change " + "snapcast setting"); + } + } else { + ret = xQueueOverwrite(snapcastSettingQueueHandle, &settingChanged); + if (ret != pdPASS) { + ESP_LOGE(TAG, + "player_send_snapcast_setting: couldn't notify " + "snapcast setting"); + } else { + // notify successful, so change parameters + ret = player_set_snapcast_settings(setting); + if (ret != pdPASS) { + ESP_LOGE(TAG, + "player_send_snapcast_setting: couldn't " + "change snapcast setting"); } + } } + } return pdPASS; } @@ -446,38 +390,30 @@ player_send_snapcast_setting (snapcastSetting_t *setting) /** * */ -int8_t -reset_latency_buffer (void) -{ +int8_t reset_latency_buffer(void) { // init diff buff median filter - if (MEDIANFILTER_Init (&latencyMedianFilterLong) < 0) - { - ESP_LOGE (TAG, - "reset_diff_buffer: couldn't init median filter long. STOP"); + if (MEDIANFILTER_Init(&latencyMedianFilterLong) < 0) { + ESP_LOGE(TAG, "reset_diff_buffer: couldn't init median filter long. STOP"); - return -2; - } + return -2; + } - if (latencyBufSemaphoreHandle == NULL) - { - ESP_LOGE (TAG, "reset_diff_buffer: latencyBufSemaphoreHandle == NULL"); + if (latencyBufSemaphoreHandle == NULL) { + ESP_LOGE(TAG, "reset_diff_buffer: latencyBufSemaphoreHandle == NULL"); - return -2; - } + return -2; + } - if (xSemaphoreTake (latencyBufSemaphoreHandle, portMAX_DELAY) == pdTRUE) - { - latencyBuffFull = false; - latencyToServer = 0; + if (xSemaphoreTake(latencyBufSemaphoreHandle, portMAX_DELAY) == pdTRUE) { + latencyBuffFull = false; + latencyToServer = 0; - xSemaphoreGive (latencyBufSemaphoreHandle); - } - else - { - ESP_LOGW (TAG, "reset_diff_buffer: can't take semaphore"); + xSemaphoreGive(latencyBufSemaphoreHandle); + } else { + ESP_LOGW(TAG, "reset_diff_buffer: can't take semaphore"); - return -1; - } + return -1; + } return 0; } @@ -485,28 +421,24 @@ reset_latency_buffer (void) /** * */ -int8_t -latency_buffer_full (void) -{ +int8_t latency_buffer_full(void) { int8_t tmp; - if (latencyBufSemaphoreHandle == NULL) - { - ESP_LOGE (TAG, "latency_buffer_full: latencyBufSemaphoreHandle == NULL"); + if (latencyBufSemaphoreHandle == NULL) { + ESP_LOGE(TAG, "latency_buffer_full: latencyBufSemaphoreHandle == NULL"); - return -2; - } + return -2; + } - if (xSemaphoreTake (latencyBufSemaphoreHandle, 0) == pdFALSE) - { - ESP_LOGW (TAG, "latency_buffer_full: can't take semaphore"); + if (xSemaphoreTake(latencyBufSemaphoreHandle, 0) == pdFALSE) { + ESP_LOGW(TAG, "latency_buffer_full: can't take semaphore"); - return -1; - } + return -1; + } tmp = latencyBuffFull; - xSemaphoreGive (latencyBufSemaphoreHandle); + xSemaphoreGive(latencyBufSemaphoreHandle); return tmp; } @@ -514,33 +446,29 @@ latency_buffer_full (void) /** * */ -int8_t -get_diff_to_server (int64_t *tDiff) -{ +int8_t get_diff_to_server(int64_t *tDiff) { static int64_t lastDiff = 0; - if (latencyBufSemaphoreHandle == NULL) - { - ESP_LOGE (TAG, "get_diff_to_server: latencyBufSemaphoreHandle == NULL"); + if (latencyBufSemaphoreHandle == NULL) { + ESP_LOGE(TAG, "get_diff_to_server: latencyBufSemaphoreHandle == NULL"); - return -2; - } + return -2; + } - if (xSemaphoreTake (latencyBufSemaphoreHandle, 0) == pdFALSE) - { - *tDiff = lastDiff; + if (xSemaphoreTake(latencyBufSemaphoreHandle, 0) == pdFALSE) { + *tDiff = lastDiff; - ESP_LOGW ( - TAG, "get_diff_to_server: can't take semaphore. Old diff retrieved"); + ESP_LOGW(TAG, + "get_diff_to_server: can't take semaphore. Old diff retrieved"); - return -1; - } + return -1; + } *tDiff = latencyToServer; - lastDiff = latencyToServer; // store value, so we can return a value if - // semaphore couldn't be taken + lastDiff = latencyToServer; // store value, so we can return a value if + // semaphore couldn't be taken - xSemaphoreGive (latencyBufSemaphoreHandle); + xSemaphoreGive(latencyBufSemaphoreHandle); return 0; } @@ -548,33 +476,27 @@ get_diff_to_server (int64_t *tDiff) /** * */ -int8_t -server_now (int64_t *sNow) -{ +int8_t server_now(int64_t *sNow) { struct timeval now; int64_t diff; // get current time - if (gettimeofday (&now, NULL)) - { - ESP_LOGE (TAG, "server_now: Failed to get time of day"); + if (gettimeofday(&now, NULL)) { + ESP_LOGE(TAG, "server_now: Failed to get time of day"); - return -1; - } + return -1; + } - if (get_diff_to_server (&diff) == -1) - { - ESP_LOGW ( - TAG, - "server_now: can't get current diff to server. Retrieved old one"); - } + if (get_diff_to_server(&diff) == -1) { + ESP_LOGW(TAG, + "server_now: can't get current diff to server. Retrieved old one"); + } - if (diff == 0) - { - // ESP_LOGW(TAG, "server_now: diff to server not initialized yet"); + if (diff == 0) { + // ESP_LOGW(TAG, "server_now: diff to server not initialized yet"); - return -1; - } + return -1; + } *sNow = ((int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec) + diff; @@ -594,81 +516,67 @@ server_now (int64_t *sNow) * flash cache is disabled, we can allocate this interrupt without the * ESP_INTR_FLAG_IRAM flag and use the normal API. */ -void IRAM_ATTR -timer_group0_isr (void *para) -{ - timer_spinlock_take (TIMER_GROUP_0); +void IRAM_ATTR timer_group0_isr(void *para) { + timer_spinlock_take(TIMER_GROUP_0); BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Retrieve the interrupt status and the counter value // from the timer that reported the interrupt - uint32_t timer_intr = timer_group_get_intr_status_in_isr (TIMER_GROUP_0); + uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0); // Clear the interrupt // and update the alarm time for the timer with without reload - if (timer_intr & TIMER_INTR_T1) - { - timer_group_clr_intr_status_in_isr (TIMER_GROUP_0, TIMER_1); + if (timer_intr & TIMER_INTR_T1) { + timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1); - // Notify the task in the task's notification value. - xTaskNotifyFromISR (syncTaskHandle, 0, eNoAction, - &xHigherPriorityTaskWoken); - } + // Notify the task in the task's notification value. + xTaskNotifyFromISR(syncTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken); + } - timer_spinlock_give (TIMER_GROUP_0); + timer_spinlock_give(TIMER_GROUP_0); - if (xHigherPriorityTaskWoken) - { - portYIELD_FROM_ISR (); - } + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } } -static void -tg0_timer_deinit (void) -{ - timer_deinit (TIMER_GROUP_0, TIMER_1); -} +static void tg0_timer_deinit(void) { timer_deinit(TIMER_GROUP_0, TIMER_1); } /* * */ -static void -tg0_timer_init (void) -{ +static void tg0_timer_init(void) { // Select and initialize basic parameters of the timer timer_config_t config = { - //.divider = 8, // 100ns ticks - .divider = 80, // 1µs ticks - .counter_dir = TIMER_COUNT_UP, - .counter_en = TIMER_PAUSE, - .alarm_en = TIMER_ALARM_EN, - .auto_reload = TIMER_AUTORELOAD_DIS, - }; // default clock source is APB - timer_init (TIMER_GROUP_0, TIMER_1, &config); + //.divider = 8, // 100ns ticks + .divider = 80, // 1µs ticks + .counter_dir = TIMER_COUNT_UP, + .counter_en = TIMER_PAUSE, + .alarm_en = TIMER_ALARM_EN, + .auto_reload = TIMER_AUTORELOAD_DIS, + }; // default clock source is APB + timer_init(TIMER_GROUP_0, TIMER_1, &config); // Configure the alarm value and the interrupt on alarm. - timer_set_alarm_value (TIMER_GROUP_0, TIMER_1, 0); - timer_enable_intr (TIMER_GROUP_0, TIMER_1); - if (timer_isr_register (TIMER_GROUP_0, TIMER_1, timer_group0_isr, NULL, - ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL3, NULL) - != ESP_OK) - { - ESP_LOGE (TAG, "unable to register timer 1 callback"); - } + timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, 0); + timer_enable_intr(TIMER_GROUP_0, TIMER_1); + if (timer_isr_register(TIMER_GROUP_0, TIMER_1, timer_group0_isr, NULL, + ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL3, + NULL) != ESP_OK) { + ESP_LOGE(TAG, "unable to register timer 1 callback"); + } } /** * */ -static void -tg0_timer1_start (uint64_t alarm_value) -{ - timer_pause (TIMER_GROUP_0, TIMER_1); - timer_set_counter_value (TIMER_GROUP_0, TIMER_1, 0); - timer_set_alarm_value (TIMER_GROUP_0, TIMER_1, alarm_value); - timer_set_alarm (TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN); - timer_start (TIMER_GROUP_0, TIMER_1); +static void tg0_timer1_start(uint64_t alarm_value) { + timer_pause(TIMER_GROUP_0, TIMER_1); + timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0); + timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, alarm_value); + timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN); + timer_start(TIMER_GROUP_0, TIMER_1); // ESP_LOGI(TAG, "started age timer"); } @@ -677,45 +585,37 @@ tg0_timer1_start (uint64_t alarm_value) // sdm2, uint32_t o_div); apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + // sdm0/65536)/((o_div + 2) * 2) xtal == 40MHz on lyrat v4.3 I2S bit_clock = // rate * (number of channels) * bits_per_sample -void -adjust_apll (int8_t direction) -{ +void adjust_apll(int8_t direction) { int sdm0, sdm1, sdm2, o_div; // only change if necessary - if (currentDir == direction) - { - return; - } + if (currentDir == direction) { + return; + } - if (direction == 1) - { - // speed up - sdm0 = apll_corr_predefine[0][2]; - sdm1 = apll_corr_predefine[0][3]; - sdm2 = apll_corr_predefine[0][4]; - o_div = apll_corr_predefine[0][5]; - } - else if (direction == -1) - { - // slow down - sdm0 = apll_corr_predefine[1][2]; - sdm1 = apll_corr_predefine[1][3]; - sdm2 = apll_corr_predefine[1][4]; - o_div = apll_corr_predefine[1][5]; - } - else - { - // reset to normal playback speed - sdm0 = apll_normal_predefine[2]; - sdm1 = apll_normal_predefine[3]; - sdm2 = apll_normal_predefine[4]; - o_div = apll_normal_predefine[5]; + if (direction == 1) { + // speed up + sdm0 = apll_corr_predefine[0][2]; + sdm1 = apll_corr_predefine[0][3]; + sdm2 = apll_corr_predefine[0][4]; + o_div = apll_corr_predefine[0][5]; + } else if (direction == -1) { + // slow down + sdm0 = apll_corr_predefine[1][2]; + sdm1 = apll_corr_predefine[1][3]; + sdm2 = apll_corr_predefine[1][4]; + o_div = apll_corr_predefine[1][5]; + } else { + // reset to normal playback speed + sdm0 = apll_normal_predefine[2]; + sdm1 = apll_normal_predefine[3]; + sdm2 = apll_normal_predefine[4]; + o_div = apll_normal_predefine[5]; - direction = 0; - } + direction = 0; + } - rtc_clk_apll_enable (1, sdm0, sdm1, sdm2, o_div); + rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, o_div); currentDir = direction; } @@ -723,32 +623,25 @@ adjust_apll (int8_t direction) /** * */ -int8_t -free_pcm_chunk_fragments (pcm_chunk_fragment_t *fragment) -{ - if (fragment == NULL) - { - ESP_LOGE (TAG, "free_pcm_chunk_fragments() parameter Error"); +int8_t free_pcm_chunk_fragments(pcm_chunk_fragment_t *fragment) { + if (fragment == NULL) { + ESP_LOGE(TAG, "free_pcm_chunk_fragments() parameter Error"); - return -1; - } + return -1; + } // free all fragments recursive - if (fragment->nextFragment == NULL) - { - if (fragment->payload != NULL) - { - free (fragment->payload); - fragment->payload = NULL; - } + if (fragment->nextFragment == NULL) { + if (fragment->payload != NULL) { + free(fragment->payload); + fragment->payload = NULL; + } - free (fragment); - fragment = NULL; - } - else - { - free_pcm_chunk_fragments (fragment->nextFragment); - } + free(fragment); + fragment = NULL; + } else { + free_pcm_chunk_fragments(fragment->nextFragment); + } return 0; } @@ -756,29 +649,24 @@ free_pcm_chunk_fragments (pcm_chunk_fragment_t *fragment) /** * */ -int8_t -free_pcm_chunk (pcm_chunk_message_t *pcmChunk) -{ - if (pcmChunk == NULL) - { - ESP_LOGE (TAG, "free_pcm_chunk() parameter Error"); +int8_t free_pcm_chunk(pcm_chunk_message_t *pcmChunk) { + if (pcmChunk == NULL) { + ESP_LOGE(TAG, "free_pcm_chunk() parameter Error"); - return -1; - } + return -1; + } - free_pcm_chunk_fragments (pcmChunk->fragment); - pcmChunk->fragment = NULL; // was freed in free_pcm_chunk_fragments() + free_pcm_chunk_fragments(pcmChunk->fragment); + pcmChunk->fragment = NULL; // was freed in free_pcm_chunk_fragments() - free (pcmChunk); + free(pcmChunk); pcmChunk = NULL; return 0; } -int8_t -insert_pcm_chunk_IRAM (wire_chunk_message_t *decodedWireChunk, - pcm_chunk_message_t *pcmChunk) -{ +int8_t insert_pcm_chunk_IRAM(wire_chunk_message_t *decodedWireChunk, + pcm_chunk_message_t *pcmChunk) { size_t largestFreeBlock, freeMem; int ret = -3; @@ -786,1186 +674,1007 @@ insert_pcm_chunk_IRAM (wire_chunk_message_t *decodedWireChunk, // first we try to allocated 32 bit aligned memory for payload // check available memory first so we can decide if we need to fragment the // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - largestFreeBlock - = heap_caps_get_largest_free_block (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if ((freeMem >= decodedWireChunk->size) - && (largestFreeBlock >= decodedWireChunk->size)) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - decodedWireChunk->size, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - // copy the whole payload to our fragment - memcpy (pcmChunk->fragment->payload, decodedWireChunk->payload, - decodedWireChunk->size); - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = decodedWireChunk->size; - - ret = 0; - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", - // decodedWireChunk->size, - // freeMem, largestFreeBlock); - } - - return ret; -} - -int8_t -insert_pcm_chunk_DRAM (wire_chunk_message_t *decodedWireChunk, - pcm_chunk_message_t *pcmChunk) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); - largestFreeBlock = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); - if ((freeMem >= decodedWireChunk->size) - && (largestFreeBlock >= decodedWireChunk->size)) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - pcmChunk->fragment->payload - = (char *)heap_caps_malloc (decodedWireChunk->size, MALLOC_CAP_8BIT); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate DRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - // copy the whole payload to our fragment - memcpy (pcmChunk->fragment->payload, decodedWireChunk->payload, - decodedWireChunk->size); - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = decodedWireChunk->size; - - ret = 0; - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert chunk - // of size %d, DRAM freemem: %d blocksize %d", - // decodedWireChunk->size, freeMem, largestFreeBlock); - } - - return ret; -} - -int8_t -insert_pcm_chunk_IRAM_fragmented (wire_chunk_message_t *decodedWireChunk, - pcm_chunk_message_t *pcmChunk) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - size_t tmpSize; - pcm_chunk_fragment_t *next = NULL; - size_t s; - - freeMem = heap_caps_get_free_size (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - largestFreeBlock - = heap_caps_get_largest_free_block (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - // ESP_LOGW( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - // just to be sure, normally insert_pcm_chunk_IRAM() would have been called - // previously and this shouldn't be possible now - if (largestFreeBlock >= decodedWireChunk->size) - { - ret = insert_pcm_chunk_IRAM (decodedWireChunk, pcmChunk); - } - else - { - ret = 0; - - if (freeMem >= decodedWireChunk->size) - { - tmpSize = decodedWireChunk->size; - // heap_caps_aligned_alloc(sizeof(uint32_t), decodedWireChunk->size, - // MALLOC_CAP_32BIT); - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - largestFreeBlock, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate IRAM memory for pcm chunk " - "fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - next = pcmChunk->fragment; - s = largestFreeBlock; - - // loop until we have all data stored to a fragment - do - { - // copy the whole payload to our fragment - memcpy (next->payload, decodedWireChunk->payload, s); - next->size = s; - tmpSize -= s; - decodedWireChunk->payload += s; - - // ESP_LOGI (TAG,"%p %d", next->payload, - // next->size); - - if (tmpSize > 0) - { - next->nextFragment - = (pcm_chunk_fragment_t *)heap_caps_calloc ( - 1, sizeof (pcm_chunk_fragment_t), - MALLOC_CAP_8BIT); - if (next->nextFragment == NULL) - { - ESP_LOGE ( - TAG, - "Failed to allocate IRAM memory for next pcm " - "chunk fragment %d %d", - heap_caps_get_free_size (MALLOC_CAP_8BIT), - heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT)); - - // free_pcm_chunk - //(pcmChunk); - - ret = -3; - - break; - } - else - { - largestFreeBlock = heap_caps_get_largest_free_block ( - MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (largestFreeBlock <= tmpSize) - { - s = largestFreeBlock; - } - else - { - s = tmpSize; - } - - next->nextFragment->payload - = (char *)heap_caps_malloc ( - s, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (next->nextFragment->payload == NULL) - { - ESP_LOGE ( - TAG, - "Failed to allocate IRAM memory for pcm " - "chunk next fragmented payload"); - - // free_pcm_chunk - //(pcmChunk); - - ret = -3; - - break; - } - else - { - next = next->nextFragment; - } - } - } - } - while (tmpSize); - } - } - } - - /* - if (ret < 0) { -// freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); -// largestFreeBlock = heap_caps_get_largest_free_block -(MALLOC_CAP_8BIT); - // ESP_LOGW( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - // just to be sure, normally insert_pcm_chunk_DRAM() would have been -called previously and this shouldn't be possible now -// if (largestFreeBlock >= decodedWireChunk->size) -// { -// ret = insert_pcm_chunk_DRAM(decodedWireChunk, -pcmChunk); -// } -// else - { -// pcm_chunk_fragment_t *next = NULL; -// size_t s; - - ret = 0; - -// tmpSize = decodedWireChunk->size; - // heap_caps_aligned_alloc(sizeof(uint32_t), -decodedWireChunk->size, - // MALLOC_CAP_32BIT); - pcmChunk->fragment->payload - = (char *)heap_caps_malloc (largestFreeBlock, -MALLOC_CAP_8BIT); if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate DRAM memory for -pcm chunk " "fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - next = pcmChunk->fragment; - s = largestFreeBlock; - - // loop until we have all data stored to a fragment - do - { - // copy the whole payload to our fragment - memcpy (next->payload, -decodedWireChunk->payload, s); next->size = s; tmpSize -= s; - decodedWireChunk->payload += s; - -// ESP_LOGI (TAG,"%p %d", next->payload, next->size); - - if (tmpSize > 0) - { - next->nextFragment = -(pcm_chunk_fragment_t *)heap_caps_calloc ( 1, sizeof (pcm_chunk_fragment_t), -MALLOC_CAP_8BIT); if (next->nextFragment == NULL) - { - ESP_LOGE (TAG, - "Failed -to allocate DRAM memory for next pcm " "chunk fragment %d %d", - heap_caps_get_free_size -(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block ( MALLOC_CAP_8BIT)); - - free_pcm_chunk (pcmChunk); - - ret = -3; - - break; - } - else - { - largestFreeBlock = -heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); if (largestFreeBlock <= -tmpSize) - { - s = largestFreeBlock; - } - else - { - s = tmpSize; - } - - next->nextFragment->payload - = (char -*)heap_caps_malloc (s, MALLOC_CAP_8BIT); if (next->nextFragment->payload == -NULL) - { - ESP_LOGE (TAG, - "Failed to allocate DRAM memory for pcm " - "chunk next fragmented payload"); - - free_pcm_chunk -(pcmChunk); - - ret = -3; - - break; - } - else - { - next = -next->nextFragment; - } - } - } - } - while (tmpSize); - } - } - } - */ - - return ret; -} - -int8_t -insert_pcm_chunk_DRAM_fragmented (wire_chunk_message_t *decodedWireChunk, - pcm_chunk_message_t *pcmChunk) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - size_t tmpSize; - pcm_chunk_fragment_t *next = NULL; - size_t s; - - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); - largestFreeBlock = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); - // ESP_LOGW( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - // just to be sure, normally insert_pcm_chunk_IRAM() would have been called - // previously and this shouldn't be possible now - if (largestFreeBlock >= decodedWireChunk->size) - { - ret = insert_pcm_chunk_DRAM (decodedWireChunk, pcmChunk); - } - else - { - ret = 0; - - if (freeMem >= decodedWireChunk->size) - { - tmpSize = decodedWireChunk->size; - // heap_caps_aligned_alloc(sizeof(uint32_t), decodedWireChunk->size, - // MALLOC_CAP_32BIT); - pcmChunk->fragment->payload - = (char *)heap_caps_malloc (largestFreeBlock, MALLOC_CAP_8BIT); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate IRAM memory for pcm chunk " - "fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - next = pcmChunk->fragment; - s = largestFreeBlock; - - // loop until we have all data stored to a fragment - do - { - // copy the whole payload to our fragment - memcpy (next->payload, decodedWireChunk->payload, s); - next->size = s; - tmpSize -= s; - decodedWireChunk->payload += s; - - // ESP_LOGI (TAG,"%p %d", next->payload, - // next->size); - - if (tmpSize > 0) - { - next->nextFragment - = (pcm_chunk_fragment_t *)heap_caps_calloc ( - 1, sizeof (pcm_chunk_fragment_t), - MALLOC_CAP_8BIT); - if (next->nextFragment == NULL) - { - ESP_LOGE ( - TAG, - "Failed to allocate IRAM memory for next pcm " - "chunk fragment %d %d", - heap_caps_get_free_size (MALLOC_CAP_8BIT), - heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT)); - - // free_pcm_chunk - //(pcmChunk); - - ret = -3; - - break; - } - else - { - largestFreeBlock = heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT); - if (largestFreeBlock <= tmpSize) - { - s = largestFreeBlock; - } - else - { - s = tmpSize; - } - - next->nextFragment->payload - = (char *)heap_caps_malloc (s, MALLOC_CAP_8BIT); - if (next->nextFragment->payload == NULL) - { - ESP_LOGE ( - TAG, - "Failed to allocate IRAM memory for pcm " - "chunk next fragmented payload"); - - // free_pcm_chunk - //(pcmChunk); - - ret = -3; - - break; - } - else - { - next = next->nextFragment; - } - } - } - } - while (tmpSize); - } - } - } - - /* - if (ret < 0) { -// freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); -// largestFreeBlock = heap_caps_get_largest_free_block -(MALLOC_CAP_8BIT); - // ESP_LOGW( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - // just to be sure, normally insert_pcm_chunk_DRAM() would have been -called previously and this shouldn't be possible now -// if (largestFreeBlock >= decodedWireChunk->size) -// { -// ret = insert_pcm_chunk_DRAM(decodedWireChunk, -pcmChunk); -// } -// else - { -// pcm_chunk_fragment_t *next = NULL; -// size_t s; - - ret = 0; - -// tmpSize = decodedWireChunk->size; - // heap_caps_aligned_alloc(sizeof(uint32_t), -decodedWireChunk->size, - // MALLOC_CAP_32BIT); - pcmChunk->fragment->payload - = (char *)heap_caps_malloc (largestFreeBlock, -MALLOC_CAP_8BIT); if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate DRAM memory for -pcm chunk " "fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - next = pcmChunk->fragment; - s = largestFreeBlock; - - // loop until we have all data stored to a fragment - do - { - // copy the whole payload to our fragment - memcpy (next->payload, -decodedWireChunk->payload, s); next->size = s; tmpSize -= s; - decodedWireChunk->payload += s; - -// ESP_LOGI (TAG,"%p %d", next->payload, next->size); - - if (tmpSize > 0) - { - next->nextFragment = -(pcm_chunk_fragment_t *)heap_caps_calloc ( 1, sizeof (pcm_chunk_fragment_t), -MALLOC_CAP_8BIT); if (next->nextFragment == NULL) - { - ESP_LOGE (TAG, - "Failed -to allocate DRAM memory for next pcm " "chunk fragment %d %d", - heap_caps_get_free_size -(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block ( MALLOC_CAP_8BIT)); - - free_pcm_chunk (pcmChunk); - - ret = -3; - - break; - } - else - { - largestFreeBlock = -heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); if (largestFreeBlock <= -tmpSize) - { - s = largestFreeBlock; - } - else - { - s = tmpSize; - } - - next->nextFragment->payload - = (char -*)heap_caps_malloc (s, MALLOC_CAP_8BIT); if (next->nextFragment->payload == -NULL) - { - ESP_LOGE (TAG, - "Failed to allocate DRAM memory for pcm " - "chunk next fragmented payload"); - - free_pcm_chunk -(pcmChunk); - - ret = -3; - - break; - } - else - { - next = -next->nextFragment; - } - } - } - } - while (tmpSize); - } - } - } - */ - - return ret; -} - -/** - * - */ -int8_t -allocate_pcm_chunk_memory_caps (pcm_chunk_message_t *pcmChunk, size_t bytes, - uint32_t caps) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (caps); - largestFreeBlock = heap_caps_get_largest_free_block (caps); - if ((freeMem >= bytes) && (largestFreeBlock >= bytes)) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - pcmChunk->fragment->payload = (char *)heap_caps_malloc (bytes, caps); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - pcmChunk->totalSize = bytes; - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = bytes; - - ret = 0; - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", bytes, freeMem, - // largestFreeBlock); - } - - return ret; -} - -/** - * - */ -int8_t -allocate_pcm_chunk_memory_caps_fragmented (pcm_chunk_message_t *pcmChunk, - size_t bytes, uint32_t caps) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (caps); - largestFreeBlock = heap_caps_get_largest_free_block (caps); - if (freeMem >= bytes) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - if (largestFreeBlock >= bytes) - { - pcmChunk->fragment->payload = (char *)heap_caps_malloc (bytes, caps); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE ( - TAG, "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - pcmChunk->totalSize = bytes; - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = bytes; - - ret = 0; - } - } - else - { - size_t remainingBytes = bytes + (largestFreeBlock % 4); - size_t needBytes = largestFreeBlock - (largestFreeBlock % 4); - pcm_chunk_fragment_t *fragment = pcmChunk->fragment; - - pcmChunk->totalSize = 0; - - while (remainingBytes) - { - fragment->payload = (char *)heap_caps_malloc (needBytes, caps); - if (fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate fragmented IRAM memory for " - "pcm chunk payload %d %d %d %d", - needBytes, remainingBytes, - heap_caps_get_free_size (caps), - heap_caps_get_largest_free_block (caps)); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - - break; - } - else - { - fragment->size = needBytes; - remainingBytes -= needBytes; - pcmChunk->totalSize += needBytes; - - if (remainingBytes > 0) - { - fragment->nextFragment = (pcm_chunk_fragment_t *)calloc ( - 1, sizeof (pcm_chunk_fragment_t)); - if (fragment->nextFragment == NULL) - { - ESP_LOGE (TAG, "Failed to fragmented IRAM memory " - "for pcm chunk fragment"); - - ret = -2; - - break; - } - else - { - fragment = fragment->nextFragment; - largestFreeBlock - = heap_caps_get_largest_free_block (caps); - if (largestFreeBlock >= remainingBytes) - { - needBytes = remainingBytes; - } - else - { - needBytes - = largestFreeBlock - (largestFreeBlock % 4); - } - } - } - else - { - ret = 0; - } - } - } - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", - // decodedWireChunk->size, - // freeMem, largestFreeBlock); - } - - return ret; -} - -/** - * - */ -int8_t -allocate_pcm_chunk_memory_IRAM_fragmented (pcm_chunk_message_t *pcmChunk, - size_t bytes) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - largestFreeBlock - = heap_caps_get_largest_free_block (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (freeMem >= bytes) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - if (largestFreeBlock >= bytes) - { - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - bytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE ( - TAG, "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - pcmChunk->totalSize = bytes; - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = bytes; - - ret = 0; - } - } - else - { - size_t remainingBytes = bytes + (largestFreeBlock % 4); - size_t needBytes = largestFreeBlock - (largestFreeBlock % 4); - pcm_chunk_fragment_t *fragment = pcmChunk->fragment; - - pcmChunk->totalSize = 0; - - while (remainingBytes) - { - fragment->payload = (char *)heap_caps_malloc ( - needBytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate fragmented IRAM memory for " - "pcm chunk payload %d %d %d", - needBytes, largestFreeBlock, remainingBytes); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - - break; - } - else - { - fragment->size = needBytes; - remainingBytes -= needBytes; - pcmChunk->totalSize += needBytes; - - if (remainingBytes > 0) - { - fragment->nextFragment = (pcm_chunk_fragment_t *)calloc ( - 1, sizeof (pcm_chunk_fragment_t)); - if (fragment->nextFragment == NULL) - { - ESP_LOGE (TAG, "Failed to fragmented IRAM memory " - "for pcm chunk fragment"); - - ret = -2; - - break; - } - else - { - fragment = fragment->nextFragment; - largestFreeBlock = heap_caps_get_largest_free_block ( - MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (largestFreeBlock >= remainingBytes) - { - needBytes = remainingBytes; - } - else - { - needBytes - = largestFreeBlock - (largestFreeBlock % 4); - } - } - } - else - { - ret = 0; - } - } - } - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", - // decodedWireChunk->size, - // freeMem, largestFreeBlock); - } - - return ret; -} - -/** - * - */ -int8_t -allocate_pcm_chunk_memory_IRAM (pcm_chunk_message_t *pcmChunk, size_t bytes) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - largestFreeBlock - = heap_caps_get_largest_free_block (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if ((freeMem >= bytes) && (largestFreeBlock >= bytes)) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - bytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - pcmChunk->totalSize = bytes; - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = bytes; - - ret = 0; - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", - // decodedWireChunk->size, - // freeMem, largestFreeBlock); - } - - return ret; -} - -/** - * - */ -int8_t -allocate_pcm_chunk_memory_DRAM_fragmented (pcm_chunk_message_t *pcmChunk, - size_t bytes) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); - largestFreeBlock = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); - if (freeMem >= bytes) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - if (largestFreeBlock >= bytes) - { - pcmChunk->fragment->payload - = (char *)heap_caps_malloc (bytes, MALLOC_CAP_8BIT); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE ( - TAG, "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - pcmChunk->totalSize = bytes; - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = bytes; - - ret = 0; - } - } - else - { - size_t remainingBytes = bytes + (largestFreeBlock % 4); - size_t needBytes = largestFreeBlock - (largestFreeBlock % 4); - pcm_chunk_fragment_t *fragment = pcmChunk->fragment; - - pcmChunk->totalSize = 0; - - while (remainingBytes) - { - fragment->payload - = (char *)heap_caps_malloc (needBytes, MALLOC_CAP_8BIT); - if (fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate fragmented IRAM memory for " - "pcm chunk payload %d %d %d", - needBytes, largestFreeBlock, remainingBytes); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - - break; - } - else - { - fragment->size = needBytes; - remainingBytes -= needBytes; - pcmChunk->totalSize += needBytes; - - if (remainingBytes > 0) - { - fragment->nextFragment = (pcm_chunk_fragment_t *)calloc ( - 1, sizeof (pcm_chunk_fragment_t)); - if (fragment->nextFragment == NULL) - { - ESP_LOGE (TAG, "Failed to fragmented IRAM memory " - "for pcm chunk fragment"); - - ret = -2; - - break; - } - else - { - fragment = fragment->nextFragment; - largestFreeBlock = heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT); - if (largestFreeBlock >= remainingBytes) - { - needBytes = remainingBytes; - } - else - { - needBytes - = largestFreeBlock - (largestFreeBlock % 4); - } - } - } - else - { - ret = 0; - } - } - } - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", - // decodedWireChunk->size, - // freeMem, largestFreeBlock); - } - - return ret; -} - -/** - * - */ -int8_t -allocate_pcm_chunk_memory_DRAM (pcm_chunk_message_t *pcmChunk, size_t bytes) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - // we got valid memory for pcm_chunk_message_t - // first we try to allocated 32 bit aligned memory for payload - // check available memory first so we can decide if we need to fragment the - // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); - largestFreeBlock = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); - if ((freeMem >= bytes) && (largestFreeBlock >= bytes)) - { - // ESP_LOGI( - // TAG, - // "32b f %d b %d", freeMem, - // largestFreeBlock); - - pcmChunk->fragment->payload - = (char *)heap_caps_malloc (bytes, MALLOC_CAP_8BIT); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate IRAM memory for pcm chunk payload"); - - // free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - pcmChunk->totalSize = bytes; - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = bytes; - - ret = 0; - } - } - else - { - // ESP_LOGE (TAG, "couldn't get memory to insert - // chunk of size %d, IRAM freemem: %d blocksize %d", - // decodedWireChunk->size, - // freeMem, largestFreeBlock); - } - - return ret; -} - -int8_t -allocate_pcm_chunk_memory (pcm_chunk_message_t **pcmChunk, size_t bytes) -{ - size_t largestFreeBlock, freeMem; - int ret = -3; - - *pcmChunk = (pcm_chunk_message_t *)calloc (1, sizeof (pcm_chunk_message_t)); - if (*pcmChunk == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk message"); - - return -2; - } - - (*pcmChunk)->fragment - = (pcm_chunk_fragment_t *)calloc (1, sizeof (pcm_chunk_fragment_t)); - if ((*pcmChunk)->fragment == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk fragment"); - - free_pcm_chunk (*pcmChunk); - - return -2; - } - -#if CONFIG_USE_PSRAM - (*pcmChunk)->fragment->payload - = (char *)heap_caps_malloc (bytes, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - if ((*pcmChunk)->fragment->payload == NULL) - { - // ESP_LOGE (TAG, - // "Failed to allocate memory for pcm chunk - // fragment payload"); - - // free_pcm_chunk (pcmChunk); - - // freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT | - // MALLOC_CAP_SPIRAM); + freeMem = heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if ((freeMem >= decodedWireChunk->size) && + (largestFreeBlock >= decodedWireChunk->size)) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + pcmChunk->fragment->payload = (char *)heap_caps_malloc( + decodedWireChunk->size, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); ret = -2; - } - else - { - (*pcmChunk)->fragment->nextFragment = NULL; - (*pcmChunk)->fragment->size = bytes; + } else { + // copy the whole payload to our fragment + memcpy(pcmChunk->fragment->payload, decodedWireChunk->payload, + decodedWireChunk->size); + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = decodedWireChunk->size; ret = 0; } -#else - ret = allocate_pcm_chunk_memory_caps (*pcmChunk, bytes, - MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (ret < 0) - { - ret = allocate_pcm_chunk_memory_caps (*pcmChunk, bytes, MALLOC_CAP_8BIT); - if (ret < 0) - { - // ret = allocate_pcm_chunk_memory_caps_fragmented - //(*pcmChunk, bytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (ret < 0) - { - // allocate_pcm_chunk_memory_caps_fragmented (*pcmChunk, bytes, - // MALLOC_CAP_8BIT); - } - } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", + // decodedWireChunk->size, + // freeMem, largestFreeBlock); + } + + return ret; +} + +int8_t insert_pcm_chunk_DRAM(wire_chunk_message_t *decodedWireChunk, + pcm_chunk_message_t *pcmChunk) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT); + largestFreeBlock = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + if ((freeMem >= decodedWireChunk->size) && + (largestFreeBlock >= decodedWireChunk->size)) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(decodedWireChunk->size, MALLOC_CAP_8BIT); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate DRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + // copy the whole payload to our fragment + memcpy(pcmChunk->fragment->payload, decodedWireChunk->payload, + decodedWireChunk->size); + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = decodedWireChunk->size; + + ret = 0; } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert chunk + // of size %d, DRAM freemem: %d blocksize %d", + // decodedWireChunk->size, freeMem, largestFreeBlock); + } + + return ret; +} + +int8_t insert_pcm_chunk_IRAM_fragmented(wire_chunk_message_t *decodedWireChunk, + pcm_chunk_message_t *pcmChunk) { + size_t largestFreeBlock, freeMem; + int ret = -3; + size_t tmpSize; + pcm_chunk_fragment_t *next = NULL; + size_t s; + + freeMem = heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + // ESP_LOGW( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + // just to be sure, normally insert_pcm_chunk_IRAM() would have been called + // previously and this shouldn't be possible now + if (largestFreeBlock >= decodedWireChunk->size) { + ret = insert_pcm_chunk_IRAM(decodedWireChunk, pcmChunk); + } else { + ret = 0; + + if (freeMem >= decodedWireChunk->size) { + tmpSize = decodedWireChunk->size; + // heap_caps_aligned_alloc(sizeof(uint32_t), decodedWireChunk->size, + // MALLOC_CAP_32BIT); + pcmChunk->fragment->payload = (char *)heap_caps_malloc( + largestFreeBlock, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate IRAM memory for pcm chunk " + "fragmented payload"); + + free_pcm_chunk(pcmChunk); + + ret = -2; + } else { + next = pcmChunk->fragment; + s = largestFreeBlock; + + // loop until we have all data stored to a fragment + do { + // copy the whole payload to our fragment + memcpy(next->payload, decodedWireChunk->payload, s); + next->size = s; + tmpSize -= s; + decodedWireChunk->payload += s; + + // ESP_LOGI (TAG,"%p %d", next->payload, + // next->size); + + if (tmpSize > 0) { + next->nextFragment = (pcm_chunk_fragment_t *)heap_caps_calloc( + 1, sizeof(pcm_chunk_fragment_t), MALLOC_CAP_8BIT); + if (next->nextFragment == NULL) { + ESP_LOGE(TAG, + "Failed to allocate IRAM memory for next pcm " + "chunk fragment %d %d", + heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); + + // free_pcm_chunk + //(pcmChunk); + + ret = -3; + + break; + } else { + largestFreeBlock = heap_caps_get_largest_free_block( + MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (largestFreeBlock <= tmpSize) { + s = largestFreeBlock; + } else { + s = tmpSize; + } + + next->nextFragment->payload = (char *)heap_caps_malloc( + s, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (next->nextFragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate IRAM memory for pcm " + "chunk next fragmented payload"); + + // free_pcm_chunk + //(pcmChunk); + + ret = -3; + + break; + } else { + next = next->nextFragment; + } + } + } + } while (tmpSize); + } + } + } + + /* + if (ret < 0) { +// freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); +// largestFreeBlock = heap_caps_get_largest_free_block +(MALLOC_CAP_8BIT); + // ESP_LOGW( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + // just to be sure, normally insert_pcm_chunk_DRAM() would have been +called previously and this shouldn't be possible now +// if (largestFreeBlock >= decodedWireChunk->size) +// { +// ret = insert_pcm_chunk_DRAM(decodedWireChunk, +pcmChunk); +// } +// else + { +// pcm_chunk_fragment_t *next = NULL; +// size_t s; + + ret = 0; + +// tmpSize = decodedWireChunk->size; + // heap_caps_aligned_alloc(sizeof(uint32_t), +decodedWireChunk->size, + // MALLOC_CAP_32BIT); + pcmChunk->fragment->payload + = (char *)heap_caps_malloc (largestFreeBlock, +MALLOC_CAP_8BIT); if (pcmChunk->fragment->payload == NULL) + { + ESP_LOGE (TAG, "Failed to allocate DRAM memory for +pcm chunk " "fragmented payload"); + + free_pcm_chunk (pcmChunk); + + ret = -2; + } + else + { + next = pcmChunk->fragment; + s = largestFreeBlock; + + // loop until we have all data stored to a fragment + do + { + // copy the whole payload to our fragment + memcpy (next->payload, +decodedWireChunk->payload, s); next->size = s; tmpSize -= s; + decodedWireChunk->payload += s; + +// ESP_LOGI (TAG,"%p %d", next->payload, next->size); + + if (tmpSize > 0) + { + next->nextFragment = +(pcm_chunk_fragment_t *)heap_caps_calloc ( 1, sizeof (pcm_chunk_fragment_t), +MALLOC_CAP_8BIT); if (next->nextFragment == NULL) + { + ESP_LOGE (TAG, + "Failed +to allocate DRAM memory for next pcm " "chunk fragment %d %d", + heap_caps_get_free_size +(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block ( MALLOC_CAP_8BIT)); + + free_pcm_chunk (pcmChunk); + + ret = -3; + + break; + } + else + { + largestFreeBlock = +heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); if (largestFreeBlock <= +tmpSize) + { + s = largestFreeBlock; + } + else + { + s = tmpSize; + } + + next->nextFragment->payload + = (char +*)heap_caps_malloc (s, MALLOC_CAP_8BIT); if (next->nextFragment->payload == +NULL) + { + ESP_LOGE (TAG, + "Failed to allocate DRAM memory for pcm " + "chunk next fragmented payload"); + + free_pcm_chunk +(pcmChunk); + + ret = -3; + + break; + } + else + { + next = +next->nextFragment; + } + } + } + } + while (tmpSize); + } + } + } + */ + + return ret; +} + +int8_t insert_pcm_chunk_DRAM_fragmented(wire_chunk_message_t *decodedWireChunk, + pcm_chunk_message_t *pcmChunk) { + size_t largestFreeBlock, freeMem; + int ret = -3; + size_t tmpSize; + pcm_chunk_fragment_t *next = NULL; + size_t s; + + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT); + largestFreeBlock = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + // ESP_LOGW( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + // just to be sure, normally insert_pcm_chunk_IRAM() would have been called + // previously and this shouldn't be possible now + if (largestFreeBlock >= decodedWireChunk->size) { + ret = insert_pcm_chunk_DRAM(decodedWireChunk, pcmChunk); + } else { + ret = 0; + + if (freeMem >= decodedWireChunk->size) { + tmpSize = decodedWireChunk->size; + // heap_caps_aligned_alloc(sizeof(uint32_t), decodedWireChunk->size, + // MALLOC_CAP_32BIT); + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(largestFreeBlock, MALLOC_CAP_8BIT); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate IRAM memory for pcm chunk " + "fragmented payload"); + + free_pcm_chunk(pcmChunk); + + ret = -2; + } else { + next = pcmChunk->fragment; + s = largestFreeBlock; + + // loop until we have all data stored to a fragment + do { + // copy the whole payload to our fragment + memcpy(next->payload, decodedWireChunk->payload, s); + next->size = s; + tmpSize -= s; + decodedWireChunk->payload += s; + + // ESP_LOGI (TAG,"%p %d", next->payload, + // next->size); + + if (tmpSize > 0) { + next->nextFragment = (pcm_chunk_fragment_t *)heap_caps_calloc( + 1, sizeof(pcm_chunk_fragment_t), MALLOC_CAP_8BIT); + if (next->nextFragment == NULL) { + ESP_LOGE(TAG, + "Failed to allocate IRAM memory for next pcm " + "chunk fragment %d %d", + heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); + + // free_pcm_chunk + //(pcmChunk); + + ret = -3; + + break; + } else { + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + if (largestFreeBlock <= tmpSize) { + s = largestFreeBlock; + } else { + s = tmpSize; + } + + next->nextFragment->payload = + (char *)heap_caps_malloc(s, MALLOC_CAP_8BIT); + if (next->nextFragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate IRAM memory for pcm " + "chunk next fragmented payload"); + + // free_pcm_chunk + //(pcmChunk); + + ret = -3; + + break; + } else { + next = next->nextFragment; + } + } + } + } while (tmpSize); + } + } + } + + /* + if (ret < 0) { +// freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); +// largestFreeBlock = heap_caps_get_largest_free_block +(MALLOC_CAP_8BIT); + // ESP_LOGW( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + // just to be sure, normally insert_pcm_chunk_DRAM() would have been +called previously and this shouldn't be possible now +// if (largestFreeBlock >= decodedWireChunk->size) +// { +// ret = insert_pcm_chunk_DRAM(decodedWireChunk, +pcmChunk); +// } +// else + { +// pcm_chunk_fragment_t *next = NULL; +// size_t s; + + ret = 0; + +// tmpSize = decodedWireChunk->size; + // heap_caps_aligned_alloc(sizeof(uint32_t), +decodedWireChunk->size, + // MALLOC_CAP_32BIT); + pcmChunk->fragment->payload + = (char *)heap_caps_malloc (largestFreeBlock, +MALLOC_CAP_8BIT); if (pcmChunk->fragment->payload == NULL) + { + ESP_LOGE (TAG, "Failed to allocate DRAM memory for +pcm chunk " "fragmented payload"); + + free_pcm_chunk (pcmChunk); + + ret = -2; + } + else + { + next = pcmChunk->fragment; + s = largestFreeBlock; + + // loop until we have all data stored to a fragment + do + { + // copy the whole payload to our fragment + memcpy (next->payload, +decodedWireChunk->payload, s); next->size = s; tmpSize -= s; + decodedWireChunk->payload += s; + +// ESP_LOGI (TAG,"%p %d", next->payload, next->size); + + if (tmpSize > 0) + { + next->nextFragment = +(pcm_chunk_fragment_t *)heap_caps_calloc ( 1, sizeof (pcm_chunk_fragment_t), +MALLOC_CAP_8BIT); if (next->nextFragment == NULL) + { + ESP_LOGE (TAG, + "Failed +to allocate DRAM memory for next pcm " "chunk fragment %d %d", + heap_caps_get_free_size +(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block ( MALLOC_CAP_8BIT)); + + free_pcm_chunk (pcmChunk); + + ret = -3; + + break; + } + else + { + largestFreeBlock = +heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); if (largestFreeBlock <= +tmpSize) + { + s = largestFreeBlock; + } + else + { + s = tmpSize; + } + + next->nextFragment->payload + = (char +*)heap_caps_malloc (s, MALLOC_CAP_8BIT); if (next->nextFragment->payload == +NULL) + { + ESP_LOGE (TAG, + "Failed to allocate DRAM memory for pcm " + "chunk next fragmented payload"); + + free_pcm_chunk +(pcmChunk); + + ret = -3; + + break; + } + else + { + next = +next->nextFragment; + } + } + } + } + while (tmpSize); + } + } + } + */ + + return ret; +} + +/** + * + */ +int8_t allocate_pcm_chunk_memory_caps(pcm_chunk_message_t *pcmChunk, + size_t bytes, uint32_t caps) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(caps); + largestFreeBlock = heap_caps_get_largest_free_block(caps); + if ((freeMem >= bytes) && (largestFreeBlock >= bytes)) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + pcmChunk->fragment->payload = (char *)heap_caps_malloc(bytes, caps); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + pcmChunk->totalSize = bytes; + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = bytes; + + ret = 0; + } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", bytes, freeMem, + // largestFreeBlock); + } + + return ret; +} + +/** + * + */ +int8_t allocate_pcm_chunk_memory_caps_fragmented(pcm_chunk_message_t *pcmChunk, + size_t bytes, uint32_t caps) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(caps); + largestFreeBlock = heap_caps_get_largest_free_block(caps); + if (freeMem >= bytes) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + if (largestFreeBlock >= bytes) { + pcmChunk->fragment->payload = (char *)heap_caps_malloc(bytes, caps); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + pcmChunk->totalSize = bytes; + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = bytes; + + ret = 0; + } + } else { + size_t remainingBytes = bytes + (largestFreeBlock % 4); + size_t needBytes = largestFreeBlock - (largestFreeBlock % 4); + pcm_chunk_fragment_t *fragment = pcmChunk->fragment; + + pcmChunk->totalSize = 0; + + while (remainingBytes) { + fragment->payload = (char *)heap_caps_malloc(needBytes, caps); + if (fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate fragmented IRAM memory for " + "pcm chunk payload %d %d %d %d", + needBytes, remainingBytes, heap_caps_get_free_size(caps), + heap_caps_get_largest_free_block(caps)); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + + break; + } else { + fragment->size = needBytes; + remainingBytes -= needBytes; + pcmChunk->totalSize += needBytes; + + if (remainingBytes > 0) { + fragment->nextFragment = + (pcm_chunk_fragment_t *)calloc(1, sizeof(pcm_chunk_fragment_t)); + if (fragment->nextFragment == NULL) { + ESP_LOGE(TAG, + "Failed to fragmented IRAM memory " + "for pcm chunk fragment"); + + ret = -2; + + break; + } else { + fragment = fragment->nextFragment; + largestFreeBlock = heap_caps_get_largest_free_block(caps); + if (largestFreeBlock >= remainingBytes) { + needBytes = remainingBytes; + } else { + needBytes = largestFreeBlock - (largestFreeBlock % 4); + } + } + } else { + ret = 0; + } + } + } + } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", + // decodedWireChunk->size, + // freeMem, largestFreeBlock); + } + + return ret; +} + +/** + * + */ +int8_t allocate_pcm_chunk_memory_IRAM_fragmented(pcm_chunk_message_t *pcmChunk, + size_t bytes) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (freeMem >= bytes) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + if (largestFreeBlock >= bytes) { + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(bytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + pcmChunk->totalSize = bytes; + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = bytes; + + ret = 0; + } + } else { + size_t remainingBytes = bytes + (largestFreeBlock % 4); + size_t needBytes = largestFreeBlock - (largestFreeBlock % 4); + pcm_chunk_fragment_t *fragment = pcmChunk->fragment; + + pcmChunk->totalSize = 0; + + while (remainingBytes) { + fragment->payload = (char *)heap_caps_malloc( + needBytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate fragmented IRAM memory for " + "pcm chunk payload %d %d %d", + needBytes, largestFreeBlock, remainingBytes); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + + break; + } else { + fragment->size = needBytes; + remainingBytes -= needBytes; + pcmChunk->totalSize += needBytes; + + if (remainingBytes > 0) { + fragment->nextFragment = + (pcm_chunk_fragment_t *)calloc(1, sizeof(pcm_chunk_fragment_t)); + if (fragment->nextFragment == NULL) { + ESP_LOGE(TAG, + "Failed to fragmented IRAM memory " + "for pcm chunk fragment"); + + ret = -2; + + break; + } else { + fragment = fragment->nextFragment; + largestFreeBlock = heap_caps_get_largest_free_block( + MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (largestFreeBlock >= remainingBytes) { + needBytes = remainingBytes; + } else { + needBytes = largestFreeBlock - (largestFreeBlock % 4); + } + } + } else { + ret = 0; + } + } + } + } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", + // decodedWireChunk->size, + // freeMem, largestFreeBlock); + } + + return ret; +} + +/** + * + */ +int8_t allocate_pcm_chunk_memory_IRAM(pcm_chunk_message_t *pcmChunk, + size_t bytes) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if ((freeMem >= bytes) && (largestFreeBlock >= bytes)) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(bytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + pcmChunk->totalSize = bytes; + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = bytes; + + ret = 0; + } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", + // decodedWireChunk->size, + // freeMem, largestFreeBlock); + } + + return ret; +} + +/** + * + */ +int8_t allocate_pcm_chunk_memory_DRAM_fragmented(pcm_chunk_message_t *pcmChunk, + size_t bytes) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT); + largestFreeBlock = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + if (freeMem >= bytes) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + if (largestFreeBlock >= bytes) { + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(bytes, MALLOC_CAP_8BIT); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + pcmChunk->totalSize = bytes; + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = bytes; + + ret = 0; + } + } else { + size_t remainingBytes = bytes + (largestFreeBlock % 4); + size_t needBytes = largestFreeBlock - (largestFreeBlock % 4); + pcm_chunk_fragment_t *fragment = pcmChunk->fragment; + + pcmChunk->totalSize = 0; + + while (remainingBytes) { + fragment->payload = + (char *)heap_caps_malloc(needBytes, MALLOC_CAP_8BIT); + if (fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate fragmented IRAM memory for " + "pcm chunk payload %d %d %d", + needBytes, largestFreeBlock, remainingBytes); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + + break; + } else { + fragment->size = needBytes; + remainingBytes -= needBytes; + pcmChunk->totalSize += needBytes; + + if (remainingBytes > 0) { + fragment->nextFragment = + (pcm_chunk_fragment_t *)calloc(1, sizeof(pcm_chunk_fragment_t)); + if (fragment->nextFragment == NULL) { + ESP_LOGE(TAG, + "Failed to fragmented IRAM memory " + "for pcm chunk fragment"); + + ret = -2; + + break; + } else { + fragment = fragment->nextFragment; + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + if (largestFreeBlock >= remainingBytes) { + needBytes = remainingBytes; + } else { + needBytes = largestFreeBlock - (largestFreeBlock % 4); + } + } + } else { + ret = 0; + } + } + } + } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", + // decodedWireChunk->size, + // freeMem, largestFreeBlock); + } + + return ret; +} + +/** + * + */ +int8_t allocate_pcm_chunk_memory_DRAM(pcm_chunk_message_t *pcmChunk, + size_t bytes) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + // we got valid memory for pcm_chunk_message_t + // first we try to allocated 32 bit aligned memory for payload + // check available memory first so we can decide if we need to fragment the + // data + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT); + largestFreeBlock = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + if ((freeMem >= bytes) && (largestFreeBlock >= bytes)) { + // ESP_LOGI( + // TAG, + // "32b f %d b %d", freeMem, + // largestFreeBlock); + + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(bytes, MALLOC_CAP_8BIT); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate IRAM memory for pcm chunk payload"); + + // free_pcm_chunk (pcmChunk); + + ret = -2; + } else { + pcmChunk->totalSize = bytes; + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = bytes; + + ret = 0; + } + } else { + // ESP_LOGE (TAG, "couldn't get memory to insert + // chunk of size %d, IRAM freemem: %d blocksize %d", + // decodedWireChunk->size, + // freeMem, largestFreeBlock); + } + + return ret; +} + +int8_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk, size_t bytes) { + size_t largestFreeBlock, freeMem; + int ret = -3; + + *pcmChunk = (pcm_chunk_message_t *)calloc(1, sizeof(pcm_chunk_message_t)); + if (*pcmChunk == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for pcm chunk message"); + + return -2; + } + + (*pcmChunk)->fragment = + (pcm_chunk_fragment_t *)calloc(1, sizeof(pcm_chunk_fragment_t)); + if ((*pcmChunk)->fragment == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for pcm chunk fragment"); + + free_pcm_chunk(*pcmChunk); + + return -2; + } + +#if CONFIG_USE_PSRAM + (*pcmChunk)->fragment->payload = + (char *)heap_caps_malloc(bytes, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + if ((*pcmChunk)->fragment->payload == NULL) { + // ESP_LOGE (TAG, + // "Failed to allocate memory for pcm chunk + // fragment payload"); + + // free_pcm_chunk (pcmChunk); + + // freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT | + // MALLOC_CAP_SPIRAM); + + ret = -2; + } else { + (*pcmChunk)->fragment->nextFragment = NULL; + (*pcmChunk)->fragment->size = bytes; + + ret = 0; + } +#else + ret = allocate_pcm_chunk_memory_caps(*pcmChunk, bytes, + MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (ret < 0) { + ret = allocate_pcm_chunk_memory_caps(*pcmChunk, bytes, MALLOC_CAP_8BIT); + if (ret < 0) { + // ret = allocate_pcm_chunk_memory_caps_fragmented + //(*pcmChunk, bytes, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (ret < 0) { + // allocate_pcm_chunk_memory_caps_fragmented (*pcmChunk, bytes, + // MALLOC_CAP_8BIT); + } + } + } // ret = allocate_pcm_chunk_memory_IRAM (*pcmChunk, bytes); // if (ret < 0) { // ret = allocate_pcm_chunk_memory_DRAM (*pcmChunk, bytes); @@ -1979,53 +1688,44 @@ allocate_pcm_chunk_memory (pcm_chunk_message_t **pcmChunk, size_t bytes) // } #endif - if (ret < 0) - { - ESP_LOGE (TAG, "couldn't get memory to insert chunk"); + if (ret < 0) { + ESP_LOGE(TAG, "couldn't get memory to insert chunk"); - ESP_LOGI (TAG, "%d, %d, %d, %d, %d", - heap_caps_get_free_size (MALLOC_CAP_8BIT), - heap_caps_get_largest_free_block (MALLOC_CAP_8BIT), - uxQueueMessagesWaiting (pcmChkQHdl), - heap_caps_get_free_size (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC), - heap_caps_get_largest_free_block (MALLOC_CAP_32BIT - | MALLOC_CAP_EXEC)); + ESP_LOGI( + TAG, "%d, %d, %d, %d, %d", heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT), + uxQueueMessagesWaiting(pcmChkQHdl), + heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC), + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC)); - free_pcm_chunk (*pcmChunk); - } - else - { - // ESP_LOGI (TAG, "got memory for pcm chunk %p %p %d", *pcmChunk, - // (*pcmChunk)->fragment->payload, bytes); - } + free_pcm_chunk(*pcmChunk); + } else { + // ESP_LOGI (TAG, "got memory for pcm chunk %p %p %d", *pcmChunk, + // (*pcmChunk)->fragment->payload, bytes); + } return ret; } -int8_t -insert_pcm_chunk (pcm_chunk_message_t *pcmChunk) -{ - if (pcmChunk == NULL) - { - ESP_LOGE (TAG, "Parameter Error"); +int8_t insert_pcm_chunk(pcm_chunk_message_t *pcmChunk) { + if (pcmChunk == NULL) { + ESP_LOGE(TAG, "Parameter Error"); - return -1; - } + return -1; + } - if (pcmChkQHdl == NULL) - { - ESP_LOGW (TAG, "pcm chunk queue not created"); + if (pcmChkQHdl == NULL) { + ESP_LOGW(TAG, "pcm chunk queue not created"); - return -2; - } + return -2; + } - if (xQueueSendToBack (pcmChkQHdl, &pcmChunk, pdMS_TO_TICKS (1000)) != pdTRUE) - { - ESP_LOGW (TAG, "send: pcmChunkQueue full, messages waiting %d", - uxQueueMessagesWaiting (pcmChkQHdl)); + if (xQueueSendToBack(pcmChkQHdl, &pcmChunk, pdMS_TO_TICKS(1000)) != pdTRUE) { + ESP_LOGW(TAG, "send: pcmChunkQueue full, messages waiting %d", + uxQueueMessagesWaiting(pcmChkQHdl)); - free_pcm_chunk (pcmChunk); - } + free_pcm_chunk(pcmChunk); + } return 0; } @@ -2033,9 +1733,7 @@ insert_pcm_chunk (pcm_chunk_message_t *pcmChunk) /** * */ -int8_t -insert_pcm_chunk_backup (wire_chunk_message_t *decodedWireChunk) -{ +int8_t insert_pcm_chunk_backup(wire_chunk_message_t *decodedWireChunk) { pcm_chunk_message_t *pcmChunk; size_t tmpSize; size_t largestFreeBlock, freeMem; @@ -2046,373 +1744,312 @@ insert_pcm_chunk_backup (wire_chunk_message_t *decodedWireChunk) // heap_caps_get_free_size(MALLOC_CAP_32BIT); // heap_caps_get_largest_free_block(MALLOC_CAP_32BIT); - if (decodedWireChunk == NULL) - { - ESP_LOGE (TAG, "Parameter Error"); + if (decodedWireChunk == NULL) { + ESP_LOGE(TAG, "Parameter Error"); - return -1; - } + return -1; + } - if (pcmChkQHdl == NULL) - { - ESP_LOGW (TAG, "pcm chunk queue not created"); + if (pcmChkQHdl == NULL) { + ESP_LOGW(TAG, "pcm chunk queue not created"); - return -2; - } + return -2; + } - pcmChunk = (pcm_chunk_message_t *)calloc (1, sizeof (pcm_chunk_message_t)); - if (pcmChunk == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk message"); + pcmChunk = (pcm_chunk_message_t *)calloc(1, sizeof(pcm_chunk_message_t)); + if (pcmChunk == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for pcm chunk message"); - return -2; - } + return -2; + } - pcmChunk->fragment - = (pcm_chunk_fragment_t *)calloc (1, sizeof (pcm_chunk_fragment_t)); - if (pcmChunk->fragment == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk fragment"); + pcmChunk->fragment = + (pcm_chunk_fragment_t *)calloc(1, sizeof(pcm_chunk_fragment_t)); + if (pcmChunk->fragment == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for pcm chunk fragment"); - free_pcm_chunk (pcmChunk); + free_pcm_chunk(pcmChunk); - return -2; - } + return -2; + } // store the timestamp pcmChunk->timestamp = decodedWireChunk->timestamp; #if CONFIG_USE_PSRAM - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - largestFreeBlock - = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( + pcmChunk->fragment->payload = (char *)heap_caps_malloc( decodedWireChunk->size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate memory for pcm chunk fragment payload"); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for pcm chunk fragment payload"); - free_pcm_chunk (pcmChunk); + free_pcm_chunk(pcmChunk); - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - ret = -2; - } - else - { - // copy the whole payload to our fragment - memcpy (pcmChunk->fragment->payload, decodedWireChunk->payload, - decodedWireChunk->size); - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = decodedWireChunk->size; + ret = -2; + } else { + // copy the whole payload to our fragment + memcpy(pcmChunk->fragment->payload, decodedWireChunk->payload, + decodedWireChunk->size); + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = decodedWireChunk->size; - ret = 0; - } + ret = 0; + } #else // we got valid memory for pcm_chunk_message_t // first we try to allocated 32 bit aligned memory for payload // check available memory first so we can decide if we need to fragment the // data - freeMem = heap_caps_get_free_size (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - largestFreeBlock - = heap_caps_get_largest_free_block (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + freeMem = heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); // if (freeMem >= decodedWireChunk->size) - if ((freeMem >= decodedWireChunk->size) - && (largestFreeBlock >= decodedWireChunk->size)) - { - // largestFreeBlock = heap_caps_get_largest_free_block - // (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); ESP_LOGW( - // TAG, "32b f %d b %d", freeMem, largestFreeBlock); - if (largestFreeBlock >= decodedWireChunk->size) - { - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - decodedWireChunk->size, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE ( + if ((freeMem >= decodedWireChunk->size) && + (largestFreeBlock >= decodedWireChunk->size)) { + // largestFreeBlock = heap_caps_get_largest_free_block + // (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); ESP_LOGW( + // TAG, "32b f %d b %d", freeMem, largestFreeBlock); + if (largestFreeBlock >= decodedWireChunk->size) { + pcmChunk->fragment->payload = (char *)heap_caps_malloc( + decodedWireChunk->size, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for pcm chunk fragment payload"); + + free_pcm_chunk(pcmChunk); + + ret = -2; + } else { + // copy the whole payload to our fragment + memcpy(pcmChunk->fragment->payload, decodedWireChunk->payload, + decodedWireChunk->size); + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = decodedWireChunk->size; + + ret = 0; + } + } else { + pcm_chunk_fragment_t *next = NULL; + size_t s; + + ret = 0; + + tmpSize = decodedWireChunk->size; + // heap_caps_aligned_alloc(sizeof(uint32_t), decodedWireChunk->size, + // MALLOC_CAP_32BIT); + pcmChunk->fragment->payload = (char *)heap_caps_malloc( + largestFreeBlock, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for pcm chunk " + "fragmented payload"); + + free_pcm_chunk(pcmChunk); + + ret = -2; + } else { + next = pcmChunk->fragment; + s = largestFreeBlock; + + ret = 0; + + // loop until we have all data stored to a fragment + do { + // copy the whole payload to our fragment + memcpy(next->payload, decodedWireChunk->payload, s); + next->size = s; + tmpSize -= s; + decodedWireChunk->payload += s; + + // ESP_LOGI (TAG,"%p %d", next->payload, + // next->size); + + if (tmpSize > 0) { + next->nextFragment = + (pcm_chunk_fragment_t *)calloc(1, sizeof(pcm_chunk_fragment_t)); + if (next->nextFragment == NULL) { + ESP_LOGE( TAG, - "Failed to allocate memory for pcm chunk fragment payload"); + "Failed to allocate memory for next pcm " + "chunk fragment %d %d", + heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_EXEC), + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | + MALLOC_CAP_EXEC)); - free_pcm_chunk (pcmChunk); + free_pcm_chunk(pcmChunk); - ret = -2; + ret = -3; + + break; + } else { + largestFreeBlock = heap_caps_get_largest_free_block( + MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (largestFreeBlock <= tmpSize) { + s = largestFreeBlock; + } else { + s = tmpSize; + } + + next->nextFragment->payload = (char *)heap_caps_malloc( + s, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); + if (next->nextFragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for pcm " + "chunk next fragmented payload"); + + free_pcm_chunk(pcmChunk); + + ret = -3; + + break; + } else { + next = next->nextFragment; + } } - else - { - // copy the whole payload to our fragment - memcpy (pcmChunk->fragment->payload, decodedWireChunk->payload, - decodedWireChunk->size); - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = decodedWireChunk->size; + } + } while (tmpSize); + } + } - ret = 0; - } + // ret = 0; + } else { + // we got valid memory for pcm_chunk_message_t + // no 32 bit aligned memory available, try to allocate 8 bit aligned + // memory for payload check available memory first so we can decide if we + // need to fragment the data + freeMem = heap_caps_get_free_size(MALLOC_CAP_8BIT); + largestFreeBlock = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + // if (freeMem >= decodedWireChunk->size) + if ((freeMem >= decodedWireChunk->size) && + (largestFreeBlock >= decodedWireChunk->size)) { + // largestFreeBlock + // = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); + // ESP_LOGW( + // TAG, + // "8b f %d b %d", freeMem, + // largestFreeBlock); + if (largestFreeBlock >= decodedWireChunk->size) { + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(decodedWireChunk->size, MALLOC_CAP_8BIT); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for pcm chunk " + "fragment payload"); + + free_pcm_chunk(pcmChunk); + + ret = -2; + } else { + // copy the whole payload to our fragment + memcpy(pcmChunk->fragment->payload, decodedWireChunk->payload, + decodedWireChunk->size); + pcmChunk->fragment->nextFragment = NULL; + pcmChunk->fragment->size = decodedWireChunk->size; + + ret = 0; } - else - { - pcm_chunk_fragment_t *next = NULL; - size_t s; + } else { + pcm_chunk_fragment_t *next = NULL; + size_t s; + + ret = 0; + + tmpSize = decodedWireChunk->size; + // heap_caps_aligned_alloc(sizeof(uint32_t), + // decodedWireChunk->size, MALLOC_CAP_32BIT); + pcmChunk->fragment->payload = + (char *)heap_caps_malloc(largestFreeBlock, MALLOC_CAP_8BIT); + if (pcmChunk->fragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for pcm chunk " + "fragmented payload"); + + free_pcm_chunk(pcmChunk); + + ret = -2; + } else { + next = pcmChunk->fragment; + s = largestFreeBlock; ret = 0; - tmpSize = decodedWireChunk->size; - // heap_caps_aligned_alloc(sizeof(uint32_t), decodedWireChunk->size, - // MALLOC_CAP_32BIT); - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - largestFreeBlock, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk " - "fragmented payload"); + // loop until we have all data stored to a fragment + do { + // copy the whole payload to our fragment + memcpy(next->payload, decodedWireChunk->payload, s); + next->size = s; + tmpSize -= s; + decodedWireChunk->payload += s; - free_pcm_chunk (pcmChunk); + if (tmpSize > 0) { + next->nextFragment = (pcm_chunk_fragment_t *)calloc( + 1, sizeof(pcm_chunk_fragment_t)); + if (next->nextFragment == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for next pcm " + "chunk fragment %d %d", + heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); - ret = -2; - } - else - { - next = pcmChunk->fragment; - s = largestFreeBlock; + free_pcm_chunk(pcmChunk); - ret = 0; + ret = -3; - // loop until we have all data stored to a fragment - do - { - // copy the whole payload to our fragment - memcpy (next->payload, decodedWireChunk->payload, s); - next->size = s; - tmpSize -= s; - decodedWireChunk->payload += s; - - // ESP_LOGI (TAG,"%p %d", next->payload, - // next->size); - - if (tmpSize > 0) - { - next->nextFragment = (pcm_chunk_fragment_t *)calloc ( - 1, sizeof (pcm_chunk_fragment_t)); - if (next->nextFragment == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate memory for next pcm " - "chunk fragment %d %d", - heap_caps_get_free_size ( - MALLOC_CAP_32BIT | MALLOC_CAP_EXEC), - heap_caps_get_largest_free_block ( - MALLOC_CAP_32BIT | MALLOC_CAP_EXEC)); - - free_pcm_chunk (pcmChunk); - - ret = -3; - - break; - } - else - { - largestFreeBlock = heap_caps_get_largest_free_block ( - MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (largestFreeBlock <= tmpSize) - { - s = largestFreeBlock; - } - else - { - s = tmpSize; - } - - next->nextFragment->payload - = (char *)heap_caps_malloc ( - s, MALLOC_CAP_32BIT | MALLOC_CAP_EXEC); - if (next->nextFragment->payload == NULL) - { - ESP_LOGE (TAG, - "Failed to allocate memory for pcm " - "chunk next fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -3; - - break; - } - else - { - next = next->nextFragment; - } - } - } - } - while (tmpSize); - } - } - - // ret = 0; - } - else - { - // we got valid memory for pcm_chunk_message_t - // no 32 bit aligned memory available, try to allocate 8 bit aligned - // memory for payload check available memory first so we can decide if we - // need to fragment the data - freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT); - largestFreeBlock = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); - // if (freeMem >= decodedWireChunk->size) - if ((freeMem >= decodedWireChunk->size) - && (largestFreeBlock >= decodedWireChunk->size)) - { - // largestFreeBlock - // = heap_caps_get_largest_free_block (MALLOC_CAP_8BIT); - // ESP_LOGW( - // TAG, - // "8b f %d b %d", freeMem, - // largestFreeBlock); - if (largestFreeBlock >= decodedWireChunk->size) - { - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - decodedWireChunk->size, MALLOC_CAP_8BIT); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk " - "fragment payload"); - - free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - // copy the whole payload to our fragment - memcpy (pcmChunk->fragment->payload, - decodedWireChunk->payload, decodedWireChunk->size); - pcmChunk->fragment->nextFragment = NULL; - pcmChunk->fragment->size = decodedWireChunk->size; - - ret = 0; - } - } - else - { - pcm_chunk_fragment_t *next = NULL; - size_t s; - - ret = 0; - - tmpSize = decodedWireChunk->size; - // heap_caps_aligned_alloc(sizeof(uint32_t), - // decodedWireChunk->size, MALLOC_CAP_32BIT); - pcmChunk->fragment->payload = (char *)heap_caps_malloc ( - largestFreeBlock, MALLOC_CAP_8BIT); - if (pcmChunk->fragment->payload == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk " - "fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -2; - } - else - { - next = pcmChunk->fragment; + break; + } else { + largestFreeBlock = + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + if (largestFreeBlock <= tmpSize) { s = largestFreeBlock; - - ret = 0; - - // loop until we have all data stored to a fragment - do - { - // copy the whole payload to our fragment - memcpy (next->payload, decodedWireChunk->payload, s); - next->size = s; - tmpSize -= s; - decodedWireChunk->payload += s; - - if (tmpSize > 0) - { - next->nextFragment = (pcm_chunk_fragment_t *)calloc ( - 1, sizeof (pcm_chunk_fragment_t)); - if (next->nextFragment == NULL) - { - ESP_LOGE ( - TAG, - "Failed to allocate memory for next pcm " - "chunk fragment %d %d", - heap_caps_get_free_size (MALLOC_CAP_8BIT), - heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT)); - - free_pcm_chunk (pcmChunk); - - ret = -3; - - break; - } - else - { - largestFreeBlock - = heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT); - if (largestFreeBlock <= tmpSize) - { - s = largestFreeBlock; - } - else - { - s = tmpSize; - } - - next->nextFragment->payload - = (char *)heap_caps_malloc (s, - MALLOC_CAP_8BIT); - if (next->nextFragment->payload == NULL) - { - ESP_LOGE ( - TAG, "Failed to allocate memory for pcm " - "chunk next fragmented payload"); - - free_pcm_chunk (pcmChunk); - - ret = -3; - - break; - } - else - { - next = next->nextFragment; - } - } - } - } - while (tmpSize); + } else { + s = tmpSize; } - } - // ret = 0; + next->nextFragment->payload = + (char *)heap_caps_malloc(s, MALLOC_CAP_8BIT); + if (next->nextFragment->payload == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for pcm " + "chunk next fragmented payload"); + + free_pcm_chunk(pcmChunk); + + ret = -3; + + break; + } else { + next = next->nextFragment; + } + } + } + } while (tmpSize); } + } + + // ret = 0; } + } #endif - if (ret == 0) - { - if (xQueueSendToBack (pcmChkQHdl, &pcmChunk, pdMS_TO_TICKS (1000)) - != pdTRUE) - { - ESP_LOGW (TAG, "send: pcmChunkQueue full, messages waiting %d", - uxQueueMessagesWaiting (pcmChkQHdl)); + if (ret == 0) { + if (xQueueSendToBack(pcmChkQHdl, &pcmChunk, pdMS_TO_TICKS(1000)) != + pdTRUE) { + ESP_LOGW(TAG, "send: pcmChunkQueue full, messages waiting %d", + uxQueueMessagesWaiting(pcmChkQHdl)); - free_pcm_chunk (pcmChunk); - } - } - else - { - ESP_LOGE (TAG, - "couldn't get memory to insert fragmented chunk of size %d, " - "freemem: %d blocksize %d", - decodedWireChunk->size, freeMem, largestFreeBlock); + free_pcm_chunk(pcmChunk); } + } else { + ESP_LOGE(TAG, + "couldn't get memory to insert fragmented chunk of size %d, " + "freemem: %d blocksize %d", + decodedWireChunk->size, freeMem, largestFreeBlock); + } return ret; } @@ -2420,9 +2057,7 @@ insert_pcm_chunk_backup (wire_chunk_message_t *decodedWireChunk) /** * */ -static void -player_task (void *pvParameters) -{ +static void player_task(void *pvParameters) { pcm_chunk_message_t *chnk = NULL; int64_t serverNow = 0; int64_t age; @@ -2445,419 +2080,354 @@ player_task (void *pvParameters) int64_t clientDacLatency_us = 0; uint8_t sendResyncMSg = 0; - ESP_LOGI (TAG, "started sync task"); + ESP_LOGI(TAG, "started sync task"); // stats_init(); // create message queue to inform task of changed settings - snapcastSettingQueueHandle = xQueueCreate (1, sizeof (uint8_t)); + snapcastSettingQueueHandle = xQueueCreate(1, sizeof(uint8_t)); initialSync = 0; shortMedianFilter.numNodes = SHORT_BUFFER_LEN; shortMedianFilter.medianBuffer = shortMedianBuffer; - if (MEDIANFILTER_Init (&shortMedianFilter)) - { - ESP_LOGE (TAG, - "snapcast_sync_task: couldn't init shortMedianFilter. STOP"); + if (MEDIANFILTER_Init(&shortMedianFilter)) { + ESP_LOGE(TAG, "snapcast_sync_task: couldn't init shortMedianFilter. STOP"); - return; + return; + } + + while (1) { + // ESP_LOGW( + // TAG, + // "32b f %d b %d", heap_caps_get_free_size + //(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block (MALLOC_CAP_8BIT)); + // ESP_LOGW (TAG, "stack free: %d", + // uxTaskGetStackHighWaterMark(NULL)); + + // check if we got changed setting available, if so we need to + // reinitialize + ret = xQueueReceive(snapcastSettingQueueHandle, &scSetChgd, 0); + if (ret == pdTRUE) { + player_get_snapcast_settings(&scSet); + + buf_us = (int64_t)(scSet.buf_ms) * 1000LL; + + chkDur_us = (int64_t)(scSet.chkDur_ms) * 1000LL; + chkInBytes = + (scSet.chkDur_ms * scSet.sr * scSet.ch * (scSet.bits / 8)) / 1000; + clientDacLatency_us = (int64_t)scSet.cDacLat_ms * 1000LL; + + if ((scSet.sr > 0) && (scSet.bits) > 0 && (scSet.ch > 0)) { + i2s_custom_stop(I2S_NUM_0); + + ret = player_setup_i2s(I2S_NUM_0, ¤tSnapcastSetting); + if (ret < 0) { + ESP_LOGE(TAG, "player_setup_i2s failed: %d", ret); + + return; + } + + // force adjust_apll() to set playback speed + currentDir = 1; + adjust_apll(0); + + i2s_custom_set_clk(I2S_NUM_0, scSet.sr, scSet.bits, scSet.ch); + initialSync = 0; + } + + if ((scSet.buf_ms > 0) && (scSet.chkDur_ms > 0)) { + // create snapcast receive buffer + if (pcmChkQHdl != NULL) { + destroy_pcm_queue(&pcmChkQHdl); + } + + // round up + int entries = ((float)scSet.buf_ms / (float)scSet.chkDur_ms) + 0.5; + pcmChkQHdl = xQueueCreate(entries, sizeof(pcm_chunk_message_t *)); + + ESP_LOGI(TAG, "created new queue with %d", entries); + } + + ESP_LOGI(TAG, + "snapserver config changed, buffer %dms, chunk %dms, " + "sample rate %d, ch %d, bits %d mute %d latency %d", + scSet.buf_ms, scSet.chkDur_ms, scSet.sr, scSet.ch, scSet.bits, + scSet.muted, scSet.cDacLat_ms); + + gotSnapserverConfig = true; + } else if (gotSnapserverConfig == false) { + vTaskDelay(pdMS_TO_TICKS(10)); + + continue; } - while (1) - { - // ESP_LOGW( - // TAG, - // "32b f %d b %d", heap_caps_get_free_size - //(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block (MALLOC_CAP_8BIT)); - // ESP_LOGW (TAG, "stack free: %d", - // uxTaskGetStackHighWaterMark(NULL)); + if (chnk == NULL) { + if (pcmChkQHdl != NULL) { + ret = xQueueReceive(pcmChkQHdl, &chnk, pdMS_TO_TICKS(2000)); + } else { + // ESP_LOGE (TAG, + // "Couldn't get PCM chunk, pcm queue not + // created"); - // check if we got changed setting available, if so we need to - // reinitialize - ret = xQueueReceive (snapcastSettingQueueHandle, &scSetChgd, 0); - if (ret == pdTRUE) - { - player_get_snapcast_settings (&scSet); + vTaskDelay(pdMS_TO_TICKS(100)); - buf_us = (int64_t) (scSet.buf_ms) * 1000LL; + continue; + } - chkDur_us = (int64_t) (scSet.chkDur_ms) * 1000LL; - chkInBytes - = (scSet.chkDur_ms * scSet.sr * scSet.ch * (scSet.bits / 8)) - / 1000; - clientDacLatency_us = (int64_t)scSet.cDacLat_ms * 1000LL; + if (ret != pdFAIL) { + // ESP_LOGW(TAG, "got pcm chunk"); + } + } else { + // ESP_LOGW(TAG, "already retrieved chunk needs + // service"); + ret = pdPASS; + } - if ((scSet.sr > 0) && (scSet.bits) > 0 && (scSet.ch > 0)) - { - i2s_custom_stop (I2S_NUM_0); + if (ret != pdFAIL) { + if (server_now(&serverNow) >= 0) { + age = serverNow - + ((int64_t)chnk->timestamp.sec * 1000000LL + + (int64_t)chnk->timestamp.usec) - + (int64_t)buf_us + (int64_t)clientDacLatency_us; + } else { + // ESP_LOGW(TAG, "couldn't get server now"); - ret = player_setup_i2s (I2S_NUM_0, ¤tSnapcastSetting); - if (ret < 0) - { - ESP_LOGE (TAG, "player_setup_i2s failed: %d", ret); - - return; - } - - // force adjust_apll() to set playback speed - currentDir = 1; - adjust_apll (0); - - i2s_custom_set_clk (I2S_NUM_0, scSet.sr, scSet.bits, scSet.ch); - initialSync = 0; - } - - if ((scSet.buf_ms > 0) && (scSet.chkDur_ms > 0)) - { - // create snapcast receive buffer - if (pcmChkQHdl != NULL) - { - destroy_pcm_queue (&pcmChkQHdl); - } - - // round up - int entries - = ((float)scSet.buf_ms / (float)scSet.chkDur_ms) + 0.5; - pcmChkQHdl - = xQueueCreate (entries, sizeof (pcm_chunk_message_t *)); - - ESP_LOGI (TAG, "created new queue with %d", entries); - } - - ESP_LOGI (TAG, - "snapserver config changed, buffer %dms, chunk %dms, " - "sample rate %d, ch %d, bits %d mute %d latency %d", - scSet.buf_ms, scSet.chkDur_ms, scSet.sr, scSet.ch, - scSet.bits, scSet.muted, scSet.cDacLat_ms); - - gotSnapserverConfig = true; + if (chnk != NULL) { + free_pcm_chunk(chnk); + chnk = NULL; } - else if (gotSnapserverConfig == false) - { - vTaskDelay (pdMS_TO_TICKS (10)); + + vTaskDelay(pdMS_TO_TICKS(1)); + + continue; + } + + // wait for early time syncs to be ready + int tmp = latency_buffer_full(); + if (tmp <= 0) { + if (tmp < 0) { + vTaskDelay(1); continue; } - if (chnk == NULL) - { - if (pcmChkQHdl != NULL) - { - ret = xQueueReceive (pcmChkQHdl, &chnk, pdMS_TO_TICKS (2000)); - } - else - { - // ESP_LOGE (TAG, - // "Couldn't get PCM chunk, pcm queue not - // created"); - - vTaskDelay (pdMS_TO_TICKS (100)); - - continue; - } - - if (ret != pdFAIL) - { - // ESP_LOGW(TAG, "got pcm chunk"); - } - } - else - { - // ESP_LOGW(TAG, "already retrieved chunk needs - // service"); - ret = pdPASS; + if (age >= 0) { + if (chnk != NULL) { + free_pcm_chunk(chnk); + chnk = NULL; + } } - if (ret != pdFAIL) - { - if (server_now (&serverNow) >= 0) - { - age = serverNow - - ((int64_t)chnk->timestamp.sec * 1000000LL - + (int64_t)chnk->timestamp.usec) - - (int64_t)buf_us + (int64_t)clientDacLatency_us; + // ESP_LOGW(TAG, "diff buffer not full"); + + vTaskDelay(pdMS_TO_TICKS(10)); + + continue; + } + + if (age < 0) { // get initial sync using hardware timer + if (initialSync == 0) { + tg0_timer1_start(-age - + alarmValSub); // alarm a little earlier to account + // for context switch duration from + // freeRTOS, timer with 1µs ticks + + // tg0_timer1_start((-age * 10) - alarmValSub)); + // // alarm a + // little earlier to account for context switch duration from + // freeRTOS, timer with 100ns ticks + + i2s_custom_stop(I2S_NUM_0); + + if (MEDIANFILTER_Init(&shortMedianFilter)) { + ESP_LOGE(TAG, + "snapcast_sync_task: couldn't init " + "shortMedianFilter. STOP"); + + return; + } + + adjust_apll(0); // reset to normal playback speed + + fragment = chnk->fragment; + p_payload = fragment->payload; + size = fragment->size; + + i2s_custom_init_dma_tx_queues(I2S_NUM_0, (uint8_t *)p_payload, size, + &written); + size -= written; + p_payload += written; + + // ESP_LOGE(TAG, "wrote %d", written); + + if (size == 0) { + if (fragment->nextFragment != NULL) { + fragment = fragment->nextFragment; + p_payload = fragment->payload; + size = fragment->size; + } else { + free_pcm_chunk(chnk); + chnk = NULL; } - else - { - // ESP_LOGW(TAG, "couldn't get server now"); + } - if (chnk != NULL) - { - free_pcm_chunk (chnk); - chnk = NULL; - } + // TCP_STATS_DISPLAY(); + // IP_STATS_DISPLAY(); + // MEM_STATS_DISPLAY(); + // LINK_STATS_DISPLAY(); - vTaskDelay (pdMS_TO_TICKS (1)); + // Wait to be notified of a timer interrupt. + xTaskNotifyWait(pdFALSE, // Don't clear bits on entry. + pdFALSE, // Don't clear bits on exit. + ¬ifiedValue, // Stores the notified value. + portMAX_DELAY); + // or use simple task delay for this + // vTaskDelay( pdMS_TO_TICKS(-age / 1000) ); - continue; - } + i2s_custom_start(I2S_NUM_0); - // wait for early time syncs to be ready - int tmp = latency_buffer_full (); - if (tmp <= 0) - { - if (tmp < 0) - { - vTaskDelay (1); + // get timer value so we can get the real age + timer_get_counter_value(TIMER_GROUP_0, TIMER_1, &timer_val); + timer_pause(TIMER_GROUP_0, TIMER_1); - continue; - } + // get actual age after alarm + // age = ((int64_t)timer_val - (-age) * 10) / 10; + // // timer with 100ns ticks + age = (int64_t)timer_val - (-age); // timer with 1µs ticks - if (age >= 0) - { - if (chnk != NULL) - { - free_pcm_chunk (chnk); - chnk = NULL; - } - } + // check if we need to write remaining data + if (size != 0) { + do { + written = 0; + if (i2s_custom_write(I2S_NUM_0, p_payload, (size_t)size, &written, + portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "i2s_playback_task: I2S write error"); + } + if (written < size) { + ESP_LOGE(TAG, + "i2s_playback_task: I2S didn't " + "write all data"); + } + size -= written; + p_payload += written; - // ESP_LOGW(TAG, "diff buffer not full"); - - vTaskDelay (pdMS_TO_TICKS (10)); - - continue; - } - - if (age < 0) - { // get initial sync using hardware timer - if (initialSync == 0) - { - tg0_timer1_start ( - -age - alarmValSub); // alarm a little earlier to account - // for context switch duration from - // freeRTOS, timer with 1µs ticks - - // tg0_timer1_start((-age * 10) - alarmValSub)); - // // alarm a - // little earlier to account for context switch duration from - // freeRTOS, timer with 100ns ticks - - i2s_custom_stop (I2S_NUM_0); - - if (MEDIANFILTER_Init (&shortMedianFilter)) - { - ESP_LOGE (TAG, "snapcast_sync_task: couldn't init " - "shortMedianFilter. STOP"); - - return; - } - - adjust_apll (0); // reset to normal playback speed - - fragment = chnk->fragment; + if (size == 0) { + if (fragment->nextFragment != NULL) { + fragment = fragment->nextFragment; p_payload = fragment->payload; size = fragment->size; - - i2s_custom_init_dma_tx_queues ( - I2S_NUM_0, (uint8_t *)p_payload, size, &written); - size -= written; - p_payload += written; - - // ESP_LOGE(TAG, "wrote %d", written); - - if (size == 0) - { - if (fragment->nextFragment != NULL) - { - fragment = fragment->nextFragment; - p_payload = fragment->payload; - size = fragment->size; - } - else - { - free_pcm_chunk (chnk); - chnk = NULL; - } - } - - // TCP_STATS_DISPLAY(); - // IP_STATS_DISPLAY(); - // MEM_STATS_DISPLAY(); - // LINK_STATS_DISPLAY(); - - // Wait to be notified of a timer interrupt. - xTaskNotifyWait ( - pdFALSE, // Don't clear bits on entry. - pdFALSE, // Don't clear bits on exit. - ¬ifiedValue, // Stores the notified value. - portMAX_DELAY); - // or use simple task delay for this - // vTaskDelay( pdMS_TO_TICKS(-age / 1000) ); - - i2s_custom_start (I2S_NUM_0); - - // get timer value so we can get the real age - timer_get_counter_value (TIMER_GROUP_0, TIMER_1, &timer_val); - timer_pause (TIMER_GROUP_0, TIMER_1); - - // get actual age after alarm - // age = ((int64_t)timer_val - (-age) * 10) / 10; - // // timer with 100ns ticks - age = (int64_t)timer_val - (-age); // timer with 1µs ticks - - // check if we need to write remaining data - if (size != 0) - { - do - { - written = 0; - if (i2s_custom_write (I2S_NUM_0, p_payload, - (size_t)size, &written, - portMAX_DELAY) - != ESP_OK) - { - ESP_LOGE (TAG, - "i2s_playback_task: I2S write error"); - } - if (written < size) - { - ESP_LOGE (TAG, "i2s_playback_task: I2S didn't " - "write all data"); - } - size -= written; - p_payload += written; - - if (size == 0) - { - if (fragment->nextFragment != NULL) - { - fragment = fragment->nextFragment; - p_payload = fragment->payload; - size = fragment->size; - } - else - { - free_pcm_chunk (chnk); - chnk = NULL; - - break; - } - } - } - while (1); - } - - initialSync = 1; - sendResyncMSg = 1; - - ESP_LOGI (TAG, "initial sync %lldus", age); - - continue; - } - } - else if ((age > 0) && (initialSync == 0)) - { - if (chnk != NULL) - { - free_pcm_chunk (chnk); + } else { + free_pcm_chunk(chnk); chnk = NULL; + + break; } + } + } while (1); + } - int64_t t; - get_diff_to_server (&t); + initialSync = 1; + sendResyncMSg = 1; - wifi_ap_record_t ap; - esp_wifi_sta_get_ap_info (&ap); + ESP_LOGI(TAG, "initial sync %lldus", age); - if (sendResyncMSg == 1) - { - sendResyncMSg = 0; + continue; + } + } else if ((age > 0) && (initialSync == 0)) { + if (chnk != NULL) { + free_pcm_chunk(chnk); + chnk = NULL; + } - ESP_LOGW ( - TAG, - "RESYNCING HARD 1: age %lldus, latency %lldus, free %d, " - "largest block %d, %d, rssi: %d", - age, t, heap_caps_get_free_size (MALLOC_CAP_32BIT), - heap_caps_get_largest_free_block (MALLOC_CAP_32BIT), - uxQueueMessagesWaiting (pcmChkQHdl), ap.rssi); - } + int64_t t; + get_diff_to_server(&t); - dir = 0; + wifi_ap_record_t ap; + esp_wifi_sta_get_ap_info(&ap); - initialSync = 0; + // if (sendResyncMSg == 1) + { + sendResyncMSg = 0; - continue; + ESP_LOGW(TAG, + "RESYNCING HARD 1: age %lldus, latency %lldus, free %d, " + "largest block %d, %d, rssi: %d", + age, t, heap_caps_get_free_size(MALLOC_CAP_32BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT), + uxQueueMessagesWaiting(pcmChkQHdl), ap.rssi); + } + + dir = 0; + + initialSync = 0; + + continue; + } + + const uint8_t enableControlLoop = 1; + const int64_t age_expect = + -chkDur_us * + CHNK_CTRL_CNT; // this value is highly coupled with I2S DMA buffer + // size. DMA buffer has a size of 1 chunk (e.g. 20ms) + // so next chunk we get from queue will be -20ms + const int64_t maxOffset = 25; //µs, softsync 1 + const int64_t hardResyncThreshold = 10000; //µs, hard sync + + if (initialSync == 1) { + avg = MEDIANFILTER_Insert(&shortMedianFilter, age + (-age_expect)); + if (MEDIANFILTER_isFull(&shortMedianFilter) == 0) { + avg = age + (-age_expect); + } else { + // resync hard if we are off too far + // if ((avg < -hardResyncThreshold) + // || (avg > hardResyncThreshold) || + // (initialSync == 0)) + if ((initialSync == 0) || (uxQueueMessagesWaiting(pcmChkQHdl) == + 0)) // only resync if we are getting late. + // hopefully being early will get ok + // through apll speed control + // if ((avg > hardResyncThreshold) || (initialSync == 0)) + // // only resync if we are getting late. hopefully being + // early will get ok through apll speed control + { + if (chnk != NULL) { + free_pcm_chunk(chnk); + chnk = NULL; } - const uint8_t enableControlLoop = 1; - const int64_t age_expect - = -chkDur_us - * 1; // this value is highly coupled with I2S DMA buffer - // size. DMA buffer has a size of 1 chunk (e.g. 20ms) - // so next chunk we get from queue will be -20ms - const int64_t maxOffset = 25; //µs, softsync 1 - const int64_t hardResyncThreshold = 10000; //µs, hard sync + int64_t t; + get_diff_to_server(&t); - if (initialSync == 1) - { - avg = MEDIANFILTER_Insert (&shortMedianFilter, - age + (-age_expect)); - if (MEDIANFILTER_isFull (&shortMedianFilter) == 0) - { - avg = age + (-age_expect); - } - else - { - // resync hard if we are off too far - // if ((avg < -hardResyncThreshold) - // || (avg > hardResyncThreshold) || - // (initialSync == 0)) - if ((initialSync == 0) - || (uxQueueMessagesWaiting (pcmChkQHdl) - == 0)) // only resync if we are getting late. - // hopefully being early will get ok through - // apll speed control - // if ((avg > hardResyncThreshold) || (initialSync == 0)) - // // only resync if we are getting late. hopefully being - // early will get ok through apll speed control - { - if (chnk != NULL) - { - free_pcm_chunk (chnk); - chnk = NULL; - } + wifi_ap_record_t ap; + esp_wifi_sta_get_ap_info(&ap); - int64_t t; - get_diff_to_server (&t); + ESP_LOGW(TAG, + "RESYNCING HARD 2: age %lldus, latency %lldus, free " + "%d, largest block %d, %d, rssi: %d", + avg, t, heap_caps_get_free_size(MALLOC_CAP_32BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_32BIT), + uxQueueMessagesWaiting(pcmChkQHdl), ap.rssi); - wifi_ap_record_t ap; - esp_wifi_sta_get_ap_info (&ap); + initialSync = 0; - ESP_LOGW ( - TAG, - "RESYNCING HARD 2: age %lldus, latency %lldus, free " - "%d, largest block %d, %d, rssi: %d", - avg, t, heap_caps_get_free_size (MALLOC_CAP_32BIT), - heap_caps_get_largest_free_block (MALLOC_CAP_32BIT), - uxQueueMessagesWaiting (pcmChkQHdl), ap.rssi); + continue; + } + } - initialSync = 0; + if (enableControlLoop == 1) { + if (avg < -maxOffset) { // we are early + dir = -1; + } else if ((avg >= -maxOffset) && (avg <= maxOffset)) { + dir = 0; + } else if (avg > maxOffset) { // we are late + dir = 1; + } - continue; - } - } + adjust_apll(dir); + } - if (enableControlLoop == 1) - { - if (avg < -maxOffset) - { // we are early - dir = -1; - } - else if ((avg >= -maxOffset) && (avg <= maxOffset)) - { - dir = 0; - } - else if (avg > maxOffset) - { // we are late - dir = 1; - } - - adjust_apll (dir); - } - - // clang-format off + // clang-format off // int64_t t; // get_diff_to_server (&t); // @@ -2901,72 +2471,59 @@ player_task (void *pvParameters) // ESP_LOGI (TAG, "%d, %lldus, %lldus %lldus", dir, age, avg, t); - // ESP_LOGI (TAG, "%d %lldus, %d", dir, avg, uxQueueMessagesWaiting(pcmChkQHdl)); - // clang-format on - fragment = chnk->fragment; + // ESP_LOGI (TAG, "%d %lldus, %d", dir, avg, uxQueueMessagesWaiting(pcmChkQHdl)); + // clang-format on + + fragment = chnk->fragment; + p_payload = fragment->payload; + size = fragment->size; + + do { + written = 0; + if (i2s_custom_write(I2S_NUM_0, p_payload, (size_t)size, &written, + portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "i2s_playback_task: I2S write error %d", size); + } + if (written < size) { + ESP_LOGE(TAG, "i2s_playback_task: I2S didn't write all data"); + } + size -= written; + p_payload += written; + + if (size == 0) { + if (fragment->nextFragment != NULL) { + fragment = fragment->nextFragment; p_payload = fragment->payload; size = fragment->size; - do - { - written = 0; - if (i2s_custom_write (I2S_NUM_0, p_payload, (size_t)size, - &written, portMAX_DELAY) - != ESP_OK) - { - ESP_LOGE (TAG, "i2s_playback_task: I2S write error %d", - size); - } - if (written < size) - { - ESP_LOGE ( - TAG, "i2s_playback_task: I2S didn't write all data"); - } - size -= written; - p_payload += written; + // ESP_LOGI (TAG, + // "i2s_playback_task: + // fragmented"); + } else { + free_pcm_chunk(chnk); + chnk = NULL; - if (size == 0) - { - if (fragment->nextFragment != NULL) - { - fragment = fragment->nextFragment; - p_payload = fragment->payload; - size = fragment->size; - - // ESP_LOGI (TAG, - // "i2s_playback_task: - // fragmented"); - } - else - { - free_pcm_chunk (chnk); - chnk = NULL; - - break; - } - } - } - while (1); + break; } - } - else - { - int64_t t; + } + } while (1); + } + } else { + int64_t t; - get_diff_to_server (&t); + get_diff_to_server(&t); - if (pcmChkQHdl != NULL) - { - ESP_LOGE (TAG, - "Couldn't get PCM chunk, recv: messages waiting %d, " - "latency %lldus", - uxQueueMessagesWaiting (pcmChkQHdl), t); - } + if (pcmChkQHdl != NULL) { + ESP_LOGE(TAG, + "Couldn't get PCM chunk, recv: messages waiting %d, " + "latency %lldus", + uxQueueMessagesWaiting(pcmChkQHdl), t); + } - dir = 0; + dir = 0; - initialSync = 0; - } + initialSync = 0; } + } } diff --git a/components/ota_server/ota_server.c b/components/ota_server/ota_server.c index 27e6558..6bc1a17 100644 --- a/components/ota_server/ota_server.c +++ b/components/ota_server/ota_server.c @@ -30,17 +30,15 @@ EventGroupHandle_t ota_event_group; /*socket*/ static int connect_socket = 0; -void -ota_server_task (void *param) -{ +void ota_server_task(void *param) { // xEventGroupWaitBits(ota_event_group, OTA_CONNECTED_BIT, false, true, // portMAX_DELAY); - // TODO: find a god place to verify app is working properly after OTA - esp_ota_mark_app_valid_cancel_rollback (); + // TODO: find a good place to verify app is working properly after OTA + esp_ota_mark_app_valid_cancel_rollback(); - ota_server_start_my (); - vTaskDelete (NULL); + ota_server_start_my(); + vTaskDelete(NULL); } /* @@ -87,207 +85,177 @@ void initialise_wifi(void) } */ -static int -get_socket_error_code (int socket) -{ +static int get_socket_error_code(int socket) { int result; - u32_t optlen = sizeof (int); + u32_t optlen = sizeof(int); - int err = getsockopt (socket, SOL_SOCKET, SO_ERROR, &result, &optlen); + int err = getsockopt(socket, SOL_SOCKET, SO_ERROR, &result, &optlen); - if (err == -1) - { - ESP_LOGE (TAG, "getsockopt failed:%s", strerror (err)); - return -1; - } + if (err == -1) { + ESP_LOGE(TAG, "getsockopt failed:%s", strerror(err)); + return -1; + } return result; } -static int -show_socket_error_reason (const char *str, int socket) -{ - int err = get_socket_error_code (socket); +static int show_socket_error_reason(const char *str, int socket) { + int err = get_socket_error_code(socket); - if (err != 0) - { - ESP_LOGW (TAG, "%s socket error %d %s", str, err, strerror (err)); - } + if (err != 0) { + ESP_LOGW(TAG, "%s socket error %d %s", str, err, strerror(err)); + } return err; } -static esp_err_t -create_tcp_server () -{ - ESP_LOGI (TAG, - "idf.py build ; curl snapclient.local:%d --data-binary @- < " - "build/snapclient.bin", - OTA_LISTEN_PORT); +static esp_err_t create_tcp_server() { + ESP_LOGI(TAG, + "idf.py build ; curl snapclient.local:%d --data-binary @- < " + "build/snapclient.bin", + OTA_LISTEN_PORT); int server_socket = 0; struct sockaddr_in server_addr; - server_socket = socket (AF_INET, SOCK_STREAM, 0); + server_socket = socket(AF_INET, SOCK_STREAM, 0); - if (server_socket < 0) - { - show_socket_error_reason ("create_server", server_socket); - return ESP_FAIL; - } + if (server_socket < 0) { + show_socket_error_reason("create_server", server_socket); + return ESP_FAIL; + } server_addr.sin_family = AF_INET; - server_addr.sin_port = htons (OTA_LISTEN_PORT); - server_addr.sin_addr.s_addr = htonl (INADDR_ANY); - if (bind (server_socket, (struct sockaddr *)&server_addr, - sizeof (server_addr)) - < 0) - { - show_socket_error_reason ("bind_server", server_socket); - close (server_socket); - return ESP_FAIL; - } + server_addr.sin_port = htons(OTA_LISTEN_PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(server_socket, (struct sockaddr *)&server_addr, + sizeof(server_addr)) < 0) { + show_socket_error_reason("bind_server", server_socket); + close(server_socket); + return ESP_FAIL; + } - if (listen (server_socket, 5) < 0) - { - show_socket_error_reason ("listen_server", server_socket); - close (server_socket); - return ESP_FAIL; - } + if (listen(server_socket, 5) < 0) { + show_socket_error_reason("listen_server", server_socket); + close(server_socket); + return ESP_FAIL; + } struct sockaddr_in client_addr; - unsigned int socklen = sizeof (client_addr); - connect_socket - = accept (server_socket, (struct sockaddr *)&client_addr, &socklen); + unsigned int socklen = sizeof(client_addr); + connect_socket = + accept(server_socket, (struct sockaddr *)&client_addr, &socklen); - if (connect_socket < 0) - { - show_socket_error_reason ("accept_server", connect_socket); - close (server_socket); - return ESP_FAIL; - } + if (connect_socket < 0) { + show_socket_error_reason("accept_server", connect_socket); + close(server_socket); + return ESP_FAIL; + } /*connection established,now can send/recv*/ - ESP_LOGI (TAG, "tcp connection established!"); + ESP_LOGI(TAG, "tcp connection established!"); return ESP_OK; } -void -ota_server_start_my (void) -{ +void ota_server_start_my(void) { uint8_t percent_loaded; uint8_t old_percent_loaded; - ESP_ERROR_CHECK (create_tcp_server ()); + ESP_ERROR_CHECK(create_tcp_server()); - const esp_partition_t *update_partition - = esp_ota_get_next_update_partition (NULL); + const esp_partition_t *update_partition = + esp_ota_get_next_update_partition(NULL); - ESP_LOGI (TAG, "Writing to partition subtype %d at offset 0x%x", - update_partition->subtype, update_partition->address); + ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", + update_partition->subtype, update_partition->address); // https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/log.html // I don't want to see all the Log esp_image stuff while its flashing it - esp_log_level_set ( + esp_log_level_set( "esp_image", - ESP_LOG_ERROR); // set all components to ERROR level ESP_LOG_NONE + ESP_LOG_ERROR); // set all components to ERROR level ESP_LOG_NONE // We don't want any other thread running during this update. // SuspendAllThreads(); // KillAllThreads(); // dsp_i2s_task_deinit(); - vTaskDelete (t_http_get_task); - deinit_player (); // ensure this is called after http_task was killed + vTaskDelete(t_http_get_task); + deinit_player(); // ensure this is called after http_task was killed int recv_len; - char ota_buff[OTA_BUFF_SIZE] = { 0 }; + char ota_buff[OTA_BUFF_SIZE] = {0}; bool is_req_body_started = false; int content_length = -1; int content_received = 0; esp_ota_handle_t ota_handle; - do - { - // ESP_LOGW (TAG, "stack free: %d", - // uxTaskGetStackHighWaterMark(NULL)); + do { + // ESP_LOGW (TAG, "stack free: %d", + // uxTaskGetStackHighWaterMark(NULL)); - recv_len = recv (connect_socket, ota_buff, OTA_BUFF_SIZE, 0); + recv_len = recv(connect_socket, ota_buff, OTA_BUFF_SIZE, 0); - if (recv_len > 0) - { - if (!is_req_body_started) - { - const char *content_length_start = "Content-Length: "; - char *content_length_start_p - = strstr (ota_buff, content_length_start) - + strlen (content_length_start); - sscanf (content_length_start_p, "%d", &content_length); - ESP_LOGI (TAG, "Detected content length: %d", content_length); - ESP_ERROR_CHECK (esp_ota_begin (update_partition, - OTA_SIZE_UNKNOWN, &ota_handle)); - const char *header_end = "\r\n\r\n"; - char *body_start_p - = strstr (ota_buff, header_end) + strlen (header_end); - int body_part_len = recv_len - (body_start_p - ota_buff); - esp_ota_write (ota_handle, body_start_p, body_part_len); - content_received += body_part_len; - is_req_body_started = true; - } - else - { - esp_ota_write (ota_handle, ota_buff, recv_len); - content_received += recv_len; + if (recv_len > 0) { + if (!is_req_body_started) { + const char *content_length_start = "Content-Length: "; + char *content_length_start_p = strstr(ota_buff, content_length_start) + + strlen(content_length_start); + sscanf(content_length_start_p, "%d", &content_length); + ESP_LOGI(TAG, "Detected content length: %d", content_length); + ESP_ERROR_CHECK( + esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &ota_handle)); + const char *header_end = "\r\n\r\n"; + char *body_start_p = strstr(ota_buff, header_end) + strlen(header_end); + int body_part_len = recv_len - (body_start_p - ota_buff); + esp_ota_write(ota_handle, body_start_p, body_part_len); + content_received += body_part_len; + is_req_body_started = true; + } else { + esp_ota_write(ota_handle, ota_buff, recv_len); + content_received += recv_len; - percent_loaded - = (((float)content_received / (float)content_length) - * 100.00); - if ((percent_loaded % 10 == 0) - & (percent_loaded != old_percent_loaded)) - { - old_percent_loaded = percent_loaded; - ESP_LOGI (TAG, "Uploaded %03u%%", percent_loaded); - } - } - } - else if (recv_len < 0) - { - ESP_LOGI (TAG, "Error: recv data error! errno=%d", errno); + percent_loaded = + (((float)content_received / (float)content_length) * 100.00); + if ((percent_loaded % 10 == 0) & + (percent_loaded != old_percent_loaded)) { + old_percent_loaded = percent_loaded; + ESP_LOGI(TAG, "Uploaded %03u%%", percent_loaded); } + } + } else if (recv_len < 0) { + ESP_LOGI(TAG, "Error: recv data error! errno=%d", errno); } - while (recv_len > 0 && content_received < content_length); + } while (recv_len > 0 && content_received < content_length); - ESP_LOGI (TAG, "OTA Transferred Finished: %d bytes", content_received); + ESP_LOGI(TAG, "OTA Transferred Finished: %d bytes", content_received); char res_buff[128]; int send_len; - send_len = sprintf (res_buff, "200 OK\n\n"); - send (connect_socket, res_buff, send_len, 0); - vTaskDelay (2000 / portTICK_PERIOD_MS); - close (connect_socket); + send_len = sprintf(res_buff, "200 OK\n\n"); + send(connect_socket, res_buff, send_len, 0); + vTaskDelay(2000 / portTICK_PERIOD_MS); + close(connect_socket); - ESP_ERROR_CHECK (esp_ota_end (ota_handle)); + ESP_ERROR_CHECK(esp_ota_end(ota_handle)); - esp_err_t err = esp_ota_set_boot_partition (update_partition); + esp_err_t err = esp_ota_set_boot_partition(update_partition); - if (err == ESP_OK) - { - const esp_partition_t *boot_partition = esp_ota_get_boot_partition (); + if (err == ESP_OK) { + const esp_partition_t *boot_partition = esp_ota_get_boot_partition(); - ESP_LOGI (TAG, - "***********************************************************"); - ESP_LOGI (TAG, "OTA Successful"); - ESP_LOGI (TAG, "Next Boot Partition Subtype %d At Offset 0x%x", - boot_partition->subtype, boot_partition->address); - ESP_LOGI (TAG, - "***********************************************************"); - } - else - { - ESP_LOGI (TAG, "!!! OTA Failed !!!"); - } + ESP_LOGI(TAG, + "***********************************************************"); + ESP_LOGI(TAG, "OTA Successful"); + ESP_LOGI(TAG, "Next Boot Partition Subtype %d At Offset 0x%x", + boot_partition->subtype, boot_partition->address); + ESP_LOGI(TAG, + "***********************************************************"); + } else { + ESP_LOGI(TAG, "!!! OTA Failed !!!"); + } // for (int x = 2; x >= 1; x--) //{ - ESP_LOGI (TAG, "Prepare to restart system.."); - vTaskDelay (1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Prepare to restart system.."); + vTaskDelay(1000 / portTICK_PERIOD_MS); //} - esp_restart (); + esp_restart(); } diff --git a/main/main.c b/main/main.c index b9f0aec..f52a8de 100644 --- a/main/main.c +++ b/main/main.c @@ -51,18 +51,18 @@ #include "player.h" #include "snapcast.h" -static FLAC__StreamDecoderReadStatus -read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], - size_t *bytes, void *client_data); -static FLAC__StreamDecoderWriteStatus -write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, - const FLAC__int32 *const buffer[], void *client_data); -static void metadata_callback (const FLAC__StreamDecoder *decoder, - const FLAC__StreamMetadata *metadata, - void *client_data); -static void error_callback (const FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderErrorStatus status, - void *client_data); +static FLAC__StreamDecoderReadStatus read_callback( + const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, + void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback( + const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, + const FLAC__int32 *const buffer[], void *client_data); +static void metadata_callback(const FLAC__StreamDecoder *decoder, + const FLAC__StreamMetadata *metadata, + void *client_data); +static void error_callback(const FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderErrorStatus status, + void *client_data); //#include "ma120.h" @@ -75,13 +75,13 @@ SemaphoreHandle_t decoderWriteSemaphore = NULL; const char *VERSION_STRING = "0.0.2"; #define HTTP_TASK_PRIORITY 6 -#define HTTP_TASK_CORE_ID 1 // tskNO_AFFINITY +#define HTTP_TASK_CORE_ID 1 // tskNO_AFFINITY #define OTA_TASK_PRIORITY 6 -#define OTA_TASK_CORE_ID 1 // tskNO_AFFINITY +#define OTA_TASK_CORE_ID 1 // tskNO_AFFINITY #define FLAC_TASK_PRIORITY 6 -#define FLAC_TASK_CORE_ID 1 // tskNO_AFFINITY +#define FLAC_TASK_CORE_ID 1 // tskNO_AFFINITY xTaskHandle t_ota_task = NULL; xTaskHandle t_http_get_task = NULL; @@ -108,11 +108,10 @@ extern char mac_address[18]; SemaphoreHandle_t timeSyncSemaphoreHandle = NULL; #if CONFIG_USE_DSP_PROCESSOR -uint8_t dspFlow = dspfStereo; // dspfBiamp; // dspfStereo; // dspfBassBoost; +uint8_t dspFlow = dspfStereo; // dspfBiamp; // dspfStereo; // dspfBassBoost; #endif -typedef struct flacData_s -{ +typedef struct flacData_s { char *inData; pcm_chunk_message_t *outData; uint32_t bytes; @@ -121,73 +120,63 @@ typedef struct flacData_s /** * */ -void -time_sync_msg_cb (void *args) -{ +void time_sync_msg_cb(void *args) { BaseType_t xHigherPriorityTaskWoken; // causes kernel panic, which shouldn't happen though? // Isn't it called from timer task instead of ISR? // xSemaphoreGive(timeSyncSemaphoreHandle); - xSemaphoreGiveFromISR (timeSyncSemaphoreHandle, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) - { - portYIELD_FROM_ISR (); - } + xSemaphoreGiveFromISR(timeSyncSemaphoreHandle, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } } -static FLAC__StreamDecoderReadStatus -read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], - size_t *bytes, void *client_data) -{ +static FLAC__StreamDecoderReadStatus read_callback( + const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, + void *client_data) { snapcastSetting_t *scSet = (snapcastSetting_t *)client_data; flacData_t *flacData; (void)scSet; - xQueueReceive (decoderReadQHdl, &flacData, portMAX_DELAY); + xQueueReceive(decoderReadQHdl, &flacData, portMAX_DELAY); // ESP_LOGI(TAG, "in flac read cb %d %p", flacData->bytes, // flacData->inData); - if (flacData->bytes <= 0) - { - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - } + if (flacData->bytes <= 0) { + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } - if (flacData->inData == NULL) - { - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } + if (flacData->inData == NULL) { + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } - if (flacData->bytes <= *bytes) - { - memcpy (buffer, flacData->inData, flacData->bytes); - *bytes = flacData->bytes; - // ESP_LOGW(TAG, "read all flac inData %d", *bytes); - } - else - { - memcpy (buffer, flacData->inData, *bytes); - ESP_LOGW (TAG, "dind't read all flac inData %d", *bytes); - flacData->inData += *bytes; - flacData->bytes -= *bytes; - } + if (flacData->bytes <= *bytes) { + memcpy(buffer, flacData->inData, flacData->bytes); + *bytes = flacData->bytes; + // ESP_LOGW(TAG, "read all flac inData %d", *bytes); + } else { + memcpy(buffer, flacData->inData, *bytes); + ESP_LOGW(TAG, "dind't read all flac inData %d", *bytes); + flacData->inData += *bytes; + flacData->bytes -= *bytes; + } // xQueueSend (flacReadQHdl, &flacData, portMAX_DELAY); - xSemaphoreGive (decoderReadSemaphore); + xSemaphoreGive(decoderReadSemaphore); return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } static flacData_t flacOutData; -static FLAC__StreamDecoderWriteStatus -write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, - const FLAC__int32 *const buffer[], void *client_data) -{ +static FLAC__StreamDecoderWriteStatus write_callback( + const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, + const FLAC__int32 *const buffer[], void *client_data) { size_t i; flacData_t *flacData = &flacOutData; snapcastSetting_t *scSet = (snapcastSetting_t *)client_data; @@ -197,102 +186,91 @@ write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, (void)decoder; - xSemaphoreTake (decoderWriteSemaphore, portMAX_DELAY); + xSemaphoreTake(decoderWriteSemaphore, portMAX_DELAY); // xQueueReceive (flacReadQHdl, &flacData, portMAX_DELAY); // ESP_LOGI(TAG, "in flac write cb %d %p", frame->header.blocksize, // flacData); - if (frame->header.channels != scSet->ch) - { - ESP_LOGE (TAG, - "ERROR: frame header reports different channel count %d than " - "previous metadata block %d", - frame->header.channels, scSet->ch); - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - if (frame->header.bits_per_sample != scSet->bits) - { - ESP_LOGE (TAG, - "ERROR: frame header reports different bps %d than previous " - "metadata block %d", - frame->header.bits_per_sample, scSet->bits); - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - if (buffer[0] == NULL) - { - ESP_LOGE (TAG, "ERROR: buffer [0] is NULL\n"); - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - if (buffer[1] == NULL) - { - ESP_LOGE (TAG, "ERROR: buffer [1] is NULL\n"); - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } + if (frame->header.channels != scSet->ch) { + ESP_LOGE(TAG, + "ERROR: frame header reports different channel count %d than " + "previous metadata block %d", + frame->header.channels, scSet->ch); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if (frame->header.bits_per_sample != scSet->bits) { + ESP_LOGE(TAG, + "ERROR: frame header reports different bps %d than previous " + "metadata block %d", + frame->header.bits_per_sample, scSet->bits); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if (buffer[0] == NULL) { + ESP_LOGE(TAG, "ERROR: buffer [0] is NULL\n"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if (buffer[1] == NULL) { + ESP_LOGE(TAG, "ERROR: buffer [1] is NULL\n"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } - flacData->bytes = frame->header.blocksize * frame->header.channels - * (frame->header.bits_per_sample / 8); + flacData->bytes = frame->header.blocksize * frame->header.channels * + (frame->header.bits_per_sample / 8); // flacData->outData = (char *)realloc (flacData->outData, flacData->bytes); // flacData->outData = (char *)malloc (flacData->bytes); - ret = allocate_pcm_chunk_memory (&(flacData->outData), flacData->bytes); + ret = allocate_pcm_chunk_memory(&(flacData->outData), flacData->bytes); // ESP_LOGI (TAG, "mem %p %p %d", flacData->outData, // flacData->outData->fragment->payload, flacData->bytes); - if (ret == 0) - { - pcm_chunk_fragment_t *fragment = flacData->outData->fragment; + if (ret == 0) { + pcm_chunk_fragment_t *fragment = flacData->outData->fragment; - fragmentCnt = 0; + fragmentCnt = 0; - for (i = 0; i < frame->header.blocksize; i++) - { - // write little endian - // flacData->outData[4 * i] = (uint8_t)buffer[0][i]; - // flacData->outData[4 * i + 1] = (uint8_t) (buffer[0][i] >> 8); - // flacData->outData[4 * i + 2] = (uint8_t)buffer[1][i]; - // flacData->outData[4 * i + 3] = (uint8_t)(buffer[1][i] >> 8); + for (i = 0; i < frame->header.blocksize; i++) { + // write little endian + // flacData->outData[4 * i] = (uint8_t)buffer[0][i]; + // flacData->outData[4 * i + 1] = (uint8_t) (buffer[0][i] >> 8); + // flacData->outData[4 * i + 2] = (uint8_t)buffer[1][i]; + // flacData->outData[4 * i + 3] = (uint8_t)(buffer[1][i] >> 8); - // TODO: for now fragmented payload is not supported and the whole - // chunk is expected to be in the first fragment - tmpData = ((uint32_t) ((buffer[0][i] >> 8) & 0xFF) << 24) - | ((uint32_t) ((buffer[0][i] >> 0) & 0xFF) << 16) - | ((uint32_t) ((buffer[1][i] >> 8) & 0xFF) << 8) - | ((uint32_t) ((buffer[1][i] >> 0) & 0xFF) << 0); + // TODO: for now fragmented payload is not supported and the whole + // chunk is expected to be in the first fragment + tmpData = ((uint32_t)((buffer[0][i] >> 8) & 0xFF) << 24) | + ((uint32_t)((buffer[0][i] >> 0) & 0xFF) << 16) | + ((uint32_t)((buffer[1][i] >> 8) & 0xFF) << 8) | + ((uint32_t)((buffer[1][i] >> 0) & 0xFF) << 0); - if (fragment != NULL) - { - uint32_t *test = (uint32_t *)(&(fragment->payload[fragmentCnt])); - *test = tmpData; - } + if (fragment != NULL) { + uint32_t *test = (uint32_t *)(&(fragment->payload[fragmentCnt])); + *test = tmpData; + } - fragmentCnt += 4; - if (fragmentCnt >= fragment->size) - { - fragmentCnt = 0; + fragmentCnt += 4; + if (fragmentCnt >= fragment->size) { + fragmentCnt = 0; - fragment = fragment->nextFragment; - } - } - } - else - { - flacData->outData = NULL; + fragment = fragment->nextFragment; + } } + } else { + flacData->outData = NULL; + } - xQueueSend (decoderWriteQHdl, &flacData, portMAX_DELAY); + xQueueSend(decoderWriteQHdl, &flacData, portMAX_DELAY); // xSemaphoreGive(flacWriteSemaphore); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } -void -metadata_callback (const FLAC__StreamDecoder *decoder, - const FLAC__StreamMetadata *metadata, void *client_data) -{ +void metadata_callback(const FLAC__StreamDecoder *decoder, + const FLAC__StreamMetadata *metadata, + void *client_data) { flacData_t *flacData = &flacOutData; snapcastSetting_t *scSet = (snapcastSetting_t *)client_data; @@ -300,124 +278,109 @@ metadata_callback (const FLAC__StreamDecoder *decoder, // xQueueReceive (flacReadQHdl, &flacData, portMAX_DELAY); - if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) - { - // ESP_LOGI(TAG, "in flac meta cb"); + if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + // ESP_LOGI(TAG, "in flac meta cb"); - // save for later - scSet->sr = metadata->data.stream_info.sample_rate; - scSet->ch = metadata->data.stream_info.channels; - scSet->bits = metadata->data.stream_info.bits_per_sample; + // save for later + scSet->sr = metadata->data.stream_info.sample_rate; + scSet->ch = metadata->data.stream_info.channels; + scSet->bits = metadata->data.stream_info.bits_per_sample; - xQueueSend (decoderWriteQHdl, &flacData, portMAX_DELAY); - } + xQueueSend(decoderWriteQHdl, &flacData, portMAX_DELAY); + } // xSemaphoreGive(flacReadSemaphore); } -void -error_callback (const FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderErrorStatus status, void *client_data) -{ +void error_callback(const FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderErrorStatus status, void *client_data) { (void)decoder, (void)client_data; - ESP_LOGE (TAG, "Got error callback: %s\n", - FLAC__StreamDecoderErrorStatusString[status]); + ESP_LOGE(TAG, "Got error callback: %s\n", + FLAC__StreamDecoderErrorStatusString[status]); } -static void -flac_decoder_task (void *pvParameters) -{ +static void flac_decoder_task(void *pvParameters) { FLAC__bool ok = true; FLAC__StreamDecoderInitStatus init_status; snapcastSetting_t *scSet = (snapcastSetting_t *)pvParameters; - if (decoderReadQHdl != NULL) - { - vQueueDelete (decoderReadQHdl); - decoderReadQHdl = NULL; - } + if (decoderReadQHdl != NULL) { + vQueueDelete(decoderReadQHdl); + decoderReadQHdl = NULL; + } - decoderReadQHdl = xQueueCreate (1, sizeof (flacData_t *)); - if (decoderReadQHdl == NULL) - { - ESP_LOGE (TAG, "Failed to create flac read queue"); - return; - } + decoderReadQHdl = xQueueCreate(1, sizeof(flacData_t *)); + if (decoderReadQHdl == NULL) { + ESP_LOGE(TAG, "Failed to create flac read queue"); + return; + } - if (decoderWriteQHdl != NULL) - { - vQueueDelete (decoderWriteQHdl); - decoderWriteQHdl = NULL; - } + if (decoderWriteQHdl != NULL) { + vQueueDelete(decoderWriteQHdl); + decoderWriteQHdl = NULL; + } - decoderWriteQHdl = xQueueCreate (1, sizeof (flacData_t *)); - if (decoderWriteQHdl == NULL) - { - ESP_LOGE (TAG, "Failed to create flac write queue"); - return; - } + decoderWriteQHdl = xQueueCreate(1, sizeof(flacData_t *)); + if (decoderWriteQHdl == NULL) { + ESP_LOGE(TAG, "Failed to create flac write queue"); + return; + } - if (flacDecoder != NULL) - { - FLAC__stream_decoder_finish (flacDecoder); - FLAC__stream_decoder_delete (flacDecoder); - flacDecoder = NULL; - } + if (flacDecoder != NULL) { + FLAC__stream_decoder_finish(flacDecoder); + FLAC__stream_decoder_delete(flacDecoder); + flacDecoder = NULL; + } - flacDecoder = FLAC__stream_decoder_new (); - if (flacDecoder == NULL) - { - ESP_LOGE (TAG, "Failed to init flac decoder"); - return; - } + flacDecoder = FLAC__stream_decoder_new(); + if (flacDecoder == NULL) { + ESP_LOGE(TAG, "Failed to init flac decoder"); + return; + } - init_status = FLAC__stream_decoder_init_stream ( + init_status = FLAC__stream_decoder_init_stream( flacDecoder, read_callback, NULL, NULL, NULL, NULL, write_callback, metadata_callback, error_callback, scSet); - if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) - { - ESP_LOGE (TAG, "ERROR: initializing decoder: %s\n", - FLAC__StreamDecoderInitStatusString[init_status]); - ok = false; - return; - } + if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + ESP_LOGE(TAG, "ERROR: initializing decoder: %s\n", + FLAC__StreamDecoderInitStatusString[init_status]); + ok = false; + return; + } - while (1) - { - FLAC__stream_decoder_process_until_end_of_stream (flacDecoder); - } + while (1) { + FLAC__stream_decoder_process_until_end_of_stream(flacDecoder); + } } static char base_message_serialized[BASE_MESSAGE_SIZE]; static char time_message_serialized[TIME_MESSAGE_SIZE]; -static const esp_timer_create_args_t tSyncArgs - = { .callback = &time_sync_msg_cb, .name = "tSyncMsg" }; +static const esp_timer_create_args_t tSyncArgs = {.callback = &time_sync_msg_cb, + .name = "tSyncMsg"}; struct netconn *lwipNetconn; /** * */ -static void -http_get_task (void *pvParameters) -{ +static void http_get_task(void *pvParameters) { struct sockaddr_in servaddr; char *start; int sock = -1; base_message_t base_message_rx; base_message_t base_message_tx; hello_message_t hello_message; - wire_chunk_message_t wire_chnk = { { 0, 0 }, 0, NULL }; + wire_chunk_message_t wire_chnk = {{0, 0}, 0, NULL}; char *hello_message_serialized = NULL; int result, size, id_counter; struct timeval now, trx, tdif, ttx; - time_message_t time_message_rx = { { 0, 0 } }; - time_message_t time_message_tx = { { 0, 0 } }; + time_message_t time_message_rx = {{0, 0}}; + time_message_t time_message_tx = {{0, 0}}; struct timeval tmpDiffToServer; - struct timeval lastTimeSync = { 0, 0 }; + struct timeval lastTimeSync = {0, 0}; esp_timer_handle_t timeSyncMessageTimer = NULL; - int16_t frameSize = 960; // 960*2: 20ms, 960*1: 10ms + int16_t frameSize = 960; // 960*2: 20ms, 960*1: 10ms int16_t *audio = NULL; int16_t pcm_size = 120; uint16_t channels; @@ -429,7 +392,7 @@ http_get_task (void *pvParameters) OpusDecoder *opusDecoder = NULL; codec_type_t codec = NONE; snapcastSetting_t scSet; - flacData_t flacData = { NULL, NULL, 0 }; + flacData_t flacData = {NULL, NULL, 0}; flacData_t *pFlacData; pcm_chunk_message_t *pcmData = NULL; char *typedMsg = NULL; @@ -444,2249 +407,1871 @@ http_get_task (void *pvParameters) uint16_t len; // create a timer to send time sync messages every x µs - esp_timer_create (&tSyncArgs, &timeSyncMessageTimer); - timeSyncSemaphoreHandle = xSemaphoreCreateMutex (); - xSemaphoreGive (timeSyncSemaphoreHandle); + esp_timer_create(&tSyncArgs, &timeSyncMessageTimer); + timeSyncSemaphoreHandle = xSemaphoreCreateMutex(); + xSemaphoreGive(timeSyncSemaphoreHandle); id_counter = 0; #if CONFIG_SNAPCLIENT_USE_MDNS - ESP_LOGI (TAG, "Enable mdns"); - mdns_init (); + ESP_LOGI(TAG, "Enable mdns"); + mdns_init(); #endif - while (1) - { - if (reset_latency_buffer () < 0) - { - ESP_LOGE ( - TAG, - "reset_diff_buffer: couldn't reset median filter long. STOP"); + while (1) { + if (reset_latency_buffer() < 0) { + ESP_LOGE(TAG, + "reset_diff_buffer: couldn't reset median filter long. STOP"); - return; - } + return; + } - esp_timer_stop (timeSyncMessageTimer); - xSemaphoreGive (timeSyncSemaphoreHandle); + esp_timer_stop(timeSyncMessageTimer); + xSemaphoreGive(timeSyncSemaphoreHandle); - if (opusDecoder != NULL) - { - opus_decoder_destroy (opusDecoder); - opusDecoder = NULL; - } + if (opusDecoder != NULL) { + opus_decoder_destroy(opusDecoder); + opusDecoder = NULL; + } - if (t_flac_decoder_task != NULL) - { - vTaskDelete (t_flac_decoder_task); - t_flac_decoder_task = NULL; - } + if (t_flac_decoder_task != NULL) { + vTaskDelete(t_flac_decoder_task); + t_flac_decoder_task = NULL; + } - if (flacDecoder != NULL) - { - FLAC__stream_decoder_finish (flacDecoder); - FLAC__stream_decoder_delete (flacDecoder); - flacDecoder = NULL; - } + if (flacDecoder != NULL) { + FLAC__stream_decoder_finish(flacDecoder); + FLAC__stream_decoder_delete(flacDecoder); + flacDecoder = NULL; + } - if (decoderWriteQHdl != NULL) - { - vQueueDelete (decoderWriteQHdl); - decoderWriteQHdl = NULL; - } + if (decoderWriteQHdl != NULL) { + vQueueDelete(decoderWriteQHdl); + decoderWriteQHdl = NULL; + } - if (decoderReadQHdl != NULL) - { - vQueueDelete (decoderReadQHdl); - decoderReadQHdl = NULL; - } + if (decoderReadQHdl != NULL) { + vQueueDelete(decoderReadQHdl); + decoderReadQHdl = NULL; + } #if SNAPCAST_SERVER_USE_MDNS - // Find snapcast server - // Connect to first snapcast server found - r = NULL; - err = 0; - while (!r || err) - { - ESP_LOGI (TAG, "Lookup snapcast service on network"); - esp_err_t err = mdns_query_ptr ("_snapcast", "_tcp", 3000, 20, &r); - if (err) - { - ESP_LOGE (TAG, "Query Failed"); - vTaskDelay (pdMS_TO_TICKS (1000)); - } + // Find snapcast server + // Connect to first snapcast server found + r = NULL; + err = 0; + while (!r || err) { + ESP_LOGI(TAG, "Lookup snapcast service on network"); + esp_err_t err = mdns_query_ptr("_snapcast", "_tcp", 3000, 20, &r); + if (err) { + ESP_LOGE(TAG, "Query Failed"); + vTaskDelay(pdMS_TO_TICKS(1000)); + } - if (!r) - { - ESP_LOGW (TAG, "No results found!"); - vTaskDelay (pdMS_TO_TICKS (1000)); - } - } + if (!r) { + ESP_LOGW(TAG, "No results found!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + } - // char serverAddr[] = "255.255.255.255"; - // ESP_LOGI (TAG, "Found %s:%d", - // inet_ntop (AF_INET, &(r->addr->addr.u_addr.ip4.addr), - // serverAddr, sizeof (serverAddr)), - // r->port); + // char serverAddr[] = "255.255.255.255"; + // ESP_LOGI (TAG, "Found %s:%d", + // inet_ntop (AF_INET, &(r->addr->addr.u_addr.ip4.addr), + // serverAddr, sizeof (serverAddr)), + // r->port); - if (r->addr) - { - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = r->addr->addr.u_addr.ip4.addr; - servaddr.sin_port = htons (r->port); - - ip_addr_copy (remote_ip, (r->addr->addr)); - remotePort = r->port; - ESP_LOGI (TAG, "Found %s:%d", ipaddr_ntoa (&remote_ip), remotePort); - - mdns_query_results_free (r); - } - else - { - mdns_query_results_free (r); - - ESP_LOGW (TAG, "No IP found in MDNS query"); - - continue; - } -#else - // configure a failsafe snapserver according to CONFIG values + if (r->addr) { servaddr.sin_family = AF_INET; - inet_pton (AF_INET, SNAPCAST_SERVER_HOST, &(servaddr.sin_addr.s_addr)); - servaddr.sin_port = htons (SNAPCAST_SERVER_PORT); + servaddr.sin_addr.s_addr = r->addr->addr.u_addr.ip4.addr; + servaddr.sin_port = htons(r->port); - inet_pton (AF_INET, SNAPCAST_SERVER_HOST, &(remote_ip.u_addr.ip4.addr)); - remotePort = SNAPCAST_SERVER_PORT; + ip_addr_copy(remote_ip, (r->addr->addr)); + remote_ip.type = IPADDR_TYPE_V4; + remotePort = r->port; + ESP_LOGI(TAG, "Found %s:%d", ipaddr_ntoa(&remote_ip), remotePort); + + mdns_query_results_free(r); + } else { + mdns_query_results_free(r); + + ESP_LOGW(TAG, "No IP found in MDNS query"); + + continue; + } +#else + // configure a failsafe snapserver according to CONFIG values + servaddr.sin_family = AF_INET; + inet_pton(AF_INET, SNAPCAST_SERVER_HOST, &(servaddr.sin_addr.s_addr)); + servaddr.sin_port = htons(SNAPCAST_SERVER_PORT); + + inet_pton(AF_INET, SNAPCAST_SERVER_HOST, &(remote_ip.u_addr.ip4.addr)); + remote_ip.type = IPADDR_TYPE_V4; + remotePort = SNAPCAST_SERVER_PORT; + + ESP_LOGI(TAG, "try connecting to static configuration %s:%d", + ipaddr_ntoa(&remote_ip), remotePort); #endif - if (lwipNetconn != NULL) - { - netconn_delete (lwipNetconn); - lwipNetconn = NULL; - } + if (lwipNetconn != NULL) { + netconn_delete(lwipNetconn); + lwipNetconn = NULL; + } - lwipNetconn = netconn_new (NETCONN_TCP); - if (lwipNetconn == NULL) - { - ESP_LOGE (TAG, "can't create netconn"); + lwipNetconn = netconn_new(NETCONN_TCP); + if (lwipNetconn == NULL) { + ESP_LOGE(TAG, "can't create netconn"); - continue; - } + continue; + } - rc1 = netconn_bind (lwipNetconn, IPADDR_ANY, 0); - if (rc1 != ERR_OK) - { - ESP_LOGE (TAG, "can't bind local IP"); - } + rc1 = netconn_bind(lwipNetconn, IPADDR_ANY, 0); + if (rc1 != ERR_OK) { + ESP_LOGE(TAG, "can't bind local IP"); + } - // ipaddr_aton("192.168.1.54", &remote_ip); - rc2 = netconn_connect (lwipNetconn, &remote_ip, remotePort); - if (rc2 != ERR_OK) - { - ESP_LOGE (TAG, "can't connect to remote %s:%d, err %d", - ipaddr_ntoa (&remote_ip), remotePort, rc2); - } - if (rc1 != ERR_OK || rc2 != ERR_OK) - { - netconn_close (lwipNetconn); - netconn_delete (lwipNetconn); - lwipNetconn = NULL; + // ipaddr_aton("192.168.1.54", &remote_ip); + rc2 = netconn_connect(lwipNetconn, &remote_ip, remotePort); + if (rc2 != ERR_OK) { + ESP_LOGE(TAG, "can't connect to remote %s:%d, err %d", + ipaddr_ntoa(&remote_ip), remotePort, rc2); + } + if (rc1 != ERR_OK || rc2 != ERR_OK) { + netconn_close(lwipNetconn); + netconn_delete(lwipNetconn); + lwipNetconn = NULL; - continue; - } + continue; + } - ESP_LOGI (TAG, "netconn connected"); + ESP_LOGI(TAG, "netconn connected"); - result = gettimeofday (&now, NULL); - if (result) - { - ESP_LOGE (TAG, "Failed to gettimeofday\r\n"); - return; - } + result = gettimeofday(&now, NULL); + if (result) { + ESP_LOGE(TAG, "Failed to gettimeofday\r\n"); + return; + } - received_header = false; + received_header = false; - // init base message - base_message_rx.type = SNAPCAST_MESSAGE_HELLO; - base_message_rx.id = 0x0000; - base_message_rx.refersTo = 0x0000; - base_message_rx.sent.sec = now.tv_sec; - base_message_rx.sent.usec = now.tv_usec; - base_message_rx.received.sec = 0; - base_message_rx.received.usec = 0; - base_message_rx.size = 0x00000000; + // init base message + base_message_rx.type = SNAPCAST_MESSAGE_HELLO; + base_message_rx.id = 0x0000; + base_message_rx.refersTo = 0x0000; + base_message_rx.sent.sec = now.tv_sec; + base_message_rx.sent.usec = now.tv_usec; + base_message_rx.received.sec = 0; + base_message_rx.received.usec = 0; + base_message_rx.size = 0x00000000; - // init hello message - hello_message.mac = mac_address; - hello_message.hostname = "ESP32-Caster"; - hello_message.version = (char *)VERSION_STRING; - hello_message.client_name = "libsnapcast"; - hello_message.os = "esp32"; - hello_message.arch = "xtensa"; - hello_message.instance = 1; - hello_message.id = mac_address; - hello_message.protocol_version = 2; + // init hello message + hello_message.mac = mac_address; + hello_message.hostname = "ESP32-Caster"; + hello_message.version = (char *)VERSION_STRING; + hello_message.client_name = "libsnapcast"; + hello_message.os = "esp32"; + hello_message.arch = "xtensa"; + hello_message.instance = 1; + hello_message.id = mac_address; + hello_message.protocol_version = 2; - if (hello_message_serialized == NULL) - { - hello_message_serialized = hello_message_serialize ( - &hello_message, (size_t *)&(base_message_rx.size)); - if (!hello_message_serialized) - { - ESP_LOGE (TAG, "Failed to serialize hello message"); - return; - } - } + if (hello_message_serialized == NULL) { + hello_message_serialized = hello_message_serialize( + &hello_message, (size_t *)&(base_message_rx.size)); + if (!hello_message_serialized) { + ESP_LOGE(TAG, "Failed to serialize hello message"); + return; + } + } - result = base_message_serialize ( - &base_message_rx, base_message_serialized, BASE_MESSAGE_SIZE); - if (result) - { - ESP_LOGE (TAG, "Failed to serialize base message"); - return; - } + result = base_message_serialize(&base_message_rx, base_message_serialized, + BASE_MESSAGE_SIZE); + if (result) { + ESP_LOGE(TAG, "Failed to serialize base message"); + return; + } - rc1 = netconn_write (lwipNetconn, base_message_serialized, - BASE_MESSAGE_SIZE, NETCONN_NOCOPY); - if (rc1 != ERR_OK) - { - ESP_LOGE (TAG, "netconn failed to send base message"); + rc1 = netconn_write(lwipNetconn, base_message_serialized, BASE_MESSAGE_SIZE, + NETCONN_NOCOPY); + if (rc1 != ERR_OK) { + ESP_LOGE(TAG, "netconn failed to send base message"); - continue; - } - rc1 = netconn_write (lwipNetconn, hello_message_serialized, - base_message_rx.size, NETCONN_NOCOPY); - if (rc1 != ERR_OK) - { - ESP_LOGE (TAG, "netconn failed to send hello message"); + continue; + } + rc1 = netconn_write(lwipNetconn, hello_message_serialized, + base_message_rx.size, NETCONN_NOCOPY); + if (rc1 != ERR_OK) { + ESP_LOGE(TAG, "netconn failed to send hello message"); - continue; - } + continue; + } - ESP_LOGI (TAG, "netconn sent hello message"); + ESP_LOGI(TAG, "netconn sent hello message"); - free (hello_message_serialized); - hello_message_serialized = NULL; + free(hello_message_serialized); + hello_message_serialized = NULL; - // init default setting - scSet.buf_ms = 0; - scSet.codec = NONE; - scSet.bits = 0; - scSet.ch = 0; - scSet.sr = 0; - scSet.chkDur_ms = 0; - scSet.volume = 0; - scSet.muted = true; + // init default setting + scSet.buf_ms = 0; + scSet.codec = NONE; + scSet.bits = 0; + scSet.ch = 0; + scSet.sr = 0; + scSet.chkDur_ms = 0; + scSet.volume = 0; + scSet.muted = true; - uint32_t cntTmp = 0; - uint64_t startTime, endTime; - char *tmp; - int32_t remainderSize = 0; - size_t currentPos = 0; - size_t typedMsgCurrentPos = 0; - uint32_t typedMsgLen = 0; - uint32_t offset = 0; - size = 0; - uint32_t tmpData = 0; - uint32_t *p_tmpData = NULL; - int32_t shift = 24; + uint32_t cntTmp = 0; + uint64_t startTime, endTime; + char *tmp; + int32_t remainderSize = 0; + size_t currentPos = 0; + size_t typedMsgCurrentPos = 0; + uint32_t typedMsgLen = 0; + uint32_t offset = 0; + size = 0; + uint32_t tmpData = 0; + uint32_t *p_tmpData = NULL; + int32_t shift = 24; #define BASE_MESSAGE_STATE 0 #define TYPED_MESSAGE_STATE 1 - uint32_t state - = BASE_MESSAGE_STATE; // 0 ... base message, 1 ... typed message - uint32_t internalState = 0; - uint32_t counter = 0; + uint32_t state = + BASE_MESSAGE_STATE; // 0 ... base message, 1 ... typed message + uint32_t internalState = 0; + uint32_t counter = 0; - firstNetBuf = NULL; + firstNetBuf = NULL; - decoderWriteSemaphore = xSemaphoreCreateMutex (); - xSemaphoreTake (decoderWriteSemaphore, portMAX_DELAY); + decoderWriteSemaphore = xSemaphoreCreateMutex(); + xSemaphoreTake(decoderWriteSemaphore, portMAX_DELAY); - decoderReadSemaphore = xSemaphoreCreateMutex (); - xSemaphoreGive (decoderReadSemaphore); // only decoder read callback/task - // can give semaphore + decoderReadSemaphore = xSemaphoreCreateMutex(); + xSemaphoreGive(decoderReadSemaphore); // only decoder read callback/task + // can give semaphore - while (1) - { - rc2 = netconn_recv (lwipNetconn, &firstNetBuf); - if (rc2 != ERR_OK) - { - if (rc2 == ERR_CONN) - { - netconn_close (lwipNetconn); + while (1) { + rc2 = netconn_recv(lwipNetconn, &firstNetBuf); + if (rc2 != ERR_OK) { + if (rc2 == ERR_CONN) { + netconn_close(lwipNetconn); - // restart and try to reconnect + // restart and try to reconnect + break; + } + + if (firstNetBuf != NULL) { + netbuf_delete(firstNetBuf); + + firstNetBuf = NULL; + } + continue; + } + + // now parse the data + netbuf_first(firstNetBuf); + do { + currentPos = 0; + + rc1 = netbuf_data(firstNetBuf, (void **)&start, &len); + if (rc1 == ERR_OK) { + // ESP_LOGI (TAG, "netconn rx," + // "data len: %d, %d", len, netbuf_len(firstNetBuf) - + // currentPos); + } else { + ESP_LOGE(TAG, "netconn rx, couldn't get data"); + + continue; + } + + while (len > 0) { + rc1 = ERR_OK; // probably not necessary + + switch (state) { + // decode base message + case BASE_MESSAGE_STATE: { + switch (internalState) { + case 0: + result = gettimeofday(&now, NULL); + // ESP_LOGI(TAG, "time of day: %ld %ld", + // now.tv_sec, now.tv_usec); + if (result) { + ESP_LOGW(TAG, "Failed to gettimeofday"); + } + + base_message_rx.type = *start & 0xFF; + internalState++; break; - } - if (firstNetBuf != NULL) - { - netbuf_delete (firstNetBuf); - - firstNetBuf = NULL; - } - continue; - } - - // now parse the data - netbuf_first (firstNetBuf); - do - { - currentPos = 0; - - rc1 = netbuf_data (firstNetBuf, (void **)&start, &len); - if (rc1 == ERR_OK) - { - // ESP_LOGI (TAG, "netconn rx," - // "data len: %d, %d", len, netbuf_len(firstNetBuf) - - // currentPos); - } - else - { - ESP_LOGE (TAG, "netconn rx, couldn't get data"); - - continue; - } - - while (len > 0) - { - rc1 = ERR_OK; // probably not necessary - - switch (state) - { - // decode base message - case BASE_MESSAGE_STATE: - { - switch (internalState) - { - case 0: - result = gettimeofday (&now, NULL); - // ESP_LOGI(TAG, "time of day: %ld %ld", - // now.tv_sec, now.tv_usec); - if (result) - { - ESP_LOGW (TAG, "Failed to gettimeofday"); - } - - base_message_rx.type = *start & 0xFF; - internalState++; - break; - - case 1: - base_message_rx.type |= (*start & 0xFF) << 8; - internalState++; - break; - - case 2: - base_message_rx.id = *start & 0xFF; - internalState++; - break; - - case 3: - base_message_rx.id |= (*start & 0xFF) << 8; - internalState++; - break; - - case 4: - base_message_rx.refersTo = *start & 0xFF; - internalState++; - break; - - case 5: - base_message_rx.refersTo |= (*start & 0xFF) << 8; - internalState++; - break; - - case 6: - base_message_rx.sent.sec = *start & 0xFF; - internalState++; - break; - - case 7: - base_message_rx.sent.sec |= (*start & 0xFF) << 8; - internalState++; - break; - - case 8: - base_message_rx.sent.sec |= (*start & 0xFF) << 16; - internalState++; - break; - - case 9: - base_message_rx.sent.sec |= (*start & 0xFF) << 24; - internalState++; - break; - - case 10: - base_message_rx.sent.usec = *start & 0xFF; - internalState++; - break; - - case 11: - base_message_rx.sent.usec |= (*start & 0xFF) << 8; - internalState++; - break; - - case 12: - base_message_rx.sent.usec |= (*start & 0xFF) << 16; - internalState++; - break; - - case 13: - base_message_rx.sent.usec |= (*start & 0xFF) << 24; - internalState++; - break; - - case 14: - base_message_rx.received.sec = *start & 0xFF; - internalState++; - break; - - case 15: - base_message_rx.received.sec |= (*start & 0xFF) - << 8; - internalState++; - break; - - case 16: - base_message_rx.received.sec |= (*start & 0xFF) - << 16; - internalState++; - break; - - case 17: - base_message_rx.received.sec |= (*start & 0xFF) - << 24; - internalState++; - break; - - case 18: - base_message_rx.received.usec = *start & 0xFF; - internalState++; - break; - - case 19: - base_message_rx.received.usec |= (*start & 0xFF) - << 8; - internalState++; - break; - - case 20: - base_message_rx.received.usec |= (*start & 0xFF) - << 16; - internalState++; - break; - - case 21: - base_message_rx.received.usec |= (*start & 0xFF) - << 24; - internalState++; - break; - - case 22: - base_message_rx.size = *start & 0xFF; - internalState++; - break; - - case 23: - base_message_rx.size |= (*start & 0xFF) << 8; - internalState++; - break; - - case 24: - base_message_rx.size |= (*start & 0xFF) << 16; - internalState++; - break; - - case 25: - base_message_rx.size |= (*start & 0xFF) << 24; - internalState = 0; - - base_message_rx.received.sec = now.tv_sec; - base_message_rx.received.usec = now.tv_usec; - - typedMsgCurrentPos = 0; - - // ESP_LOGI(TAG,"BM type %d ts %d.%d", - // base_message_rx.type, - // base_message_rx.received.sec, - // base_message_rx.received.usec); - // ESP_LOGI(TAG,"%d - //%d.%d", base_message_rx.type, - // base_message_rx.received.sec, - // base_message_rx.received.usec); - - state = TYPED_MESSAGE_STATE; - break; - } - - currentPos++; - len--; - start++; - - break; - } - - // decode typed message - case TYPED_MESSAGE_STATE: - { - switch (base_message_rx.type) - { - case SNAPCAST_MESSAGE_WIRE_CHUNK: - { - switch (internalState) - { - case 0: - { - wire_chnk.timestamp.sec = *start & 0xFF; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 1: - { - wire_chnk.timestamp.sec |= (*start & 0xFF) - << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 2: - { - wire_chnk.timestamp.sec |= (*start & 0xFF) - << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 3: - { - wire_chnk.timestamp.sec |= (*start & 0xFF) - << 24; - - // ESP_LOGI(TAG, - // "wire chunk time sec: %d", - // wire_chnk.timestamp.sec); - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 4: - { - wire_chnk.timestamp.usec = (*start & 0xFF); - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 5: - { - wire_chnk.timestamp.usec |= (*start & 0xFF) - << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 6: - { - wire_chnk.timestamp.usec |= (*start & 0xFF) - << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 7: - { - wire_chnk.timestamp.usec |= (*start & 0xFF) - << 24; - - // ESP_LOGI(TAG, - // "wire chunk time usec: %d", - // wire_chnk.timestamp.usec); - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 8: - { - wire_chnk.size = (*start & 0xFF); - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 9: - { - wire_chnk.size |= (*start & 0xFF) << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 10: - { - wire_chnk.size |= (*start & 0xFF) << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 11: - { - wire_chnk.size |= (*start & 0xFF) << 24; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - // ESP_LOGI(TAG, - // "got wire chunk with size: %d, at time" - // " %d.%d", wire_chnk.size, - // wire_chnk.timestamp.sec, - // wire_chnk.timestamp.usec); - - break; - } - - case 12: - { - size_t tmp; - - if ((base_message_rx.size - - typedMsgCurrentPos) - <= len) - { - tmp = base_message_rx.size - - typedMsgCurrentPos; - } - else - { - tmp = len; - } - - if (received_header == true) - { - switch (codec) - { - case FLAC: - { - flacData.bytes = tmp; - flacData.inData = start; - pFlacData = &flacData; - - xSemaphoreTake ( - decoderReadSemaphore, - portMAX_DELAY); - - // send data to flac decoder - xQueueSend (decoderReadQHdl, - &pFlacData, - portMAX_DELAY); - // and wait until data was - // processed - xSemaphoreTake ( - decoderReadSemaphore, - portMAX_DELAY); - // need to release mutex - // afterwards for next round - xSemaphoreGive ( - decoderReadSemaphore); - - break; - } - - case PCM: - { - if (pcmData == NULL) - { - if (allocate_pcm_chunk_memory ( - &pcmData, - wire_chnk.size) - < 0) - { - pcmData = NULL; - } - - offset = 0; - remainderSize = 0; - cntTmp = 0; - } - - if (pcmData != NULL) - { - uint32_t *sample; - - int max = 0, begin = 0; - - while (remainderSize) - { - tmpData - |= ((uint32_t)start - [begin++] - << (8 - * (remainderSize - - 1))); - - remainderSize--; - if (remainderSize < 0) - { - ESP_LOGE ( - TAG, - "shift < 0 this " - "shouldn't " - "happen"); - - return; - } - } - - // check if we need to write - // a remaining sample - if (begin > 0) - { - // need to reorder bytes - // in sample for correct - // playback - uint8_t dummy1; - uint32_t dummy2 = 0; - - // TODO: find a more - // clever way to do this, - // best would be to - // actually store it the - // right way in the first - // place - dummy1 = tmpData >> 24; - dummy2 - |= (uint32_t)dummy1 - << 16; - dummy1 = tmpData >> 16; - dummy2 - |= (uint32_t)dummy1 - << 24; - dummy1 = tmpData >> 8; - dummy2 - |= (uint32_t)dummy1 - << 0; - dummy1 = tmpData >> 0; - dummy2 - |= (uint32_t)dummy1 - << 8; - tmpData = dummy2; - - sample = (uint32_t *)(&( - pcmData->fragment - ->payload - [offset])); - *sample = tmpData; - - offset += 4; - } - - remainderSize - = (tmp - begin) % 4; - max = (tmp - begin) - - remainderSize; - - for (int i = begin; i < max; - i += 4) - { - // TODO: for now - // fragmented payload is - // not supported and the - // whole chunk is - // expected to be in the - // first fragment - tmpData - = ((uint32_t)start[i] - << 16) - | ((uint32_t) - start[i + 1] - << 24) - | ((uint32_t) - start[i + 2] - << 0) - | ((uint32_t) - start[i + 3] - << 8); - - // ensure 32bit alligned - // write - sample = (uint32_t *)(&( - pcmData->fragment - ->payload - [offset])); - *sample = tmpData; - - offset += 4; - } - - tmpData = 0; - while (remainderSize) - { - tmpData - |= ((uint32_t) - start[max++] - << (8 - * (remainderSize - - 1))); - - remainderSize--; - - if (remainderSize < 0) - { - ESP_LOGE ( - TAG, - "shift < 0 this " - "shouldn't " - "happen"); - - return; - } - } - - remainderSize - = (tmp - begin) % 4; - if (remainderSize) - { - remainderSize - = 4 - - remainderSize; // these are the still needed bytes for next round - tmpData - <<= (8 - * remainderSize); // shift data to correct position - } - } - - break; - } - - default: - { - ESP_LOGE ( - TAG, - "Decoder (1) not supported"); - - return; - - break; - } - } - } - - typedMsgCurrentPos += tmp; - start += tmp; - currentPos += tmp; - len -= tmp; - - if (typedMsgCurrentPos - >= base_message_rx.size) - { - // ESP_LOGI(TAG, - //"data remaining %d %d", len, - // currentPos); - // ESP_LOGI(TAG, "got wire chunk with - // size: %d, at time %d.%d", - // wire_chnk.size, - // wire_chnk.timestamp.sec, - // wire_chnk.timestamp.usec); - - if (received_header == true) - { - switch (codec) - { - case FLAC: - { - xSemaphoreGive ( - decoderWriteSemaphore); - // and wait until it is done - xQueueReceive ( - decoderWriteQHdl, - &pFlacData, - portMAX_DELAY); - - if (pFlacData->outData - != NULL) - { - pcmData - = pFlacData->outData; - pcmData->timestamp - = wire_chnk - .timestamp; - - size_t decodedSize - = pcmData - ->totalSize; // pFlacData->bytes; - scSet.chkDur_ms - = (1000UL - * decodedSize) - / (uint32_t) ( - scSet.ch - * (scSet.bits - / 8)) - / scSet.sr; - if (player_send_snapcast_setting ( - &scSet) - != pdPASS) - { - ESP_LOGE ( - TAG, - "Failed to " - "notify " - "sync task " - "about " - "codec. Did you " - "init player?"); - - return; - } - -#if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow ( - 500, scSet.sr, - scSet.chkDur_ms); - dsp_processor ( - pcm_chunk_message - .payload, - pcm_chunk_message - .size, - dspFlow); -#endif - - insert_pcm_chunk ( - pcmData); - pcmData = NULL; - } - - break; - } - - case PCM: - { - size_t decodedSize - = pcmData->fragment - ->size; - - pcmData->timestamp - = wire_chnk.timestamp; - - scSet.chkDur_ms - = (1000UL * decodedSize) - / (uint32_t) ( - scSet.ch - * (scSet.bits - / 8)) - / scSet.sr; - if (player_send_snapcast_setting ( - &scSet) - != pdPASS) - { - ESP_LOGE ( - TAG, - "Failed to notify " - "sync task about " - "codec. Did you " - "init player?"); - - return; - } - -#if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow ( - 500, scSet.sr, - scSet.chkDur_ms); - dsp_processor ( - pcm_chunk_message - .payload, - pcm_chunk_message.size, - dspFlow); -#endif - - insert_pcm_chunk (pcmData); - pcmData = NULL; - break; - } - - default: - { - ESP_LOGE (TAG, - "Decoder (2) not " - "supported"); - - return; - - break; - } - } - } - - state = BASE_MESSAGE_STATE; - internalState = 0; - - typedMsgCurrentPos = 0; - } - - break; - } - - default: - { - ESP_LOGE (TAG, "wire chunk decoder " - "shouldn't get here"); - - break; - } - } - - break; - } - - case SNAPCAST_MESSAGE_CODEC_HEADER: - { - switch (internalState) - { - case 0: - { - typedMsgLen = *start & 0xFF; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 1: - { - typedMsgLen |= (*start & 0xFF) << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 2: - { - typedMsgLen |= (*start & 0xFF) << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 3: - { - typedMsgLen |= (*start & 0xFF) << 24; - - tmp = malloc (typedMsgLen - + 1); // allocate memory for - // codec string - if (tmp == NULL) - { - ESP_LOGE (TAG, "couldn't get memory " - "for codec string"); - - return; - } - - offset = 0; - // ESP_LOGI(TAG, - // "codec header string is %d long", - // typedMsgLen); - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 4: - { - if (len >= typedMsgLen) - { - memcpy (&tmp[offset], start, - typedMsgLen); - - offset += typedMsgLen; - - typedMsgCurrentPos += typedMsgLen; - start += typedMsgLen; - currentPos += typedMsgLen; - len -= typedMsgLen; - } - else - { - memcpy (&tmp[offset], start, - typedMsgLen); - - offset += len; - - typedMsgCurrentPos += len; - start += len; - currentPos += len; - len -= len; - } - - if (offset == typedMsgLen) - { - // NULL terminate string - tmp[typedMsgLen] = 0; - - // ESP_LOGI - // (TAG, "got codec string: %s", tmp); - - if (strcmp (tmp, "opus") == 0) - { - codec = OPUS; - } - else if (strcmp (tmp, "flac") == 0) - { - codec = FLAC; - } - else if (strcmp (tmp, "pcm") == 0) - { - codec = PCM; - } - else - { - codec = NONE; - - ESP_LOGI ( - TAG, - "Codec : %s not supported", - tmp); - ESP_LOGI ( - TAG, "Change encoder codec to " - "opus, flac or pcm in " - "/etc/snapserver.conf on " - "server"); - - return; - } - - free (tmp); - tmp = NULL; - - internalState++; - } - - break; - } - - case 5: - { - typedMsgLen = *start & 0xFF; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 6: - { - typedMsgLen |= (*start & 0xFF) << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 7: - { - typedMsgLen |= (*start & 0xFF) << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 8: - { - typedMsgLen |= (*start & 0xFF) << 24; - - tmp = malloc ( - typedMsgLen); // allocate memory for - // codec string - if (tmp == NULL) - { - ESP_LOGE (TAG, "couldn't get memory " - "for codec string"); - - return; - } - - offset = 0; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 9: - { - if (len >= typedMsgLen) - { - memcpy (&tmp[offset], start, - typedMsgLen); - - offset += typedMsgLen; - - typedMsgCurrentPos += typedMsgLen; - start += typedMsgLen; - currentPos += typedMsgLen; - len -= typedMsgLen; - } - else - { - memcpy (&tmp[offset], start, - typedMsgLen); - - offset += len; - - typedMsgCurrentPos += len; - start += len; - currentPos += len; - len -= len; - } - - if (offset == typedMsgLen) - { - // first ensure everything is set up - // correctly and resources are - // available - if (t_flac_decoder_task != NULL) - { - vTaskDelete (t_flac_decoder_task); - t_flac_decoder_task = NULL; - } - - if (flacDecoder != NULL) - { - FLAC__stream_decoder_finish ( - flacDecoder); - FLAC__stream_decoder_delete ( - flacDecoder); - flacDecoder = NULL; - } - - if (decoderWriteQHdl != NULL) - { - vQueueDelete (decoderWriteQHdl); - decoderWriteQHdl = NULL; - } - - if (decoderReadQHdl != NULL) - { - vQueueDelete (decoderReadQHdl); - decoderReadQHdl = NULL; - } - - if (codec == OPUS) - { - ESP_LOGI ( - TAG, - "OPUS not implemented yet"); - - return; - } - else if (codec == FLAC) - { - if (t_flac_decoder_task == NULL) - { - xTaskCreatePinnedToCore ( - &flac_decoder_task, - "flac_decoder_task", - 9 * 256, &scSet, - FLAC_TASK_PRIORITY, - &t_flac_decoder_task, - FLAC_TASK_CORE_ID); - } - - if (flacData.outData != NULL) - { - free (flacData.outData); - flacData.outData = NULL; - } - - flacData.bytes = typedMsgLen; - flacData.inData = tmp; - pFlacData = &flacData; - - // TODO: find a smarter way for - // this wait for task creation done - while (decoderReadQHdl == NULL) - { - vTaskDelay (10); - } - - xSemaphoreTake ( - decoderReadSemaphore, - portMAX_DELAY); - - // send data to flac decoder - xQueueSend (decoderReadQHdl, - &pFlacData, - portMAX_DELAY); - // and wait until data was - // processed - xSemaphoreTake ( - decoderReadSemaphore, - portMAX_DELAY); - // need to release mutex afterwards - // for next round - xSemaphoreGive ( - decoderReadSemaphore); - // wait until it is done - xQueueReceive (decoderWriteQHdl, - &pFlacData, - portMAX_DELAY); - - ESP_LOGI ( - TAG, - "fLaC sampleformat: %d:%d:%d", - scSet.sr, scSet.bits, - scSet.ch); - } - else if (codec == PCM) - { - memcpy (&channels, tmp + 22, - sizeof (channels)); - uint32_t rate; - memcpy (&rate, tmp + 24, - sizeof (rate)); - uint16_t bits; - memcpy (&bits, tmp + 34, - sizeof (bits)); - - scSet.codec = codec; - scSet.bits = bits; - scSet.ch = channels; - scSet.sr = rate; - - ESP_LOGI ( - TAG, - "pcm sampleformat: %d:%d:%d", - scSet.sr, scSet.bits, - scSet.ch); - } - else - { - ESP_LOGE ( - TAG, - "codec header decoder " - "shouldn't get here after " - "codec string was detected"); - - return; - } - - free (tmp); - tmp = NULL; - - // ESP_LOGI(TAG, - //"done codec header msg"); - - trx.tv_sec = base_message_rx.sent.sec; - trx.tv_usec - = base_message_rx.sent.usec; - // we do this, so uint32_t timvals - // won't overflow if e.g. raspberry - // server is off to far - settimeofday (&trx, NULL); - ESP_LOGI (TAG, - "syncing clock to server " - "%ld.%06ld", - trx.tv_sec, trx.tv_usec); - - state = BASE_MESSAGE_STATE; - internalState = 0; - - received_header = true; - } - - break; - } - - default: - { - ESP_LOGE (TAG, "codec header decoder " - "shouldn't get here"); - - break; - } - } - - break; - } - - case SNAPCAST_MESSAGE_SERVER_SETTINGS: - { - switch (internalState) - { - case 0: - { - while ( - (netbuf_len (firstNetBuf) - currentPos) - < base_message_rx.size) - { - ESP_LOGI (TAG, "need more data"); - - // we need more data to process - rc1 = netconn_recv (lwipNetconn, - &newNetBuf); - if (rc1 != ERR_OK) - { - ESP_LOGE ( - TAG, - "rx error for need more data"); - - if (rc1 == ERR_CONN) - { - // netconn_close(lwipNetconn); - // closing later, see first - // netconn_recv() in the loop - - break; - } - - if (newNetBuf != NULL) - { - netbuf_delete (newNetBuf); - - newNetBuf = NULL; - } - - continue; - } - - netbuf_chain (firstNetBuf, newNetBuf); - } - - if (rc1 == ERR_OK) - { - typedMsgLen = *start & 0xFF; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - } - else - { - ESP_LOGE (TAG, "some error"); - } - - break; - } - - case 1: - { - typedMsgLen |= (*start & 0xFF) << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 2: - { - typedMsgLen |= (*start & 0xFF) << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 3: - { - typedMsgLen |= (*start & 0xFF) << 24; - - // ESP_LOGI(TAG, - // "server settings string is %d long", - // typedMsgLen); - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 4: - { - // now get some memory for server settings - // string at this point there is still - // plenty of RAM available, so we use - // malloc and netbuf_copy() here - tmp = malloc (typedMsgLen + 1); - - if (tmp == NULL) - { - ESP_LOGE (TAG, - "couldn't get memory for " - "server settings string"); - } - else - { - netbuf_copy_partial (firstNetBuf, tmp, - typedMsgLen, - currentPos); - - tmp[typedMsgLen] - = 0; // NULL terminate string - - // ESP_LOGI - //(TAG, "got string: %s", tmp); - - result - = server_settings_message_deserialize ( - &server_settings_message, tmp); - if (result) - { - ESP_LOGE (TAG, - "Failed to read server " - "settings: %d", - result); - } - else - { - // log mute state, buffer, latency - ESP_LOGI (TAG, - "Buffer length: %d", - server_settings_message - .buffer_ms); - ESP_LOGI (TAG, - "Latency: %d", - server_settings_message - .latency); - ESP_LOGI ( - TAG, "Mute: %d", - server_settings_message.muted); - ESP_LOGI (TAG, - "Setting volume: %d", - server_settings_message - .volume); - } - - // Volume setting using ADF HAL - // abstraction - if (scSet.muted - != server_settings_message.muted) - { - audio_hal_set_mute ( - board_handle->audio_hal, - server_settings_message.muted); - } - if (scSet.volume - != server_settings_message.volume) - { - audio_hal_set_volume ( - board_handle->audio_hal, - server_settings_message - .volume); - } - - scSet.cDacLat_ms - = server_settings_message.latency; - scSet.buf_ms = server_settings_message - .buffer_ms; - scSet.muted - = server_settings_message.muted; - scSet.volume - = server_settings_message.volume; - - if (player_send_snapcast_setting ( - &scSet) - != pdPASS) - { - ESP_LOGE ( - TAG, - "Failed to notify sync task. " - "Did you init player?"); - - return; - } - - free (tmp); - tmp = NULL; - } - - internalState++; - - // currentPos++; - // len--; - // - // break; - - // intentional fall through - } - - case 5: - { - size_t tmpSize = base_message_rx.size - - typedMsgCurrentPos; - - if (len > 0) - { - if (tmpSize < len) - { - start += tmpSize; - currentPos - += tmpSize; // will be - // incremented by 1 - // later so -1 here - typedMsgCurrentPos += tmpSize; - len -= tmpSize; - } - else - { - start += len; - currentPos - += len; // will be incremented - // by 1 later so -1 - // here - typedMsgCurrentPos += len; - len = 0; - } - } - - if (typedMsgCurrentPos - >= base_message_rx.size) - { - // ESP_LOGI(TAG, - // "done server settings"); - - state = BASE_MESSAGE_STATE; - internalState = 0; - - typedMsgCurrentPos = 0; - } - - break; - } - - default: - { - ESP_LOGE (TAG, "server settings decoder " - "shouldn't get here"); - - break; - } - } - - break; - } - - case SNAPCAST_MESSAGE_STREAM_TAGS: - { - size_t tmpSize - = base_message_rx.size - typedMsgCurrentPos; - - if (tmpSize < len) - { - start += tmpSize; - currentPos += tmpSize; - typedMsgCurrentPos += tmpSize; - len -= tmpSize; - } - else - { - start += len; - currentPos += len; - - typedMsgCurrentPos += len; - len = 0; - } - - if (typedMsgCurrentPos >= base_message_rx.size) - { - // ESP_LOGI(TAG, - // "done stream tags with length %d %d %d", - // base_message_rx.size, currentPos, - // tmpSize); - - typedMsgCurrentPos = 0; - // currentPos = 0; - - state = BASE_MESSAGE_STATE; - internalState = 0; - } - - break; - } - - case SNAPCAST_MESSAGE_TIME: - { - switch (internalState) - { - case 0: - { - time_message_rx.latency.sec = *start; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 1: - { - time_message_rx.latency.sec - |= (int32_t)*start << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 2: - { - time_message_rx.latency.sec - |= (int32_t)*start << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 3: - { - time_message_rx.latency.sec - |= (int32_t)*start << 24; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 4: - { - time_message_rx.latency.usec = *start; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 5: - { - time_message_rx.latency.usec - |= (int32_t)*start << 8; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 6: - { - time_message_rx.latency.usec - |= (int32_t)*start << 16; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - internalState++; - - break; - } - - case 7: - { - time_message_rx.latency.usec - |= (int32_t)*start << 24; - - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - if (typedMsgCurrentPos - >= base_message_rx.size) - { - // ESP_LOGI(TAG, - // "done time message"); - - typedMsgCurrentPos = 0; - - state = BASE_MESSAGE_STATE; - internalState = 0; - - // ESP_LOGI(TAG, "BaseTX :" - // "%d %d ", base_message.sent.sec, - // base_message.sent.usec); - // ESP_LOGI(TAG, "BaseRX - // ": %d %d ", - // base_message.received.sec , - // base_message.received.usec); - // ESP_LOGI(TAG, "baseTX->RX : %d s ", - // (base_message.received.sec - // - - // base_message.sent.sec)); - // ESP_LOGI(TAG, - // "baseTX->RX : %d ms ", - // (base_message.received.usec - //- - // base_message.sent.usec)/1000); - // ESP_LOGI(TAG, - // "Latency : %d.%d ", - // time_message.latency.sec, - // time_message_rx.latency.usec/1000); - - // tv == server to client latency (s2c) - // time_message_rx.latency == client to - // server latency(c2s) - // TODO the fact that I have to do this - // simple conversion means I should - // probably use the timeval struct - // instead of my own - trx.tv_sec - = base_message_rx.received.sec; - trx.tv_usec - = base_message_rx.received.usec; - ttx.tv_sec = base_message_rx.sent.sec; - ttx.tv_usec - = base_message_rx.sent.usec; - timersub (&trx, &ttx, &tdif); - - trx.tv_sec - = time_message_rx.latency.sec; - trx.tv_usec - = time_message_rx.latency.usec; - - // trx == c2s: client to server - // tdif == s2c: server to client - // ESP_LOGI(TAG, - // "c2s: %ld %ld", - // trx.tv_sec, - // trx.tv_usec); - // ESP_LOGI(TAG, - // "s2c: %ld %ld", - // tdif.tv_sec, - // tdif.tv_usec); - - timersub (&trx, &tdif, - &tmpDiffToServer); - if ((tmpDiffToServer.tv_sec / 2) == 0) - { - tmpDiffToServer.tv_sec = 0; - tmpDiffToServer.tv_usec - = (suseconds_t) ( - (int64_t)tmpDiffToServer - .tv_sec - * 1000000LL / 2) - + (int64_t)tmpDiffToServer - .tv_usec - / 2; - } - else - { - tmpDiffToServer.tv_sec /= 2; - tmpDiffToServer.tv_usec /= 2; - } - - // ESP_LOGI(TAG, - // "Current - // latency: %ld.%06ld", - // tmpDiffToServer.tv_sec, - // tmpDiffToServer.tv_usec); - - // TODO: Move the time message sending - // to an own thread maybe following - // code is storing / initializing / - // resetting diff to server algorithm - // we collect a number of latencies and - // apply a median filter. Based on - // these we can get server now - { - struct timeval diff; - int64_t newValue; - - // clear diffBuffer if last update is - // older than a minute - timersub (&now, &lastTimeSync, - &diff); - - if (diff.tv_sec > 60) - { - ESP_LOGW ( - TAG, "Last time sync older " - "than a minute. " - "Clearing time buffer"); - - reset_latency_buffer (); - } - - newValue - = ((int64_t) - tmpDiffToServer.tv_sec - * 1000000LL - + (int64_t)tmpDiffToServer - .tv_usec); - player_latency_insert (newValue); - - // ESP_LOGE(TAG, - // "latency %lld", - // newValue); - - // store current time - lastTimeSync.tv_sec = now.tv_sec; - lastTimeSync.tv_usec = now.tv_usec; - - if (xSemaphoreTake ( - timeSyncSemaphoreHandle, 0) - == pdTRUE) - { - ESP_LOGW ( - TAG, - "couldn't take " - "timeSyncSemaphoreHandle"); - } - - uint64_t timeout; - if (latency_buffer_full () > 0) - { - // we give - // timeSyncSemaphoreHandle after - // x µs through timer - // TODO: maybe start a periodic - // timer here, but we need to - // remember if it is already - // running then. also we need to - // stop it if - // reset_latency_buffer() was - // called - timeout = 1000000; - } - else - { - // Do a initial time sync with - // the server at boot we need to - // fill diffBuff fast so we get a - // good estimate of latency - timeout = 100000; - } - - esp_timer_start_once ( - timeSyncMessageTimer, timeout); - } - } - else - { - ESP_LOGE (TAG, - "error time message, this " - "shouldn't happen! %d %d", - typedMsgCurrentPos, - base_message_rx.size); - - typedMsgCurrentPos = 0; - - state = BASE_MESSAGE_STATE; - internalState = 0; - } - - break; - } - - default: - { - ESP_LOGE (TAG, - "time message decoder shouldn't " - "get here %d %d %d", - typedMsgCurrentPos, - base_message_rx.size, - internalState); - - break; - } - } - - break; - } - - default: - { - typedMsgCurrentPos++; - start++; - currentPos++; - len--; - - if (typedMsgCurrentPos >= base_message_rx.size) - { - ESP_LOGI (TAG, - "done unknown typed message %d", - base_message_rx.type); - - state = BASE_MESSAGE_STATE; - internalState = 0; - - typedMsgCurrentPos = 0; - } - - break; - } - } - - break; - } - - default: - { - break; - } - } - - if (rc1 != ERR_OK) - { - break; - } - } - } - while (netbuf_next (firstNetBuf) >= 0); - - netbuf_delete (firstNetBuf); - - if (rc1 != ERR_OK) - { - ESP_LOGE (TAG, "Data error, closing netconn"); - - netconn_close (lwipNetconn); + case 1: + base_message_rx.type |= (*start & 0xFF) << 8; + internalState++; + break; + + case 2: + base_message_rx.id = *start & 0xFF; + internalState++; + break; + + case 3: + base_message_rx.id |= (*start & 0xFF) << 8; + internalState++; + break; + + case 4: + base_message_rx.refersTo = *start & 0xFF; + internalState++; + break; + + case 5: + base_message_rx.refersTo |= (*start & 0xFF) << 8; + internalState++; + break; + + case 6: + base_message_rx.sent.sec = *start & 0xFF; + internalState++; + break; + + case 7: + base_message_rx.sent.sec |= (*start & 0xFF) << 8; + internalState++; + break; + + case 8: + base_message_rx.sent.sec |= (*start & 0xFF) << 16; + internalState++; + break; + + case 9: + base_message_rx.sent.sec |= (*start & 0xFF) << 24; + internalState++; + break; + + case 10: + base_message_rx.sent.usec = *start & 0xFF; + internalState++; + break; + + case 11: + base_message_rx.sent.usec |= (*start & 0xFF) << 8; + internalState++; + break; + + case 12: + base_message_rx.sent.usec |= (*start & 0xFF) << 16; + internalState++; + break; + + case 13: + base_message_rx.sent.usec |= (*start & 0xFF) << 24; + internalState++; + break; + + case 14: + base_message_rx.received.sec = *start & 0xFF; + internalState++; + break; + + case 15: + base_message_rx.received.sec |= (*start & 0xFF) << 8; + internalState++; + break; + + case 16: + base_message_rx.received.sec |= (*start & 0xFF) << 16; + internalState++; + break; + + case 17: + base_message_rx.received.sec |= (*start & 0xFF) << 24; + internalState++; + break; + + case 18: + base_message_rx.received.usec = *start & 0xFF; + internalState++; + break; + + case 19: + base_message_rx.received.usec |= (*start & 0xFF) << 8; + internalState++; + break; + + case 20: + base_message_rx.received.usec |= (*start & 0xFF) << 16; + internalState++; + break; + + case 21: + base_message_rx.received.usec |= (*start & 0xFF) << 24; + internalState++; + break; + + case 22: + base_message_rx.size = *start & 0xFF; + internalState++; + break; + + case 23: + base_message_rx.size |= (*start & 0xFF) << 8; + internalState++; + break; + + case 24: + base_message_rx.size |= (*start & 0xFF) << 16; + internalState++; + break; + + case 25: + base_message_rx.size |= (*start & 0xFF) << 24; + internalState = 0; + + base_message_rx.received.sec = now.tv_sec; + base_message_rx.received.usec = now.tv_usec; + + typedMsgCurrentPos = 0; + + // ESP_LOGI(TAG,"BM type %d ts %d.%d", + // base_message_rx.type, + // base_message_rx.received.sec, + // base_message_rx.received.usec); + // ESP_LOGI(TAG,"%d + //%d.%d", base_message_rx.type, + // base_message_rx.received.sec, + // base_message_rx.received.usec); + + state = TYPED_MESSAGE_STATE; + break; + } + + currentPos++; + len--; + start++; break; } - if (received_header == true) - { - if (xSemaphoreTake (timeSyncSemaphoreHandle, 0) == pdTRUE) - { - result = gettimeofday (&now, NULL); - // ESP_LOGI(TAG, "time of day: %ld %ld", now.tv_sec, - // now.tv_usec); - if (result) - { - ESP_LOGI (TAG, "Failed to gettimeofday"); - continue; + // decode typed message + case TYPED_MESSAGE_STATE: { + switch (base_message_rx.type) { + case SNAPCAST_MESSAGE_WIRE_CHUNK: { + switch (internalState) { + case 0: { + wire_chnk.timestamp.sec = *start & 0xFF; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; } - base_message_tx.type = SNAPCAST_MESSAGE_TIME; - base_message_tx.id = id_counter++; - base_message_tx.refersTo = 0; - base_message_tx.received.sec = 0; - base_message_tx.received.usec = 0; - base_message_tx.sent.sec = now.tv_sec; - base_message_tx.sent.usec = now.tv_usec; - base_message_tx.size = TIME_MESSAGE_SIZE; + case 1: { + wire_chnk.timestamp.sec |= (*start & 0xFF) << 8; - result = base_message_serialize (&base_message_tx, - base_message_serialized, - BASE_MESSAGE_SIZE); - if (result) - { - ESP_LOGE (TAG, - "Failed to serialize base message for time"); - continue; + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; } - memset (&time_message_tx, 0, sizeof (time_message_tx)); + case 2: { + wire_chnk.timestamp.sec |= (*start & 0xFF) << 16; - result = time_message_serialize (&time_message_tx, - time_message_serialized, - TIME_MESSAGE_SIZE); - if (result) - { - ESP_LOGI (TAG, "Failed to serialize time message"); - continue; + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; } - rc1 = netconn_write (lwipNetconn, base_message_serialized, - BASE_MESSAGE_SIZE, NETCONN_NOCOPY); - if (rc1 != ERR_OK) - { - ESP_LOGW (TAG, "error writing timesync base msg"); + case 3: { + wire_chnk.timestamp.sec |= (*start & 0xFF) << 24; - continue; + // ESP_LOGI(TAG, + // "wire chunk time sec: %d", + // wire_chnk.timestamp.sec); + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; } - rc1 = netconn_write (lwipNetconn, time_message_serialized, - TIME_MESSAGE_SIZE, NETCONN_NOCOPY); - if (rc1 != ERR_OK) - { - ESP_LOGW (TAG, "error writing timesync msg"); + case 4: { + wire_chnk.timestamp.usec = (*start & 0xFF); - continue; + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; } + + case 5: { + wire_chnk.timestamp.usec |= (*start & 0xFF) << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 6: { + wire_chnk.timestamp.usec |= (*start & 0xFF) << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 7: { + wire_chnk.timestamp.usec |= (*start & 0xFF) << 24; + + // ESP_LOGI(TAG, + // "wire chunk time usec: %d", + // wire_chnk.timestamp.usec); + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 8: { + wire_chnk.size = (*start & 0xFF); + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 9: { + wire_chnk.size |= (*start & 0xFF) << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 10: { + wire_chnk.size |= (*start & 0xFF) << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 11: { + wire_chnk.size |= (*start & 0xFF) << 24; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + // ESP_LOGI(TAG, + // "got wire chunk with size: %d, at time" + // " %d.%d", wire_chnk.size, + // wire_chnk.timestamp.sec, + // wire_chnk.timestamp.usec); + + break; + } + + case 12: { + size_t tmp; + + if ((base_message_rx.size - typedMsgCurrentPos) <= len) { + tmp = base_message_rx.size - typedMsgCurrentPos; + } else { + tmp = len; + } + + if (received_header == true) { + switch (codec) { + case FLAC: { + flacData.bytes = tmp; + flacData.inData = start; + pFlacData = &flacData; + + xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); + + // send data to flac decoder + xQueueSend(decoderReadQHdl, &pFlacData, + portMAX_DELAY); + // and wait until data was + // processed + xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); + // need to release mutex + // afterwards for next round + xSemaphoreGive(decoderReadSemaphore); + + break; + } + + case PCM: { + if (pcmData == NULL) { + if (allocate_pcm_chunk_memory( + &pcmData, wire_chnk.size) < 0) { + pcmData = NULL; + } + + offset = 0; + remainderSize = 0; + cntTmp = 0; + } + + if (pcmData != NULL) { + uint32_t *sample; + + int max = 0, begin = 0; + + while (remainderSize) { + tmpData |= ((uint32_t)start[begin++] + << (8 * (remainderSize - 1))); + + remainderSize--; + if (remainderSize < 0) { + ESP_LOGE(TAG, + "shift < 0 this " + "shouldn't " + "happen"); + + return; + } + } + + // check if we need to write + // a remaining sample + if (begin > 0) { + // need to reorder bytes + // in sample for correct + // playback + uint8_t dummy1; + uint32_t dummy2 = 0; + + // TODO: find a more + // clever way to do this, + // best would be to + // actually store it the + // right way in the first + // place + dummy1 = tmpData >> 24; + dummy2 |= (uint32_t)dummy1 << 16; + dummy1 = tmpData >> 16; + dummy2 |= (uint32_t)dummy1 << 24; + dummy1 = tmpData >> 8; + dummy2 |= (uint32_t)dummy1 << 0; + dummy1 = tmpData >> 0; + dummy2 |= (uint32_t)dummy1 << 8; + tmpData = dummy2; + + sample = (uint32_t *)(&( + pcmData->fragment->payload[offset])); + *sample = tmpData; + + offset += 4; + } + + remainderSize = (tmp - begin) % 4; + max = (tmp - begin) - remainderSize; + + for (int i = begin; i < max; i += 4) { + // TODO: for now + // fragmented payload is + // not supported and the + // whole chunk is + // expected to be in the + // first fragment + tmpData = ((uint32_t)start[i] << 16) | + ((uint32_t)start[i + 1] << 24) | + ((uint32_t)start[i + 2] << 0) | + ((uint32_t)start[i + 3] << 8); + + // ensure 32bit alligned + // write + sample = (uint32_t *)(&( + pcmData->fragment->payload[offset])); + *sample = tmpData; + + offset += 4; + } + + tmpData = 0; + while (remainderSize) { + tmpData |= ((uint32_t)start[max++] + << (8 * (remainderSize - 1))); + + remainderSize--; + + if (remainderSize < 0) { + ESP_LOGE(TAG, + "shift < 0 this " + "shouldn't " + "happen"); + + return; + } + } + + remainderSize = (tmp - begin) % 4; + if (remainderSize) { + remainderSize = + 4 - remainderSize; // these are the still + // needed bytes for next + // round + tmpData <<= + (8 * remainderSize); // shift data to + // correct position + } + } + + break; + } + + default: { + ESP_LOGE(TAG, "Decoder (1) not supported"); + + return; + + break; + } + } + } + + typedMsgCurrentPos += tmp; + start += tmp; + currentPos += tmp; + len -= tmp; + + if (typedMsgCurrentPos >= base_message_rx.size) { + // ESP_LOGI(TAG, + //"data remaining %d %d", len, + // currentPos); + // ESP_LOGI(TAG, "got wire chunk with + // size: %d, at time %d.%d", + // wire_chnk.size, + // wire_chnk.timestamp.sec, + // wire_chnk.timestamp.usec); + + if (received_header == true) { + switch (codec) { + case FLAC: { + xSemaphoreGive(decoderWriteSemaphore); + // and wait until it is done + xQueueReceive(decoderWriteQHdl, &pFlacData, + portMAX_DELAY); + + if (pFlacData->outData != NULL) { + pcmData = pFlacData->outData; + pcmData->timestamp = wire_chnk.timestamp; + + size_t decodedSize = + pcmData->totalSize; // pFlacData->bytes; + scSet.chkDur_ms = + (1000UL * decodedSize) / + (uint32_t)(scSet.ch * (scSet.bits / 8)) / + scSet.sr; + if (player_send_snapcast_setting(&scSet) != + pdPASS) { + ESP_LOGE(TAG, + "Failed to " + "notify " + "sync task " + "about " + "codec. Did you " + "init player?"); + + return; + } + +#if CONFIG_USE_DSP_PROCESSOR + dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_processor(pcm_chunk_message.payload, + pcm_chunk_message.size, dspFlow); +#endif + + insert_pcm_chunk(pcmData); + pcmData = NULL; + } + + break; + } + + case PCM: { + size_t decodedSize = pcmData->fragment->size; + + pcmData->timestamp = wire_chnk.timestamp; + + scSet.chkDur_ms = + (1000UL * decodedSize) / + (uint32_t)(scSet.ch * (scSet.bits / 8)) / + scSet.sr; + if (player_send_snapcast_setting(&scSet) != + pdPASS) { + ESP_LOGE(TAG, + "Failed to notify " + "sync task about " + "codec. Did you " + "init player?"); + + return; + } + +#if CONFIG_USE_DSP_PROCESSOR + dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_processor(pcm_chunk_message.payload, + pcm_chunk_message.size, dspFlow); +#endif + + insert_pcm_chunk(pcmData); + pcmData = NULL; + break; + } + + default: { + ESP_LOGE(TAG, + "Decoder (2) not " + "supported"); + + return; + + break; + } + } + } + + state = BASE_MESSAGE_STATE; + internalState = 0; + + typedMsgCurrentPos = 0; + } + + break; + } + + default: { + ESP_LOGE(TAG, + "wire chunk decoder " + "shouldn't get here"); + + break; + } + } + + break; } + + case SNAPCAST_MESSAGE_CODEC_HEADER: { + switch (internalState) { + case 0: { + typedMsgLen = *start & 0xFF; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 1: { + typedMsgLen |= (*start & 0xFF) << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 2: { + typedMsgLen |= (*start & 0xFF) << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 3: { + typedMsgLen |= (*start & 0xFF) << 24; + + tmp = malloc(typedMsgLen + 1); // allocate memory for + // codec string + if (tmp == NULL) { + ESP_LOGE(TAG, + "couldn't get memory " + "for codec string"); + + return; + } + + offset = 0; + // ESP_LOGI(TAG, + // "codec header string is %d long", + // typedMsgLen); + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 4: { + if (len >= typedMsgLen) { + memcpy(&tmp[offset], start, typedMsgLen); + + offset += typedMsgLen; + + typedMsgCurrentPos += typedMsgLen; + start += typedMsgLen; + currentPos += typedMsgLen; + len -= typedMsgLen; + } else { + memcpy(&tmp[offset], start, typedMsgLen); + + offset += len; + + typedMsgCurrentPos += len; + start += len; + currentPos += len; + len -= len; + } + + if (offset == typedMsgLen) { + // NULL terminate string + tmp[typedMsgLen] = 0; + + // ESP_LOGI + // (TAG, "got codec string: %s", tmp); + + if (strcmp(tmp, "opus") == 0) { + codec = OPUS; + } else if (strcmp(tmp, "flac") == 0) { + codec = FLAC; + } else if (strcmp(tmp, "pcm") == 0) { + codec = PCM; + } else { + codec = NONE; + + ESP_LOGI(TAG, "Codec : %s not supported", tmp); + ESP_LOGI(TAG, + "Change encoder codec to " + "opus, flac or pcm in " + "/etc/snapserver.conf on " + "server"); + + return; + } + + free(tmp); + tmp = NULL; + + internalState++; + } + + break; + } + + case 5: { + typedMsgLen = *start & 0xFF; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 6: { + typedMsgLen |= (*start & 0xFF) << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 7: { + typedMsgLen |= (*start & 0xFF) << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 8: { + typedMsgLen |= (*start & 0xFF) << 24; + + tmp = malloc(typedMsgLen); // allocate memory for + // codec string + if (tmp == NULL) { + ESP_LOGE(TAG, + "couldn't get memory " + "for codec string"); + + return; + } + + offset = 0; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 9: { + if (len >= typedMsgLen) { + memcpy(&tmp[offset], start, typedMsgLen); + + offset += typedMsgLen; + + typedMsgCurrentPos += typedMsgLen; + start += typedMsgLen; + currentPos += typedMsgLen; + len -= typedMsgLen; + } else { + memcpy(&tmp[offset], start, typedMsgLen); + + offset += len; + + typedMsgCurrentPos += len; + start += len; + currentPos += len; + len -= len; + } + + if (offset == typedMsgLen) { + // first ensure everything is set up + // correctly and resources are + // available + if (t_flac_decoder_task != NULL) { + vTaskDelete(t_flac_decoder_task); + t_flac_decoder_task = NULL; + } + + if (flacDecoder != NULL) { + FLAC__stream_decoder_finish(flacDecoder); + FLAC__stream_decoder_delete(flacDecoder); + flacDecoder = NULL; + } + + if (decoderWriteQHdl != NULL) { + vQueueDelete(decoderWriteQHdl); + decoderWriteQHdl = NULL; + } + + if (decoderReadQHdl != NULL) { + vQueueDelete(decoderReadQHdl); + decoderReadQHdl = NULL; + } + + if (codec == OPUS) { + ESP_LOGI(TAG, "OPUS not implemented yet"); + + return; + } else if (codec == FLAC) { + if (t_flac_decoder_task == NULL) { + xTaskCreatePinnedToCore( + &flac_decoder_task, "flac_decoder_task", + 9 * 256, &scSet, FLAC_TASK_PRIORITY, + &t_flac_decoder_task, FLAC_TASK_CORE_ID); + } + + if (flacData.outData != NULL) { + free(flacData.outData); + flacData.outData = NULL; + } + + flacData.bytes = typedMsgLen; + flacData.inData = tmp; + pFlacData = &flacData; + + // TODO: find a smarter way for + // this wait for task creation done + while (decoderReadQHdl == NULL) { + vTaskDelay(10); + } + + xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); + + // send data to flac decoder + xQueueSend(decoderReadQHdl, &pFlacData, + portMAX_DELAY); + // and wait until data was + // processed + xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); + // need to release mutex afterwards + // for next round + xSemaphoreGive(decoderReadSemaphore); + // wait until it is done + xQueueReceive(decoderWriteQHdl, &pFlacData, + portMAX_DELAY); + + ESP_LOGI(TAG, "fLaC sampleformat: %d:%d:%d", scSet.sr, + scSet.bits, scSet.ch); + } else if (codec == PCM) { + memcpy(&channels, tmp + 22, sizeof(channels)); + uint32_t rate; + memcpy(&rate, tmp + 24, sizeof(rate)); + uint16_t bits; + memcpy(&bits, tmp + 34, sizeof(bits)); + + scSet.codec = codec; + scSet.bits = bits; + scSet.ch = channels; + scSet.sr = rate; + + ESP_LOGI(TAG, "pcm sampleformat: %d:%d:%d", scSet.sr, + scSet.bits, scSet.ch); + } else { + ESP_LOGE(TAG, + "codec header decoder " + "shouldn't get here after " + "codec string was detected"); + + return; + } + + free(tmp); + tmp = NULL; + + // ESP_LOGI(TAG, + //"done codec header msg"); + + trx.tv_sec = base_message_rx.sent.sec; + trx.tv_usec = base_message_rx.sent.usec; + // we do this, so uint32_t timvals + // won't overflow if e.g. raspberry + // server is off to far + settimeofday(&trx, NULL); + ESP_LOGI(TAG, + "syncing clock to server " + "%ld.%06ld", + trx.tv_sec, trx.tv_usec); + + state = BASE_MESSAGE_STATE; + internalState = 0; + + received_header = true; + } + + break; + } + + default: { + ESP_LOGE(TAG, + "codec header decoder " + "shouldn't get here"); + + break; + } + } + + break; + } + + case SNAPCAST_MESSAGE_SERVER_SETTINGS: { + switch (internalState) { + case 0: { + while ((netbuf_len(firstNetBuf) - currentPos) < + base_message_rx.size) { + ESP_LOGI(TAG, "need more data"); + + // we need more data to process + rc1 = netconn_recv(lwipNetconn, &newNetBuf); + if (rc1 != ERR_OK) { + ESP_LOGE(TAG, "rx error for need more data"); + + if (rc1 == ERR_CONN) { + // netconn_close(lwipNetconn); + // closing later, see first + // netconn_recv() in the loop + + break; + } + + if (newNetBuf != NULL) { + netbuf_delete(newNetBuf); + + newNetBuf = NULL; + } + + continue; + } + + netbuf_chain(firstNetBuf, newNetBuf); + } + + if (rc1 == ERR_OK) { + typedMsgLen = *start & 0xFF; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + } else { + ESP_LOGE(TAG, "some error"); + } + + break; + } + + case 1: { + typedMsgLen |= (*start & 0xFF) << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 2: { + typedMsgLen |= (*start & 0xFF) << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 3: { + typedMsgLen |= (*start & 0xFF) << 24; + + // ESP_LOGI(TAG, + // "server settings string is %d long", + // typedMsgLen); + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 4: { + // now get some memory for server settings + // string at this point there is still + // plenty of RAM available, so we use + // malloc and netbuf_copy() here + tmp = malloc(typedMsgLen + 1); + + if (tmp == NULL) { + ESP_LOGE(TAG, + "couldn't get memory for " + "server settings string"); + } else { + netbuf_copy_partial(firstNetBuf, tmp, typedMsgLen, + currentPos); + + tmp[typedMsgLen] = 0; // NULL terminate string + + // ESP_LOGI + //(TAG, "got string: %s", tmp); + + result = server_settings_message_deserialize( + &server_settings_message, tmp); + if (result) { + ESP_LOGE(TAG, + "Failed to read server " + "settings: %d", + result); + } else { + // log mute state, buffer, latency + ESP_LOGI(TAG, "Buffer length: %d", + server_settings_message.buffer_ms); + ESP_LOGI(TAG, "Latency: %d", + server_settings_message.latency); + ESP_LOGI(TAG, "Mute: %d", + server_settings_message.muted); + ESP_LOGI(TAG, "Setting volume: %d", + server_settings_message.volume); + } + + // Volume setting using ADF HAL + // abstraction + if (scSet.muted != server_settings_message.muted) { + audio_hal_set_mute(board_handle->audio_hal, + server_settings_message.muted); + } + if (scSet.volume != server_settings_message.volume) { + audio_hal_set_volume(board_handle->audio_hal, + server_settings_message.volume); + } + + scSet.cDacLat_ms = server_settings_message.latency; + scSet.buf_ms = server_settings_message.buffer_ms; + scSet.muted = server_settings_message.muted; + scSet.volume = server_settings_message.volume; + + if (player_send_snapcast_setting(&scSet) != pdPASS) { + ESP_LOGE(TAG, + "Failed to notify sync task. " + "Did you init player?"); + + return; + } + + free(tmp); + tmp = NULL; + } + + internalState++; + + // currentPos++; + // len--; + // + // break; + + // intentional fall through + } + + case 5: { + size_t tmpSize = + base_message_rx.size - typedMsgCurrentPos; + + if (len > 0) { + if (tmpSize < len) { + start += tmpSize; + currentPos += tmpSize; // will be + // incremented by 1 + // later so -1 here + typedMsgCurrentPos += tmpSize; + len -= tmpSize; + } else { + start += len; + currentPos += len; // will be incremented + // by 1 later so -1 + // here + typedMsgCurrentPos += len; + len = 0; + } + } + + if (typedMsgCurrentPos >= base_message_rx.size) { + // ESP_LOGI(TAG, + // "done server settings"); + + state = BASE_MESSAGE_STATE; + internalState = 0; + + typedMsgCurrentPos = 0; + } + + break; + } + + default: { + ESP_LOGE(TAG, + "server settings decoder " + "shouldn't get here"); + + break; + } + } + + break; + } + + case SNAPCAST_MESSAGE_STREAM_TAGS: { + size_t tmpSize = base_message_rx.size - typedMsgCurrentPos; + + if (tmpSize < len) { + start += tmpSize; + currentPos += tmpSize; + typedMsgCurrentPos += tmpSize; + len -= tmpSize; + } else { + start += len; + currentPos += len; + + typedMsgCurrentPos += len; + len = 0; + } + + if (typedMsgCurrentPos >= base_message_rx.size) { + // ESP_LOGI(TAG, + // "done stream tags with length %d %d %d", + // base_message_rx.size, currentPos, + // tmpSize); + + typedMsgCurrentPos = 0; + // currentPos = 0; + + state = BASE_MESSAGE_STATE; + internalState = 0; + } + + break; + } + + case SNAPCAST_MESSAGE_TIME: { + switch (internalState) { + case 0: { + time_message_rx.latency.sec = *start; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 1: { + time_message_rx.latency.sec |= (int32_t)*start << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 2: { + time_message_rx.latency.sec |= (int32_t)*start << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 3: { + time_message_rx.latency.sec |= (int32_t)*start << 24; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 4: { + time_message_rx.latency.usec = *start; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 5: { + time_message_rx.latency.usec |= (int32_t)*start << 8; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 6: { + time_message_rx.latency.usec |= (int32_t)*start << 16; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + internalState++; + + break; + } + + case 7: { + time_message_rx.latency.usec |= (int32_t)*start << 24; + + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + if (typedMsgCurrentPos >= base_message_rx.size) { + // ESP_LOGI(TAG, + // "done time message"); + + typedMsgCurrentPos = 0; + + state = BASE_MESSAGE_STATE; + internalState = 0; + + // ESP_LOGI(TAG, "BaseTX :" + // "%d %d ", base_message.sent.sec, + // base_message.sent.usec); + // ESP_LOGI(TAG, "BaseRX + // ": %d %d ", + // base_message.received.sec , + // base_message.received.usec); + // ESP_LOGI(TAG, "baseTX->RX : %d s ", + // (base_message.received.sec + // - + // base_message.sent.sec)); + // ESP_LOGI(TAG, + // "baseTX->RX : %d ms ", + // (base_message.received.usec + //- + // base_message.sent.usec)/1000); + // ESP_LOGI(TAG, + // "Latency : %d.%d ", + // time_message.latency.sec, + // time_message_rx.latency.usec/1000); + + // tv == server to client latency (s2c) + // time_message_rx.latency == client to + // server latency(c2s) + // TODO the fact that I have to do this + // simple conversion means I should + // probably use the timeval struct + // instead of my own + trx.tv_sec = base_message_rx.received.sec; + trx.tv_usec = base_message_rx.received.usec; + ttx.tv_sec = base_message_rx.sent.sec; + ttx.tv_usec = base_message_rx.sent.usec; + timersub(&trx, &ttx, &tdif); + + trx.tv_sec = time_message_rx.latency.sec; + trx.tv_usec = time_message_rx.latency.usec; + + // trx == c2s: client to server + // tdif == s2c: server to client + // ESP_LOGI(TAG, + // "c2s: %ld %ld", + // trx.tv_sec, + // trx.tv_usec); + // ESP_LOGI(TAG, + // "s2c: %ld %ld", + // tdif.tv_sec, + // tdif.tv_usec); + + timersub(&trx, &tdif, &tmpDiffToServer); + if ((tmpDiffToServer.tv_sec / 2) == 0) { + tmpDiffToServer.tv_sec = 0; + tmpDiffToServer.tv_usec = + (suseconds_t)((int64_t)tmpDiffToServer.tv_sec * + 1000000LL / 2) + + (int64_t)tmpDiffToServer.tv_usec / 2; + } else { + tmpDiffToServer.tv_sec /= 2; + tmpDiffToServer.tv_usec /= 2; + } + + // ESP_LOGI(TAG, + // "Current + // latency: %ld.%06ld", + // tmpDiffToServer.tv_sec, + // tmpDiffToServer.tv_usec); + + // TODO: Move the time message sending + // to an own thread maybe following + // code is storing / initializing / + // resetting diff to server algorithm + // we collect a number of latencies and + // apply a median filter. Based on + // these we can get server now + { + struct timeval diff; + int64_t newValue; + + // clear diffBuffer if last update is + // older than a minute + timersub(&now, &lastTimeSync, &diff); + + if (diff.tv_sec > 60) { + ESP_LOGW(TAG, + "Last time sync older " + "than a minute. " + "Clearing time buffer"); + + reset_latency_buffer(); + } + + newValue = + ((int64_t)tmpDiffToServer.tv_sec * 1000000LL + + (int64_t)tmpDiffToServer.tv_usec); + player_latency_insert(newValue); + + // ESP_LOGE(TAG, + // "latency %lld", + // newValue); + + // store current time + lastTimeSync.tv_sec = now.tv_sec; + lastTimeSync.tv_usec = now.tv_usec; + + if (xSemaphoreTake(timeSyncSemaphoreHandle, 0) == + pdTRUE) { + ESP_LOGW(TAG, + "couldn't take " + "timeSyncSemaphoreHandle"); + } + + uint64_t timeout; + if (latency_buffer_full() > 0) { + // we give + // timeSyncSemaphoreHandle after + // x µs through timer + // TODO: maybe start a periodic + // timer here, but we need to + // remember if it is already + // running then. also we need to + // stop it if + // reset_latency_buffer() was + // called + timeout = 1000000; + } else { + // Do a initial time sync with + // the server at boot we need to + // fill diffBuff fast so we get a + // good estimate of latency + timeout = 100000; + } + + esp_timer_start_once(timeSyncMessageTimer, timeout); + } + } else { + ESP_LOGE(TAG, + "error time message, this " + "shouldn't happen! %d %d", + typedMsgCurrentPos, base_message_rx.size); + + typedMsgCurrentPos = 0; + + state = BASE_MESSAGE_STATE; + internalState = 0; + } + + break; + } + + default: { + ESP_LOGE(TAG, + "time message decoder shouldn't " + "get here %d %d %d", + typedMsgCurrentPos, base_message_rx.size, + internalState); + + break; + } + } + + break; + } + + default: { + typedMsgCurrentPos++; + start++; + currentPos++; + len--; + + if (typedMsgCurrentPos >= base_message_rx.size) { + ESP_LOGI(TAG, "done unknown typed message %d", + base_message_rx.type); + + state = BASE_MESSAGE_STATE; + internalState = 0; + + typedMsgCurrentPos = 0; + } + + break; + } + } + + break; } + + default: { break; } + } + + if (rc1 != ERR_OK) { + break; + } } + } while (netbuf_next(firstNetBuf) >= 0); + + netbuf_delete(firstNetBuf); + + if (rc1 != ERR_OK) { + ESP_LOGE(TAG, "Data error, closing netconn"); + + netconn_close(lwipNetconn); + + break; + } + + if (received_header == true) { + if (xSemaphoreTake(timeSyncSemaphoreHandle, 0) == pdTRUE) { + result = gettimeofday(&now, NULL); + // ESP_LOGI(TAG, "time of day: %ld %ld", now.tv_sec, + // now.tv_usec); + if (result) { + ESP_LOGI(TAG, "Failed to gettimeofday"); + continue; + } + + base_message_tx.type = SNAPCAST_MESSAGE_TIME; + base_message_tx.id = id_counter++; + base_message_tx.refersTo = 0; + base_message_tx.received.sec = 0; + base_message_tx.received.usec = 0; + base_message_tx.sent.sec = now.tv_sec; + base_message_tx.sent.usec = now.tv_usec; + base_message_tx.size = TIME_MESSAGE_SIZE; + + result = base_message_serialize( + &base_message_tx, base_message_serialized, BASE_MESSAGE_SIZE); + if (result) { + ESP_LOGE(TAG, "Failed to serialize base message for time"); + continue; + } + + memset(&time_message_tx, 0, sizeof(time_message_tx)); + + result = time_message_serialize( + &time_message_tx, time_message_serialized, TIME_MESSAGE_SIZE); + if (result) { + ESP_LOGI(TAG, "Failed to serialize time message"); + continue; + } + + rc1 = netconn_write(lwipNetconn, base_message_serialized, + BASE_MESSAGE_SIZE, NETCONN_NOCOPY); + if (rc1 != ERR_OK) { + ESP_LOGW(TAG, "error writing timesync base msg"); + + continue; + } + + rc1 = netconn_write(lwipNetconn, time_message_serialized, + TIME_MESSAGE_SIZE, NETCONN_NOCOPY); + if (rc1 != ERR_OK) { + ESP_LOGW(TAG, "error writing timesync msg"); + + continue; + } + } + } } + } } /** * */ -static void -http_get_task_backup (void *pvParameters) -{ +static void http_get_task_backup(void *pvParameters) { struct sockaddr_in servaddr; char *start; int sock = -1; @@ -2697,9 +2282,9 @@ http_get_task_backup (void *pvParameters) struct timeval now, trx, tdif, ttx; time_message_t time_message; struct timeval tmpDiffToServer; - struct timeval lastTimeSync = { 0, 0 }; + struct timeval lastTimeSync = {0, 0}; esp_timer_handle_t timeSyncMessageTimer = NULL; - int16_t frameSize = 960; // 960*2: 20ms, 960*1: 10ms + int16_t frameSize = 960; // 960*2: 20ms, 960*1: 10ms int16_t *audio = NULL; int16_t pcm_size = 120; uint16_t channels; @@ -2711,1190 +2296,1035 @@ http_get_task_backup (void *pvParameters) OpusDecoder *opusDecoder = NULL; codec_type_t codec = NONE; snapcastSetting_t scSet; - flacData_t flacData = { NULL, NULL, 0 }; + flacData_t flacData = {NULL, NULL, 0}; flacData_t *pFlacData; char *typedMsg = NULL; uint32_t lastTypedMsgSize = 0; // create a timer to send time sync messages every x µs - esp_timer_create (&tSyncArgs, &timeSyncMessageTimer); - timeSyncSemaphoreHandle = xSemaphoreCreateMutex (); - xSemaphoreGive (timeSyncSemaphoreHandle); + esp_timer_create(&tSyncArgs, &timeSyncMessageTimer); + timeSyncSemaphoreHandle = xSemaphoreCreateMutex(); + xSemaphoreGive(timeSyncSemaphoreHandle); id_counter = 0; - while (1) - { - if (reset_latency_buffer () < 0) - { - ESP_LOGE ( - TAG, - "reset_diff_buffer: couldn't reset median filter long. STOP"); + while (1) { + if (reset_latency_buffer() < 0) { + ESP_LOGE(TAG, + "reset_diff_buffer: couldn't reset median filter long. STOP"); - return; - } + return; + } - esp_timer_stop (timeSyncMessageTimer); - xSemaphoreGive (timeSyncSemaphoreHandle); + esp_timer_stop(timeSyncMessageTimer); + xSemaphoreGive(timeSyncSemaphoreHandle); - if (opusDecoder != NULL) - { - opus_decoder_destroy (opusDecoder); - opusDecoder = NULL; - } + if (opusDecoder != NULL) { + opus_decoder_destroy(opusDecoder); + opusDecoder = NULL; + } - if (t_flac_decoder_task != NULL) - { - vTaskDelete (t_flac_decoder_task); - t_flac_decoder_task = NULL; - } + if (t_flac_decoder_task != NULL) { + vTaskDelete(t_flac_decoder_task); + t_flac_decoder_task = NULL; + } - if (flacDecoder != NULL) - { - FLAC__stream_decoder_finish (flacDecoder); - FLAC__stream_decoder_delete (flacDecoder); - flacDecoder = NULL; - } + if (flacDecoder != NULL) { + FLAC__stream_decoder_finish(flacDecoder); + FLAC__stream_decoder_delete(flacDecoder); + flacDecoder = NULL; + } - if (decoderWriteQHdl != NULL) - { - vQueueDelete (decoderWriteQHdl); - decoderWriteQHdl = NULL; - } + if (decoderWriteQHdl != NULL) { + vQueueDelete(decoderWriteQHdl); + decoderWriteQHdl = NULL; + } - if (decoderReadQHdl != NULL) - { - vQueueDelete (decoderReadQHdl); - decoderReadQHdl = NULL; - } + if (decoderReadQHdl != NULL) { + vQueueDelete(decoderReadQHdl); + decoderReadQHdl = NULL; + } #if SNAPCAST_SERVER_USE_MDNS - // Find snapcast server - // Connect to first snapcast server found - r = NULL; - err = 0; - while (!r || err) - { - ESP_LOGI (TAG, "Lookup snapcast service on network"); - esp_err_t err = mdns_query_ptr ("_snapcast", "_tcp", 3000, 20, &r); - if (err) - { - ESP_LOGE (TAG, "Query Failed"); - } + // Find snapcast server + // Connect to first snapcast server found + r = NULL; + err = 0; + while (!r || err) { + ESP_LOGI(TAG, "Lookup snapcast service on network"); + esp_err_t err = mdns_query_ptr("_snapcast", "_tcp", 3000, 20, &r); + if (err) { + ESP_LOGE(TAG, "Query Failed"); + } - if (!r) - { - ESP_LOGW (TAG, "No results found!"); - } + if (!r) { + ESP_LOGW(TAG, "No results found!"); + } - vTaskDelay (1000 / portTICK_PERIOD_MS); - } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } - char serverAddr[] = "255.255.255.255"; - ESP_LOGI (TAG, "Found %s:%d", - inet_ntop (AF_INET, &(r->addr->addr.u_addr.ip4.addr), - serverAddr, sizeof (serverAddr)), - r->port); + char serverAddr[] = "255.255.255.255"; + ESP_LOGI(TAG, "Found %s:%d", + inet_ntop(AF_INET, &(r->addr->addr.u_addr.ip4.addr), serverAddr, + sizeof(serverAddr)), + r->port); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = r->addr->addr.u_addr.ip4.addr; - servaddr.sin_port = htons (r->port); - mdns_query_results_free (r); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = r->addr->addr.u_addr.ip4.addr; + servaddr.sin_port = htons(r->port); + mdns_query_results_free(r); #else - // configure a failsafe snapserver according to CONFIG values - servaddr.sin_family = AF_INET; - inet_pton (AF_INET, SNAPCAST_SERVER_HOST, &(servaddr.sin_addr.s_addr)); - servaddr.sin_port = htons (SNAPCAST_SERVER_PORT); + // configure a failsafe snapserver according to CONFIG values + servaddr.sin_family = AF_INET; + inet_pton(AF_INET, SNAPCAST_SERVER_HOST, &(servaddr.sin_addr.s_addr)); + servaddr.sin_port = htons(SNAPCAST_SERVER_PORT); #endif - ESP_LOGI (TAG, "allocate socket"); - sock = socket (AF_INET, SOCK_STREAM, 0); + ESP_LOGI(TAG, "allocate socket"); + sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) - { - ESP_LOGE (TAG, "... Failed to allocate socket."); - vTaskDelay (1000 / portTICK_PERIOD_MS); - continue; - } - ESP_LOGI (TAG, "... allocated socket %d", sock); + if (sock < 0) { + ESP_LOGE(TAG, "... Failed to allocate socket."); + vTaskDelay(1000 / portTICK_PERIOD_MS); + continue; + } + ESP_LOGI(TAG, "... allocated socket %d", sock); - ESP_LOGI (TAG, "connect to socket"); - err = connect (sock, (struct sockaddr *)&servaddr, - sizeof (struct sockaddr_in)); - if (err < 0) - { - ESP_LOGE (TAG, "%s, %d", strerror (errno), errno); + ESP_LOGI(TAG, "connect to socket"); + err = + connect(sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)); + if (err < 0) { + ESP_LOGE(TAG, "%s, %d", strerror(errno), errno); - shutdown (sock, 2); - closesocket (sock); + shutdown(sock, 2); + closesocket(sock); - vTaskDelay (4000 / portTICK_PERIOD_MS); + vTaskDelay(4000 / portTICK_PERIOD_MS); - continue; - } + continue; + } - ESP_LOGI (TAG, "... connected"); + ESP_LOGI(TAG, "... connected"); - result = gettimeofday (&now, NULL); - if (result) - { - ESP_LOGI (TAG, "Failed to gettimeofday\r\n"); - return; - } + result = gettimeofday(&now, NULL); + if (result) { + ESP_LOGI(TAG, "Failed to gettimeofday\r\n"); + return; + } - received_header = false; + received_header = false; - // init base message - base_message.type = SNAPCAST_MESSAGE_HELLO; - base_message.id = 0x0000; - base_message.refersTo = 0x0000; - base_message.sent.sec = now.tv_sec; - base_message.sent.usec = now.tv_usec; - base_message.received.sec = 0; - base_message.received.usec = 0; - base_message.size = 0x00000000; + // init base message + base_message.type = SNAPCAST_MESSAGE_HELLO; + base_message.id = 0x0000; + base_message.refersTo = 0x0000; + base_message.sent.sec = now.tv_sec; + base_message.sent.usec = now.tv_usec; + base_message.received.sec = 0; + base_message.received.usec = 0; + base_message.size = 0x00000000; - // init hello message - hello_message.mac = mac_address; - hello_message.hostname = "ESP32-Caster"; - hello_message.version = (char *)VERSION_STRING; - hello_message.client_name = "libsnapcast"; - hello_message.os = "esp32"; - hello_message.arch = "xtensa"; - hello_message.instance = 1; - hello_message.id = mac_address; - hello_message.protocol_version = 2; + // init hello message + hello_message.mac = mac_address; + hello_message.hostname = "ESP32-Caster"; + hello_message.version = (char *)VERSION_STRING; + hello_message.client_name = "libsnapcast"; + hello_message.os = "esp32"; + hello_message.arch = "xtensa"; + hello_message.instance = 1; + hello_message.id = mac_address; + hello_message.protocol_version = 2; - if (hello_message_serialized == NULL) - { - hello_message_serialized = hello_message_serialize ( - &hello_message, (size_t *)&(base_message.size)); - if (!hello_message_serialized) - { - ESP_LOGE (TAG, "Failed to serialize hello message\r\b"); - return; - } - } + if (hello_message_serialized == NULL) { + hello_message_serialized = hello_message_serialize( + &hello_message, (size_t *)&(base_message.size)); + if (!hello_message_serialized) { + ESP_LOGE(TAG, "Failed to serialize hello message\r\b"); + return; + } + } - result = base_message_serialize (&base_message, base_message_serialized, - BASE_MESSAGE_SIZE); - if (result) - { - ESP_LOGE (TAG, "Failed to serialize base message\r\n"); - return; - } + result = base_message_serialize(&base_message, base_message_serialized, + BASE_MESSAGE_SIZE); + if (result) { + ESP_LOGE(TAG, "Failed to serialize base message\r\n"); + return; + } - result = send (sock, base_message_serialized, BASE_MESSAGE_SIZE, 0); - if (result < 0) - { - ESP_LOGW (TAG, "error writing base msg to socket: %s", - strerror (errno)); + result = send(sock, base_message_serialized, BASE_MESSAGE_SIZE, 0); + if (result < 0) { + ESP_LOGW(TAG, "error writing base msg to socket: %s", strerror(errno)); - free (hello_message_serialized); - hello_message_serialized = NULL; - - shutdown (sock, 2); - closesocket (sock); - - continue; - } - - result = send (sock, hello_message_serialized, base_message.size, 0); - if (result < 0) - { - ESP_LOGW (TAG, "error writing hello msg to socket: %s", - strerror (errno)); - - free (hello_message_serialized); - hello_message_serialized = NULL; - - shutdown (sock, 2); - closesocket (sock); - - continue; - } - - free (hello_message_serialized); + free(hello_message_serialized); hello_message_serialized = NULL; - // init default setting - scSet.buf_ms = 0; - scSet.codec = NONE; - scSet.bits = 0; - scSet.ch = 0; - scSet.sr = 0; - scSet.chkDur_ms = 0; - scSet.volume = 0; - scSet.muted = true; + shutdown(sock, 2); + closesocket(sock); - lastTypedMsgSize = 0; - if (typedMsg) - { - free (typedMsg); - typedMsg = NULL; - } - - uint64_t startTime, endTime; - - for (;;) - { - // ESP_LOGW (TAG, "stack free: %d", - // uxTaskGetStackHighWaterMark(NULL)); - - size = 0; - result = 0; - while (size < BASE_MESSAGE_SIZE) - { - result = recv (sock, &(base_message_serialized[size]), - BASE_MESSAGE_SIZE - size, 0); - if (result < 0) - { - break; - } - size += result; - } - - if (result < 0) - { - if (errno != 0) - { - ESP_LOGW (TAG, "1: %s, %d", strerror (errno), (int)errno); - } - - shutdown (sock, 2); - closesocket (sock); - - break; // stop for(;;) will try to reconnect then - } - - if (result > 0) - { - result = gettimeofday (&now, NULL); - // ESP_LOGI(TAG, "time of day: %ld %ld", now.tv_sec, - // now.tv_usec); - if (result) - { - ESP_LOGW (TAG, "Failed to gettimeofday"); - continue; - } - - result = base_message_deserialize ( - &base_message, base_message_serialized, size); - if (result) - { - ESP_LOGW (TAG, "Failed to read base message: %d", result); - continue; - } - - base_message.received.usec = now.tv_usec; - // ESP_LOGI(TAG,"%d %d : %d %d : %d - // %d",base_message.size, - // base_message.refersTo, - // base_message.sent.sec, - // base_message.sent.usec, - // base_message.received.sec, - // base_message.received.usec - // ); - - // TODO: ensure this buffer is freed before task gets deleted - size = 0; - if (lastTypedMsgSize < base_message.size) - { - // typedMsg = (char *)heap_caps_realloc - // (typedMsg, base_message.size, MALLOC_CAP_8BIT); - // if (typedMsg == NULL) - { - // ESP_LOGI (TAG, "get memory - // for typed message %d, %d, %d", - // base_message.size, - // heap_caps_get_free_size(MALLOC_CAP_8BIT), - // heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); - typedMsg = (char *)heap_caps_realloc ( - typedMsg, base_message.size, MALLOC_CAP_8BIT); - - // typedMsg = (char - // *)heap_caps_malloc (base_message.size, - // MALLOC_CAP_8BIT); - if (typedMsg == NULL) - { - ESP_LOGE ( - TAG, - "Couldn't get memory for typed message %d, %d, %d", - base_message.size, - heap_caps_get_free_size (MALLOC_CAP_8BIT), - heap_caps_get_largest_free_block ( - MALLOC_CAP_8BIT)); - - // dummy read next data to a char variable without - // incrementing and drop it (base_message.size) - char dummy; - start = &dummy; - while (size < base_message.size) - { - result = recv (sock, start, 1, 0); - if (result < 0) - { - ESP_LOGW (TAG, - "Failed to read from server: %d", - result); - - break; - } - - size++; - } - - continue; - } - else - { - lastTypedMsgSize = base_message.size; - } - } - } - start = typedMsg; - - while (size < base_message.size) - { - result = recv (sock, &(start[size]), - base_message.size - size, 0); - if (result < 0) - { - ESP_LOGW (TAG, "Failed to read from server: %d", result); - - break; - } - - size += result; - } - - if (result < 0) - { - if (errno != 0) - { - ESP_LOGI (TAG, "2: %s, %d", strerror (errno), - (int)errno); - } - - shutdown (sock, 2); - closesocket (sock); - - break; // stop for(;;) will try to reconnect then - } - - switch (base_message.type) - { - case SNAPCAST_MESSAGE_CODEC_HEADER: - result = codec_header_message_deserialize ( - &codec_header_message, start, size); - if (result) - { - ESP_LOGI (TAG, "Failed to read codec header: %d", - result); - return; - } - - size = codec_header_message.size; - start = codec_header_message.payload; - - if (opusDecoder != NULL) - { - opus_decoder_destroy (opusDecoder); - opusDecoder = NULL; - } - - if (t_flac_decoder_task != NULL) - { - vTaskDelete (t_flac_decoder_task); - t_flac_decoder_task = NULL; - } - - if (flacDecoder != NULL) - { - FLAC__stream_decoder_finish (flacDecoder); - FLAC__stream_decoder_delete (flacDecoder); - flacDecoder = NULL; - } - - if (decoderWriteQHdl != NULL) - { - vQueueDelete (decoderWriteQHdl); - decoderWriteQHdl = NULL; - } - - if (decoderReadQHdl != NULL) - { - vQueueDelete (decoderReadQHdl); - decoderReadQHdl = NULL; - } - - // ESP_LOGI(TAG, "Received codec header message with size - // %d", codec_header_message.size); - - if (strcmp (codec_header_message.codec, "opus") == 0) - { - uint32_t rate; - memcpy (&rate, start + 4, sizeof (rate)); - uint16_t bits; - memcpy (&bits, start + 8, sizeof (bits)); - memcpy (&channels, start + 10, sizeof (channels)); - ESP_LOGI (TAG, "%s sampleformat: %d:%d:%d", - codec_header_message.codec, rate, bits, - channels); - - if (audio != NULL) - { - free (audio); - audio = NULL; - } - - if (flacData.outData != NULL) - { - free (flacData.outData); - flacData.outData = NULL; - } - - int error = 0; - opusDecoder - = opus_decoder_create (rate, channels, &error); - if (error != 0) - { - ESP_LOGE (TAG, "Failed to init %s decoder", - codec_header_message.codec); - return; - } - else - { - ESP_LOGI (TAG, "Initialized %s decoder", - codec_header_message.codec); - - codec = OPUS; - - scSet.codec = codec; - scSet.bits = bits; - scSet.ch = channels; - scSet.sr = rate; - } - } - else if (strcmp (codec_header_message.codec, "flac") == 0) - { - codec = FLAC; - - if (t_flac_decoder_task == NULL) - { - xTaskCreatePinnedToCore ( - &flac_decoder_task, "flac_decoder_task", - 4 * 4096, &scSet, FLAC_TASK_PRIORITY, - &t_flac_decoder_task, FLAC_TASK_CORE_ID); - } - - // check if audio buffer was previously allocated by some - // other codec this would happen if codec is changed - // while client was running - if (audio != NULL) - { - free (audio); - audio = NULL; - } - - if (flacData.outData != NULL) - { - free (flacData.outData); - flacData.outData = NULL; - } - - flacData.bytes = codec_header_message.size; - flacData.inData = codec_header_message.payload; - pFlacData = &flacData; - - // wait for task creation done - while (decoderReadQHdl == NULL) - { - vTaskDelay (10); - } - - // send data to flac decoder - xQueueSend (decoderReadQHdl, &pFlacData, portMAX_DELAY); - // and wait until it is done - xQueueReceive (decoderWriteQHdl, &pFlacData, - portMAX_DELAY); - - ESP_LOGI (TAG, "%s sampleformat: %d:%d:%d", - codec_header_message.codec, scSet.sr, - scSet.bits, scSet.ch); - } - else if (strcmp (codec_header_message.codec, "pcm") == 0) - { - codec = PCM; - - if (audio != NULL) - { - free (audio); - audio = NULL; - } - - if (flacData.outData != NULL) - { - free (flacData.outData); - flacData.outData = NULL; - } - - memcpy (&channels, start + 22, sizeof (channels)); - uint32_t rate; - memcpy (&rate, start + 24, sizeof (rate)); - uint16_t bits; - memcpy (&bits, start + 34, sizeof (bits)); - - ESP_LOGI (TAG, "%s sampleformat: %d:%d:%d", - codec_header_message.codec, rate, bits, - channels); - - scSet.codec = codec; - scSet.bits = bits; - scSet.ch = channels; - scSet.sr = rate; - } - else - { - codec = NONE; - - ESP_LOGI (TAG, "Codec : %s not supported", - codec_header_message.codec); - ESP_LOGI (TAG, - "Change encoder codec to opus / flac / pcm in " - "/etc/snapserver.conf " - "on server"); - return; - } - - trx.tv_sec = base_message.sent.sec; - trx.tv_usec = base_message.sent.usec; - // we do this, so uint32_t timvals won't overflow - // if e.g. raspberry server is off to far - settimeofday (&trx, NULL); - ESP_LOGI (TAG, "syncing clock to server %ld.%06ld", - trx.tv_sec, trx.tv_usec); - - codec_header_message_free (&codec_header_message); - - received_header = true; - - break; - - case SNAPCAST_MESSAGE_WIRE_CHUNK: - { - if (!received_header) - { - // if (typedMsg != NULL) - // { - // free (typedMsg); - // typedMsg = NULL; - // } - - continue; - } - - wire_chunk_message_t wire_chunk_message; - - result = wire_chunk_message_deserialize ( - &wire_chunk_message, start, size); - if (result) - { - ESP_LOGI (TAG, "Failed to read wire chunk: %d\r\n", - result); - - wire_chunk_message_free (&wire_chunk_message); - break; - } - - // ESP_LOGI(TAG, "wire - // chnk with size:" - // "%d, timestamp %d.%d", - // wire_chunk_message.size, - // wire_chunk_message.timestamp.sec, - // wire_chunk_message.timestamp.usec); - - // store chunk's timestamp, decoder callback - // will need it later - tv_t timestamp; - timestamp = wire_chunk_message.timestamp; - - switch (codec) - { - case OPUS: - { - int frame_size = 0; - - if (audio == NULL) - { -#if CONFIG_USE_PSRAM - audio = (int16_t *)heap_caps_malloc ( - frameSize * scSet.ch * (scSet.bits / 8), - MALLOC_CAP_8BIT - | MALLOC_CAP_SPIRAM); // 960*2: 20ms, - // 960*1: 10ms -#else - audio = (int16_t *)malloc ( - frameSize * scSet.ch - * (scSet.bits - / 8)); // 960*2: 20ms, 960*1: 10ms -#endif - } - - if (audio == NULL) - { - ESP_LOGE (TAG, "Failed to allocate memory for " - "opus audio decoder"); - } - else - { - size = wire_chunk_message.size; - start = wire_chunk_message.payload; - - while ((frame_size = opus_decode ( - opusDecoder, (unsigned char *)start, - size, (opus_int16 *)audio, - pcm_size / channels, 0)) - == OPUS_BUFFER_TOO_SMALL) - { - pcm_size = pcm_size * 2; - - // 960*2: 20ms, 960*1: 10ms -#if CONFIG_USE_PSRAM - audio = (int16_t *)heap_caps_realloc ( - audio, - pcm_size * scSet.ch * (scSet.bits / 8), - MALLOC_CAP_8BIT - | MALLOC_CAP_SPIRAM); // 2 channels + - // 2 Byte per - // sample == - // int32_t -#else - audio = (int16_t *)realloc ( - audio, - pcm_size * scSet.ch * (scSet.bits / 8)); - // audio = (int16_t, - // *)heap_caps_realloc( - // (int32_t - // *)audio, frameSize * - // CHANNELS * - // (BITS_PER_SAMPLE / 8), - // MALLOC_CAP_32BIT); -#endif - - ESP_LOGI (TAG, - "OPUS encoding buffer too small, " - "resizing to %d " - "samples per channel", - pcm_size / channels); - } - - if (frame_size < 0) - { - ESP_LOGE ( - TAG, - "Decode error : %d, %d, %s, %s, %d\n", - frame_size, size, start, (char *)audio, - pcm_size / channels); - - free (audio); - audio = NULL; - } - else - { - wire_chunk_message_t pcm_chunk_message; - - pcm_chunk_message.size = frame_size - * scSet.ch - * (scSet.bits / 8); - pcm_chunk_message.payload = (char *)audio; - pcm_chunk_message.timestamp = timestamp; - - scSet.chkDur_ms - = (1000UL * pcm_chunk_message.size) - / (uint32_t) (scSet.ch - * (scSet.bits / 8)) - / scSet.sr; - if (player_send_snapcast_setting (&scSet) - != pdPASS) - { - ESP_LOGE ( - TAG, - "Failed to notify sync task about " - "codec. Did you init player?"); - - return; - } - -#if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow (500, scSet.sr, - scSet.chkDur_ms); - dsp_processor (pcm_chunk_message.payload, - pcm_chunk_message.size, - dspFlow); -#endif - - insert_pcm_chunk (&pcm_chunk_message); - } - } - - break; - } - - case FLAC: - { - flacData.bytes = wire_chunk_message.size; - flacData.inData = wire_chunk_message.payload; - pFlacData = &flacData; - - // startTime = - // esp_timer_get_time (); - // send data to flac decoder - xQueueSend (decoderReadQHdl, &pFlacData, - portMAX_DELAY); - // and wait until it is done - xQueueReceive (decoderWriteQHdl, &pFlacData, - portMAX_DELAY); - // endTime = - // esp_timer_get_time (); - // ESP_LOGW(TAG, - //"%lld", endTime - startTime); - - wire_chunk_message_t pcm_chunk_message; - - pcm_chunk_message.size = flacData.bytes; - pcm_chunk_message.payload = flacData.outData; - pcm_chunk_message.timestamp = timestamp; - - scSet.chkDur_ms - = (1000UL * pcm_chunk_message.size) - / (uint32_t) (scSet.ch * (scSet.bits / 8)) - / scSet.sr; - if (player_send_snapcast_setting (&scSet) != pdPASS) - { - ESP_LOGE (TAG, - "Failed to notify sync task about " - "codec. Did you init player?"); - - return; - } - -#if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow (500, scSet.sr, scSet.chkDur_ms); - dsp_processor (pcm_chunk_message.payload, - pcm_chunk_message.size, dspFlow); -#endif - - // int ret; - // do { - // ret = - insert_pcm_chunk (&pcm_chunk_message); - // if (ret < 0) { - // vTaskDelay(10); - // } - // } while(ret != 0); - - break; - } - - case PCM: - { - wire_chunk_message_t pcm_chunk_message; - - size = wire_chunk_message.size; - start = wire_chunk_message.payload; - - pcm_chunk_message.size = size; - pcm_chunk_message.timestamp = timestamp; - pcm_chunk_message.payload - = wire_chunk_message.payload; - - scSet.chkDur_ms - = (1000UL * pcm_chunk_message.size) - / (uint32_t) (scSet.ch * (scSet.bits / 8)) - / scSet.sr; - if (player_send_snapcast_setting (&scSet) != pdPASS) - { - ESP_LOGE (TAG, - "Failed to notify sync task about " - "codec. Did you init player?"); - - return; - } - -#if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow (500, scSet.sr, scSet.chkDur_ms); - dsp_processor (pcm_chunk_message.payload, - pcm_chunk_message.size, dspFlow); -#endif - - insert_pcm_chunk (&pcm_chunk_message); - - break; - } - - default: - { - ESP_LOGE (TAG, "Decoder not supported"); - - return; - - break; - } - } - - wire_chunk_message_free (&wire_chunk_message); - - break; - } - - case SNAPCAST_MESSAGE_SERVER_SETTINGS: - // The first 4 bytes in the buffer are the size of the - // string. We don't need this, so we'll shift the entire - // buffer over 4 bytes and use the extra room to add a null - // character so cJSON can pares it. - memmove (start, start + 4, size - 4); - start[size - 3] = '\0'; - result = server_settings_message_deserialize ( - &server_settings_message, start); - if (result) - { - ESP_LOGI (TAG, "Failed to read server settings: %d", - result); - return; - } - // log mute state, buffer, latency - ESP_LOGI (TAG, "Buffer length: %d", - server_settings_message.buffer_ms); - ESP_LOGI (TAG, "Latency: %d", - server_settings_message.latency); - ESP_LOGI (TAG, "Mute: %d", - server_settings_message.muted); - ESP_LOGI (TAG, "Setting volume: %d", - server_settings_message.volume); - - // Volume setting using ADF HAL abstraction - if (scSet.muted != server_settings_message.muted) - { - audio_hal_set_mute (board_handle->audio_hal, - server_settings_message.muted); - } - if (scSet.volume != server_settings_message.volume) - { - audio_hal_set_volume (board_handle->audio_hal, - server_settings_message.volume); - } - - scSet.cDacLat_ms = server_settings_message.latency; - scSet.buf_ms = server_settings_message.buffer_ms; - scSet.muted = server_settings_message.muted; - scSet.volume = server_settings_message.volume; - - if (player_send_snapcast_setting (&scSet) != pdPASS) - { - ESP_LOGE ( - TAG, - "Failed to notify sync task. Did you init player?"); - - return; - } - - break; - - case SNAPCAST_MESSAGE_TIME: - result - = time_message_deserialize (&time_message, start, size); - if (result) - { - ESP_LOGI (TAG, "Failed to deserialize time message"); - - return; - } - - // ESP_LOGI(TAG, "BaseTX : %d %d ", - // base_message.sent.sec , - // base_message.sent.usec); ESP_LOGI(TAG, - //"BaseRX : %d %d ", - // base_message.received.sec , - // base_message.received.usec); ESP_LOGI(TAG, - // "baseTX->RX : %d s ", - // (base_message.received.sec - // - - // base_message.sent.sec)); ESP_LOGI(TAG, - // "baseTX->RX : %d ms ", - // (base_message.received.usec - - // base_message.sent.usec)/1000); - // ESP_LOGI(TAG, "Latency : %d.%d ", - // time_message.latency.sec, - // time_message.latency.usec/1000); - - // tv == server to client latency (s2c) - // time_message.latency == client to server latency(c2s) - // TODO the fact that I have to do this simple conversion - // means I should probably use the timeval struct instead of - // my own - trx.tv_sec = base_message.received.sec; - trx.tv_usec = base_message.received.usec; - ttx.tv_sec = base_message.sent.sec; - ttx.tv_usec = base_message.sent.usec; - timersub (&trx, &ttx, &tdif); - - trx.tv_sec = time_message.latency.sec; - trx.tv_usec = time_message.latency.usec; - - // trx == c2s: client to server - // tdif == s2c: server to client - // ESP_LOGI(TAG, "c2s: %ld %ld", - // trx.tv_sec, trx.tv_usec); ESP_LOGI(TAG, - // "s2c: %ld %ld", tdif.tv_sec, - // tdif.tv_usec); - - timersub (&trx, &tdif, &tmpDiffToServer); - if ((tmpDiffToServer.tv_sec / 2) == 0) - { - tmpDiffToServer.tv_sec = 0; - tmpDiffToServer.tv_usec - = (suseconds_t) ((int64_t)tmpDiffToServer.tv_sec - * 1000000LL / 2) - + (int64_t)tmpDiffToServer.tv_usec / 2; - } - else - { - tmpDiffToServer.tv_sec /= 2; - tmpDiffToServer.tv_usec /= 2; - } - - // ESP_LOGI(TAG, - // "Current latency: %ld.%06ld", - // tmpDiffToServer.tv_sec, - // tmpDiffToServer.tv_usec); - - // TODO: Move the time message sending to an own thread maybe - // following code is storing / initializing / resetting diff - // to server algorithm we collect a number of latencies and - // apply a median filter. Based on these we can get server - // now - { - struct timeval diff; - int64_t newValue; - - // clear diffBuffer if last update is older than a minute - timersub (&now, &lastTimeSync, &diff); - - if (diff.tv_sec > 60) - { - ESP_LOGW (TAG, "Last time sync older than a minute. " - "Clearing time buffer"); - - reset_latency_buffer (); - } - - newValue = ((int64_t)tmpDiffToServer.tv_sec * 1000000LL - + (int64_t)tmpDiffToServer.tv_usec); - player_latency_insert (newValue); - - // ESP_LOGE(TAG, "latency %lld", - // newValue); - - // store current time - lastTimeSync.tv_sec = now.tv_sec; - lastTimeSync.tv_usec = now.tv_usec; - - if (xSemaphoreTake (timeSyncSemaphoreHandle, 0) == pdTRUE) - { - ESP_LOGW (TAG, - "couldn't take timeSyncSemaphoreHandle"); - } - - uint64_t timeout; - if (latency_buffer_full () > 0) - { - // we give timeSyncSemaphoreHandle after x µs through - // timer - // TODO: maybe start a periodic timer here, but we need - // to remember if it is already running then. also we - // need to stop it if reset_latency_buffer() was called - timeout = 1000000; - } - else - { - // Do a initial time sync with the server at boot - // we need to fill diffBuff fast so we get a good - // estimate of latency - timeout = 100000; - } - - esp_timer_start_once (timeSyncMessageTimer, timeout); - } - - break; - } - - // if (typedMsg != NULL) - // { - // free (typedMsg); - // typedMsg = NULL; - // } - } - - if (received_header == true) - { - if (xSemaphoreTake (timeSyncSemaphoreHandle, 0) == pdTRUE) - { - result = gettimeofday (&now, NULL); - // ESP_LOGI(TAG, "time of day: %ld %ld", now.tv_sec, - // now.tv_usec); - if (result) - { - ESP_LOGI (TAG, "Failed to gettimeofday"); - continue; - } - - base_message.type = SNAPCAST_MESSAGE_TIME; - base_message.id = id_counter++; - base_message.refersTo = 0; - base_message.received.sec = 0; - base_message.received.usec = 0; - base_message.sent.sec = now.tv_sec; - base_message.sent.usec = now.tv_usec; - base_message.size = TIME_MESSAGE_SIZE; - - result = base_message_serialize (&base_message, - base_message_serialized, - BASE_MESSAGE_SIZE); - if (result) - { - ESP_LOGE ( - TAG, - "Failed to serialize base message for time\r\n"); - continue; - } - - memset (&time_message, 0, sizeof (time_message)); - - result = time_message_serialize (&time_message, - time_message_serialized, - TIME_MESSAGE_SIZE); - if (result) - { - ESP_LOGI (TAG, "Failed to serialize time message\r\b"); - continue; - } - - result = send (sock, base_message_serialized, - BASE_MESSAGE_SIZE, 0); - if (result < 0) - { - ESP_LOGW ( - TAG, "error writing timesync base msg to socket: %s", - strerror (errno)); - - shutdown (sock, 2); - closesocket (sock); - - break; // stop for(;;) will try to reconnect then - } - - result = send (sock, time_message_serialized, - TIME_MESSAGE_SIZE, 0); - if (result < 0) - { - ESP_LOGW (TAG, - "error writing timesync msg to socket: %s", - strerror (errno)); - - shutdown (sock, 2); - closesocket (sock); - - break; // stop for(;;) will try to reconnect then - } - - // ESP_LOGI(TAG, "sent time sync message - // %ld.%06ld", now.tv_sec, now.tv_usec); - } - } - - // endTime = esp_timer_get_time (); - // ESP_LOGW(TAG, "%lld", endTime - startTime); - } + continue; } + + result = send(sock, hello_message_serialized, base_message.size, 0); + if (result < 0) { + ESP_LOGW(TAG, "error writing hello msg to socket: %s", strerror(errno)); + + free(hello_message_serialized); + hello_message_serialized = NULL; + + shutdown(sock, 2); + closesocket(sock); + + continue; + } + + free(hello_message_serialized); + hello_message_serialized = NULL; + + // init default setting + scSet.buf_ms = 0; + scSet.codec = NONE; + scSet.bits = 0; + scSet.ch = 0; + scSet.sr = 0; + scSet.chkDur_ms = 0; + scSet.volume = 0; + scSet.muted = true; + + lastTypedMsgSize = 0; + if (typedMsg) { + free(typedMsg); + typedMsg = NULL; + } + + uint64_t startTime, endTime; + + for (;;) { + // ESP_LOGW (TAG, "stack free: %d", + // uxTaskGetStackHighWaterMark(NULL)); + + size = 0; + result = 0; + while (size < BASE_MESSAGE_SIZE) { + result = recv(sock, &(base_message_serialized[size]), + BASE_MESSAGE_SIZE - size, 0); + if (result < 0) { + break; + } + size += result; + } + + if (result < 0) { + if (errno != 0) { + ESP_LOGW(TAG, "1: %s, %d", strerror(errno), (int)errno); + } + + shutdown(sock, 2); + closesocket(sock); + + break; // stop for(;;) will try to reconnect then + } + + if (result > 0) { + result = gettimeofday(&now, NULL); + // ESP_LOGI(TAG, "time of day: %ld %ld", now.tv_sec, + // now.tv_usec); + if (result) { + ESP_LOGW(TAG, "Failed to gettimeofday"); + continue; + } + + result = base_message_deserialize(&base_message, + base_message_serialized, size); + if (result) { + ESP_LOGW(TAG, "Failed to read base message: %d", result); + continue; + } + + base_message.received.usec = now.tv_usec; + // ESP_LOGI(TAG,"%d %d : %d %d : %d + // %d",base_message.size, + // base_message.refersTo, + // base_message.sent.sec, + // base_message.sent.usec, + // base_message.received.sec, + // base_message.received.usec + // ); + + // TODO: ensure this buffer is freed before task gets deleted + size = 0; + if (lastTypedMsgSize < base_message.size) { + // typedMsg = (char *)heap_caps_realloc + // (typedMsg, base_message.size, MALLOC_CAP_8BIT); + // if (typedMsg == NULL) + { + // ESP_LOGI (TAG, "get memory + // for typed message %d, %d, %d", + // base_message.size, + // heap_caps_get_free_size(MALLOC_CAP_8BIT), + // heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); + typedMsg = (char *)heap_caps_realloc(typedMsg, base_message.size, + MALLOC_CAP_8BIT); + + // typedMsg = (char + // *)heap_caps_malloc (base_message.size, + // MALLOC_CAP_8BIT); + if (typedMsg == NULL) { + ESP_LOGE(TAG, "Couldn't get memory for typed message %d, %d, %d", + base_message.size, + heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_largest_free_block(MALLOC_CAP_8BIT)); + + // dummy read next data to a char variable without + // incrementing and drop it (base_message.size) + char dummy; + start = &dummy; + while (size < base_message.size) { + result = recv(sock, start, 1, 0); + if (result < 0) { + ESP_LOGW(TAG, "Failed to read from server: %d", result); + + break; + } + + size++; + } + + continue; + } else { + lastTypedMsgSize = base_message.size; + } + } + } + start = typedMsg; + + while (size < base_message.size) { + result = recv(sock, &(start[size]), base_message.size - size, 0); + if (result < 0) { + ESP_LOGW(TAG, "Failed to read from server: %d", result); + + break; + } + + size += result; + } + + if (result < 0) { + if (errno != 0) { + ESP_LOGI(TAG, "2: %s, %d", strerror(errno), (int)errno); + } + + shutdown(sock, 2); + closesocket(sock); + + break; // stop for(;;) will try to reconnect then + } + + switch (base_message.type) { + case SNAPCAST_MESSAGE_CODEC_HEADER: + result = codec_header_message_deserialize(&codec_header_message, + start, size); + if (result) { + ESP_LOGI(TAG, "Failed to read codec header: %d", result); + return; + } + + size = codec_header_message.size; + start = codec_header_message.payload; + + if (opusDecoder != NULL) { + opus_decoder_destroy(opusDecoder); + opusDecoder = NULL; + } + + if (t_flac_decoder_task != NULL) { + vTaskDelete(t_flac_decoder_task); + t_flac_decoder_task = NULL; + } + + if (flacDecoder != NULL) { + FLAC__stream_decoder_finish(flacDecoder); + FLAC__stream_decoder_delete(flacDecoder); + flacDecoder = NULL; + } + + if (decoderWriteQHdl != NULL) { + vQueueDelete(decoderWriteQHdl); + decoderWriteQHdl = NULL; + } + + if (decoderReadQHdl != NULL) { + vQueueDelete(decoderReadQHdl); + decoderReadQHdl = NULL; + } + + // ESP_LOGI(TAG, "Received codec header message with size + // %d", codec_header_message.size); + + if (strcmp(codec_header_message.codec, "opus") == 0) { + uint32_t rate; + memcpy(&rate, start + 4, sizeof(rate)); + uint16_t bits; + memcpy(&bits, start + 8, sizeof(bits)); + memcpy(&channels, start + 10, sizeof(channels)); + ESP_LOGI(TAG, "%s sampleformat: %d:%d:%d", + codec_header_message.codec, rate, bits, channels); + + if (audio != NULL) { + free(audio); + audio = NULL; + } + + if (flacData.outData != NULL) { + free(flacData.outData); + flacData.outData = NULL; + } + + int error = 0; + opusDecoder = opus_decoder_create(rate, channels, &error); + if (error != 0) { + ESP_LOGE(TAG, "Failed to init %s decoder", + codec_header_message.codec); + return; + } else { + ESP_LOGI(TAG, "Initialized %s decoder", + codec_header_message.codec); + + codec = OPUS; + + scSet.codec = codec; + scSet.bits = bits; + scSet.ch = channels; + scSet.sr = rate; + } + } else if (strcmp(codec_header_message.codec, "flac") == 0) { + codec = FLAC; + + if (t_flac_decoder_task == NULL) { + xTaskCreatePinnedToCore(&flac_decoder_task, "flac_decoder_task", + 4 * 4096, &scSet, FLAC_TASK_PRIORITY, + &t_flac_decoder_task, + FLAC_TASK_CORE_ID); + } + + // check if audio buffer was previously allocated by some + // other codec this would happen if codec is changed + // while client was running + if (audio != NULL) { + free(audio); + audio = NULL; + } + + if (flacData.outData != NULL) { + free(flacData.outData); + flacData.outData = NULL; + } + + flacData.bytes = codec_header_message.size; + flacData.inData = codec_header_message.payload; + pFlacData = &flacData; + + // wait for task creation done + while (decoderReadQHdl == NULL) { + vTaskDelay(10); + } + + // send data to flac decoder + xQueueSend(decoderReadQHdl, &pFlacData, portMAX_DELAY); + // and wait until it is done + xQueueReceive(decoderWriteQHdl, &pFlacData, portMAX_DELAY); + + ESP_LOGI(TAG, "%s sampleformat: %d:%d:%d", + codec_header_message.codec, scSet.sr, scSet.bits, + scSet.ch); + } else if (strcmp(codec_header_message.codec, "pcm") == 0) { + codec = PCM; + + if (audio != NULL) { + free(audio); + audio = NULL; + } + + if (flacData.outData != NULL) { + free(flacData.outData); + flacData.outData = NULL; + } + + memcpy(&channels, start + 22, sizeof(channels)); + uint32_t rate; + memcpy(&rate, start + 24, sizeof(rate)); + uint16_t bits; + memcpy(&bits, start + 34, sizeof(bits)); + + ESP_LOGI(TAG, "%s sampleformat: %d:%d:%d", + codec_header_message.codec, rate, bits, channels); + + scSet.codec = codec; + scSet.bits = bits; + scSet.ch = channels; + scSet.sr = rate; + } else { + codec = NONE; + + ESP_LOGI(TAG, "Codec : %s not supported", + codec_header_message.codec); + ESP_LOGI(TAG, + "Change encoder codec to opus / flac / pcm in " + "/etc/snapserver.conf " + "on server"); + return; + } + + trx.tv_sec = base_message.sent.sec; + trx.tv_usec = base_message.sent.usec; + // we do this, so uint32_t timvals won't overflow + // if e.g. raspberry server is off to far + settimeofday(&trx, NULL); + ESP_LOGI(TAG, "syncing clock to server %ld.%06ld", trx.tv_sec, + trx.tv_usec); + + codec_header_message_free(&codec_header_message); + + received_header = true; + + break; + + case SNAPCAST_MESSAGE_WIRE_CHUNK: { + if (!received_header) { + // if (typedMsg != NULL) + // { + // free (typedMsg); + // typedMsg = NULL; + // } + + continue; + } + + wire_chunk_message_t wire_chunk_message; + + result = wire_chunk_message_deserialize(&wire_chunk_message, start, + size); + if (result) { + ESP_LOGI(TAG, "Failed to read wire chunk: %d\r\n", result); + + wire_chunk_message_free(&wire_chunk_message); + break; + } + + // ESP_LOGI(TAG, "wire + // chnk with size:" + // "%d, timestamp %d.%d", + // wire_chunk_message.size, + // wire_chunk_message.timestamp.sec, + // wire_chunk_message.timestamp.usec); + + // store chunk's timestamp, decoder callback + // will need it later + tv_t timestamp; + timestamp = wire_chunk_message.timestamp; + + switch (codec) { + case OPUS: { + int frame_size = 0; + + if (audio == NULL) { +#if CONFIG_USE_PSRAM + audio = (int16_t *)heap_caps_malloc( + frameSize * scSet.ch * (scSet.bits / 8), + MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); // 960*2: 20ms, + // 960*1: 10ms +#else + audio = (int16_t *)malloc( + frameSize * scSet.ch * + (scSet.bits / 8)); // 960*2: 20ms, 960*1: 10ms +#endif + } + + if (audio == NULL) { + ESP_LOGE(TAG, + "Failed to allocate memory for " + "opus audio decoder"); + } else { + size = wire_chunk_message.size; + start = wire_chunk_message.payload; + + while ((frame_size = opus_decode( + opusDecoder, (unsigned char *)start, size, + (opus_int16 *)audio, pcm_size / channels, 0)) == + OPUS_BUFFER_TOO_SMALL) { + pcm_size = pcm_size * 2; + + // 960*2: 20ms, 960*1: 10ms +#if CONFIG_USE_PSRAM + audio = (int16_t *)heap_caps_realloc( + audio, pcm_size * scSet.ch * (scSet.bits / 8), + MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); // 2 channels + + // 2 Byte per + // sample == + // int32_t +#else + audio = (int16_t *)realloc( + audio, pcm_size * scSet.ch * (scSet.bits / 8)); + // audio = (int16_t, + // *)heap_caps_realloc( + // (int32_t + // *)audio, frameSize * + // CHANNELS * + // (BITS_PER_SAMPLE / 8), + // MALLOC_CAP_32BIT); +#endif + + ESP_LOGI(TAG, + "OPUS encoding buffer too small, " + "resizing to %d " + "samples per channel", + pcm_size / channels); + } + + if (frame_size < 0) { + ESP_LOGE(TAG, "Decode error : %d, %d, %s, %s, %d\n", + frame_size, size, start, (char *)audio, + pcm_size / channels); + + free(audio); + audio = NULL; + } else { + wire_chunk_message_t pcm_chunk_message; + + pcm_chunk_message.size = + frame_size * scSet.ch * (scSet.bits / 8); + pcm_chunk_message.payload = (char *)audio; + pcm_chunk_message.timestamp = timestamp; + + scSet.chkDur_ms = (1000UL * pcm_chunk_message.size) / + (uint32_t)(scSet.ch * (scSet.bits / 8)) / + scSet.sr; + if (player_send_snapcast_setting(&scSet) != pdPASS) { + ESP_LOGE(TAG, + "Failed to notify sync task about " + "codec. Did you init player?"); + + return; + } + +#if CONFIG_USE_DSP_PROCESSOR + dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_processor(pcm_chunk_message.payload, + pcm_chunk_message.size, dspFlow); +#endif + + insert_pcm_chunk(&pcm_chunk_message); + } + } + + break; + } + + case FLAC: { + flacData.bytes = wire_chunk_message.size; + flacData.inData = wire_chunk_message.payload; + pFlacData = &flacData; + + // startTime = + // esp_timer_get_time (); + // send data to flac decoder + xQueueSend(decoderReadQHdl, &pFlacData, portMAX_DELAY); + // and wait until it is done + xQueueReceive(decoderWriteQHdl, &pFlacData, portMAX_DELAY); + // endTime = + // esp_timer_get_time (); + // ESP_LOGW(TAG, + //"%lld", endTime - startTime); + + wire_chunk_message_t pcm_chunk_message; + + pcm_chunk_message.size = flacData.bytes; + pcm_chunk_message.payload = flacData.outData; + pcm_chunk_message.timestamp = timestamp; + + scSet.chkDur_ms = (1000UL * pcm_chunk_message.size) / + (uint32_t)(scSet.ch * (scSet.bits / 8)) / + scSet.sr; + if (player_send_snapcast_setting(&scSet) != pdPASS) { + ESP_LOGE(TAG, + "Failed to notify sync task about " + "codec. Did you init player?"); + + return; + } + +#if CONFIG_USE_DSP_PROCESSOR + dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_processor(pcm_chunk_message.payload, pcm_chunk_message.size, + dspFlow); +#endif + + // int ret; + // do { + // ret = + insert_pcm_chunk(&pcm_chunk_message); + // if (ret < 0) { + // vTaskDelay(10); + // } + // } while(ret != 0); + + break; + } + + case PCM: { + wire_chunk_message_t pcm_chunk_message; + + size = wire_chunk_message.size; + start = wire_chunk_message.payload; + + pcm_chunk_message.size = size; + pcm_chunk_message.timestamp = timestamp; + pcm_chunk_message.payload = wire_chunk_message.payload; + + scSet.chkDur_ms = (1000UL * pcm_chunk_message.size) / + (uint32_t)(scSet.ch * (scSet.bits / 8)) / + scSet.sr; + if (player_send_snapcast_setting(&scSet) != pdPASS) { + ESP_LOGE(TAG, + "Failed to notify sync task about " + "codec. Did you init player?"); + + return; + } + +#if CONFIG_USE_DSP_PROCESSOR + dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_processor(pcm_chunk_message.payload, pcm_chunk_message.size, + dspFlow); +#endif + + insert_pcm_chunk(&pcm_chunk_message); + + break; + } + + default: { + ESP_LOGE(TAG, "Decoder not supported"); + + return; + + break; + } + } + + wire_chunk_message_free(&wire_chunk_message); + + break; + } + + case SNAPCAST_MESSAGE_SERVER_SETTINGS: + // The first 4 bytes in the buffer are the size of the + // string. We don't need this, so we'll shift the entire + // buffer over 4 bytes and use the extra room to add a null + // character so cJSON can pares it. + memmove(start, start + 4, size - 4); + start[size - 3] = '\0'; + result = server_settings_message_deserialize( + &server_settings_message, start); + if (result) { + ESP_LOGI(TAG, "Failed to read server settings: %d", result); + return; + } + // log mute state, buffer, latency + ESP_LOGI(TAG, "Buffer length: %d", + server_settings_message.buffer_ms); + ESP_LOGI(TAG, "Latency: %d", + server_settings_message.latency); + ESP_LOGI(TAG, "Mute: %d", server_settings_message.muted); + ESP_LOGI(TAG, "Setting volume: %d", server_settings_message.volume); + + // Volume setting using ADF HAL abstraction + if (scSet.muted != server_settings_message.muted) { + audio_hal_set_mute(board_handle->audio_hal, + server_settings_message.muted); + } + if (scSet.volume != server_settings_message.volume) { + audio_hal_set_volume(board_handle->audio_hal, + server_settings_message.volume); + } + + scSet.cDacLat_ms = server_settings_message.latency; + scSet.buf_ms = server_settings_message.buffer_ms; + scSet.muted = server_settings_message.muted; + scSet.volume = server_settings_message.volume; + + if (player_send_snapcast_setting(&scSet) != pdPASS) { + ESP_LOGE(TAG, "Failed to notify sync task. Did you init player?"); + + return; + } + + break; + + case SNAPCAST_MESSAGE_TIME: + result = time_message_deserialize(&time_message, start, size); + if (result) { + ESP_LOGI(TAG, "Failed to deserialize time message"); + + return; + } + + // ESP_LOGI(TAG, "BaseTX : %d %d ", + // base_message.sent.sec , + // base_message.sent.usec); ESP_LOGI(TAG, + //"BaseRX : %d %d ", + // base_message.received.sec , + // base_message.received.usec); ESP_LOGI(TAG, + // "baseTX->RX : %d s ", + // (base_message.received.sec + // - + // base_message.sent.sec)); ESP_LOGI(TAG, + // "baseTX->RX : %d ms ", + // (base_message.received.usec - + // base_message.sent.usec)/1000); + // ESP_LOGI(TAG, "Latency : %d.%d ", + // time_message.latency.sec, + // time_message.latency.usec/1000); + + // tv == server to client latency (s2c) + // time_message.latency == client to server latency(c2s) + // TODO the fact that I have to do this simple conversion + // means I should probably use the timeval struct instead of + // my own + trx.tv_sec = base_message.received.sec; + trx.tv_usec = base_message.received.usec; + ttx.tv_sec = base_message.sent.sec; + ttx.tv_usec = base_message.sent.usec; + timersub(&trx, &ttx, &tdif); + + trx.tv_sec = time_message.latency.sec; + trx.tv_usec = time_message.latency.usec; + + // trx == c2s: client to server + // tdif == s2c: server to client + // ESP_LOGI(TAG, "c2s: %ld %ld", + // trx.tv_sec, trx.tv_usec); ESP_LOGI(TAG, + // "s2c: %ld %ld", tdif.tv_sec, + // tdif.tv_usec); + + timersub(&trx, &tdif, &tmpDiffToServer); + if ((tmpDiffToServer.tv_sec / 2) == 0) { + tmpDiffToServer.tv_sec = 0; + tmpDiffToServer.tv_usec = + (suseconds_t)((int64_t)tmpDiffToServer.tv_sec * 1000000LL / + 2) + + (int64_t)tmpDiffToServer.tv_usec / 2; + } else { + tmpDiffToServer.tv_sec /= 2; + tmpDiffToServer.tv_usec /= 2; + } + + // ESP_LOGI(TAG, + // "Current latency: %ld.%06ld", + // tmpDiffToServer.tv_sec, + // tmpDiffToServer.tv_usec); + + // TODO: Move the time message sending to an own thread maybe + // following code is storing / initializing / resetting diff + // to server algorithm we collect a number of latencies and + // apply a median filter. Based on these we can get server + // now + { + struct timeval diff; + int64_t newValue; + + // clear diffBuffer if last update is older than a minute + timersub(&now, &lastTimeSync, &diff); + + if (diff.tv_sec > 60) { + ESP_LOGW(TAG, + "Last time sync older than a minute. " + "Clearing time buffer"); + + reset_latency_buffer(); + } + + newValue = ((int64_t)tmpDiffToServer.tv_sec * 1000000LL + + (int64_t)tmpDiffToServer.tv_usec); + player_latency_insert(newValue); + + // ESP_LOGE(TAG, "latency %lld", + // newValue); + + // store current time + lastTimeSync.tv_sec = now.tv_sec; + lastTimeSync.tv_usec = now.tv_usec; + + if (xSemaphoreTake(timeSyncSemaphoreHandle, 0) == pdTRUE) { + ESP_LOGW(TAG, "couldn't take timeSyncSemaphoreHandle"); + } + + uint64_t timeout; + if (latency_buffer_full() > 0) { + // we give timeSyncSemaphoreHandle after x µs through + // timer + // TODO: maybe start a periodic timer here, but we need + // to remember if it is already running then. also we + // need to stop it if reset_latency_buffer() was called + timeout = 1000000; + } else { + // Do a initial time sync with the server at boot + // we need to fill diffBuff fast so we get a good + // estimate of latency + timeout = 100000; + } + + esp_timer_start_once(timeSyncMessageTimer, timeout); + } + + break; + } + + // if (typedMsg != NULL) + // { + // free (typedMsg); + // typedMsg = NULL; + // } + } + + if (received_header == true) { + if (xSemaphoreTake(timeSyncSemaphoreHandle, 0) == pdTRUE) { + result = gettimeofday(&now, NULL); + // ESP_LOGI(TAG, "time of day: %ld %ld", now.tv_sec, + // now.tv_usec); + if (result) { + ESP_LOGI(TAG, "Failed to gettimeofday"); + continue; + } + + base_message.type = SNAPCAST_MESSAGE_TIME; + base_message.id = id_counter++; + base_message.refersTo = 0; + base_message.received.sec = 0; + base_message.received.usec = 0; + base_message.sent.sec = now.tv_sec; + base_message.sent.usec = now.tv_usec; + base_message.size = TIME_MESSAGE_SIZE; + + result = base_message_serialize( + &base_message, base_message_serialized, BASE_MESSAGE_SIZE); + if (result) { + ESP_LOGE(TAG, "Failed to serialize base message for time\r\n"); + continue; + } + + memset(&time_message, 0, sizeof(time_message)); + + result = time_message_serialize( + &time_message, time_message_serialized, TIME_MESSAGE_SIZE); + if (result) { + ESP_LOGI(TAG, "Failed to serialize time message\r\b"); + continue; + } + + result = send(sock, base_message_serialized, BASE_MESSAGE_SIZE, 0); + if (result < 0) { + ESP_LOGW(TAG, "error writing timesync base msg to socket: %s", + strerror(errno)); + + shutdown(sock, 2); + closesocket(sock); + + break; // stop for(;;) will try to reconnect then + } + + result = send(sock, time_message_serialized, TIME_MESSAGE_SIZE, 0); + if (result < 0) { + ESP_LOGW(TAG, "error writing timesync msg to socket: %s", + strerror(errno)); + + shutdown(sock, 2); + closesocket(sock); + + break; // stop for(;;) will try to reconnect then + } + + // ESP_LOGI(TAG, "sent time sync message + // %ld.%06ld", now.tv_sec, now.tv_usec); + } + } + + // endTime = esp_timer_get_time (); + // ESP_LOGW(TAG, "%lld", endTime - startTime); + } + } } -void -app_main (void) -{ - esp_err_t ret = nvs_flash_init (); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_ERROR_CHECK (nvs_flash_erase ()); - ret = nvs_flash_init (); - } - ESP_ERROR_CHECK (ret); +void app_main(void) { + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || + ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); - esp_log_level_set ("*", ESP_LOG_INFO); + esp_log_level_set("*", ESP_LOG_INFO); // esp_log_level_set("c_I2S", ESP_LOG_NONE); // if enabled these cause a timer srv stack overflow - esp_log_level_set ("HEADPHONE", ESP_LOG_NONE); - esp_log_level_set ("gpio", ESP_LOG_NONE); + esp_log_level_set("HEADPHONE", ESP_LOG_NONE); + esp_log_level_set("gpio", ESP_LOG_NONE); - esp_timer_init (); + esp_timer_init(); - ESP_LOGI (TAG, "Start codec chip"); - board_handle = audio_board_init (); - ESP_LOGI (TAG, "Audio board_init done"); + ESP_LOGI(TAG, "Start codec chip"); + board_handle = audio_board_init(); + ESP_LOGI(TAG, "Audio board_init done"); - audio_hal_ctrl_codec (board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, - AUDIO_HAL_CTRL_START); - audio_hal_set_mute (board_handle->audio_hal, - true); // ensure no noise is sent after firmware crash - i2s_mclk_gpio_select (0, 0); + audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, + AUDIO_HAL_CTRL_START); + audio_hal_set_mute(board_handle->audio_hal, + true); // ensure no noise is sent after firmware crash + i2s_mclk_gpio_select(0, 0); // setup_ma120(); #if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow (500, 44100, 20); // init with default value + dsp_setup_flow(500, 44100, 20); // init with default value #endif - ESP_LOGI (TAG, "init player"); - init_player (); + ESP_LOGI(TAG, "init player"); + init_player(); // Enable and setup WIFI in station mode and connect to Access point setup in // menu config or set up provisioning mode settable in menuconfig - wifi_init (); + wifi_init(); // Enable websocket server - ESP_LOGI (TAG, "Connected to AP"); + ESP_LOGI(TAG, "Connected to AP"); // ESP_LOGI(TAG, "Setup ws server"); // websocket_if_start(); - net_mdns_register ("snapclient"); + net_mdns_register("snapclient"); #ifdef CONFIG_SNAPCLIENT_SNTP_ENABLE - set_time_from_sntp (); + set_time_from_sntp(); #endif - // xTaskCreatePinnedToCore (&ota_server_task, "ota", 14 * 256, NULL, - // OTA_TASK_PRIORITY, t_ota_task, - // OTA_TASK_CORE_ID); + xTaskCreatePinnedToCore(&ota_server_task, "ota", 14 * 256, NULL, + OTA_TASK_PRIORITY, t_ota_task, OTA_TASK_CORE_ID); // xTaskCreatePinnedToCore (&http_get_task, "http", 10 * 256, NULL, // HTTP_TASK_PRIORITY, &t_http_get_task, // HTTP_TASK_CORE_ID); - xTaskCreatePinnedToCore (&http_get_task, "http", 3 * 1024, NULL, - HTTP_TASK_PRIORITY, &t_http_get_task, - HTTP_TASK_CORE_ID); + xTaskCreatePinnedToCore(&http_get_task, "http", 3 * 1024, NULL, + HTTP_TASK_PRIORITY, &t_http_get_task, + HTTP_TASK_CORE_ID); - while (1) - { - // audio_event_iface_msg_t msg; - vTaskDelay (portMAX_DELAY); //(pdMS_TO_TICKS(5000)); + while (1) { + // audio_event_iface_msg_t msg; + vTaskDelay(portMAX_DELAY); //(pdMS_TO_TICKS(5000)); - // ma120_read_error(0x20); + // ma120_read_error(0x20); - esp_err_t ret = 0; // audio_event_iface_listen(evt, &msg, portMAX_DELAY); - if (ret != ESP_OK) - { - ESP_LOGE (TAG, "[ * ] Event interface error : %d", ret); - continue; - } + esp_err_t ret = 0; // audio_event_iface_listen(evt, &msg, portMAX_DELAY); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret); + continue; } + } }