From e79b17cbb708d843849845c9e5a66c30ebf01588 Mon Sep 17 00:00:00 2001 From: Karl Osterseher Date: Wed, 28 Dec 2022 17:07:09 +0100 Subject: [PATCH] - use separate task to handle flac data coming from http_get_task() Signed-off-by: Karl Osterseher --- components/lightsnapcast/player.c | 2 +- main/main.c | 198 +++++++++++++++++++++++++----- 2 files changed, 166 insertions(+), 34 deletions(-) diff --git a/components/lightsnapcast/player.c b/components/lightsnapcast/player.c index 5d77c67..23da32d 100644 --- a/components/lightsnapcast/player.c +++ b/components/lightsnapcast/player.c @@ -913,7 +913,7 @@ int32_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk, "couldn't get memory to insert chunk, inserting an chunk " "containing just 0"); - ESP_LOGI( + ESP_LOGW( 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), diff --git a/main/main.c b/main/main.c index cdb3b46..eb6f537 100644 --- a/main/main.c +++ b/main/main.c @@ -81,10 +81,11 @@ const char *VERSION_STRING = "0.0.2"; #define OTA_TASK_PRIORITY 6 #define OTA_TASK_CORE_ID tskNO_AFFINITY // 1 // tskNO_AFFINITY -#define FLAC_DECODER_TASK_PRIORITY HTTP_TASK_PRIORITY -#define FLAC_DECODER_TASK_CORE_ID HTTP_TASK_CORE_ID // 1 // tskNO_AFFINITY +#define FLAC_DECODER_TASK_PRIORITY 7 // HTTP_TASK_PRIORITY +#define FLAC_DECODER_TASK_CORE_ID \ + tskNO_AFFINITY // HTTP_TASK_CORE_ID // 1 // tskNO_AFFINITY -#define FLAC_TASK_PRIORITY 7 +#define FLAC_TASK_PRIORITY 8 #define FLAC_TASK_CORE_ID tskNO_AFFINITY // 1 // tskNO_AFFINITY xTaskHandle t_ota_task = NULL; @@ -128,6 +129,8 @@ dspFlows_t dspFlow = dspfBiamp; #endif typedef struct flacData_s { + uint32_t type; // should be SNAPCAST_MESSAGE_CODEC_HEADER + // or SNAPCAST_MESSAGE_WIRE_CHUNK char *inData; tv_t timestamp; pcm_chunk_message_t *outData; @@ -226,6 +229,29 @@ void time_sync_msg_cb(void *args) { // } } +/** + * + */ +void free_flac_data(flacData_t *pFlacData) { + if (pFlacData->inData) { + free(pFlacData->inData); + pFlacData->inData = NULL; + } + + if (pFlacData->outData) { + free(pFlacData->outData); + pFlacData->outData = NULL; + } + + if (pFlacData) { + free(pFlacData); + pFlacData = NULL; + } +} + +/** + * + */ static FLAC__StreamDecoderReadStatus read_callback( const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) { @@ -236,14 +262,17 @@ static FLAC__StreamDecoderReadStatus read_callback( xQueueReceive(decoderReadQHdl, &flacData, portMAX_DELAY); - // ESP_LOGI(TAG, "in flac read cb %d %p", flacData->bytes, - // flacData->inData); + // ESP_LOGI(TAG, "in flac read cb %d %p", flacData->bytes, flacData->inData); if (flacData->bytes <= 0) { + free_flac_data(flacData); + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } if (flacData->inData == NULL) { + free_flac_data(flacData); + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } @@ -253,14 +282,18 @@ static FLAC__StreamDecoderReadStatus read_callback( // 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); + // ESP_LOGW(TAG, "dind't read all flac inData %d", *bytes); flacData->inData += *bytes; flacData->bytes -= *bytes; } + free_flac_data(flacData); + // xQueueSend (flacReadQHdl, &flacData, portMAX_DELAY); - xSemaphoreGive(decoderReadSemaphore); + // xSemaphoreGive(decoderReadSemaphore); + + // ESP_LOGE(TAG, "%s: data processed", __func__); return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } @@ -271,7 +304,7 @@ 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; + flacData_t *flacData = NULL; // = &flacOutData; snapcastSetting_t *scSet = (snapcastSetting_t *)client_data; int ret = 0; uint32_t tmpData; @@ -279,7 +312,7 @@ static FLAC__StreamDecoderWriteStatus write_callback( (void)decoder; - xSemaphoreTake(decoderWriteSemaphore, portMAX_DELAY); + // xSemaphoreTake(decoderWriteSemaphore, portMAX_DELAY); // xQueueReceive (flacReadQHdl, &flacData, portMAX_DELAY); @@ -309,6 +342,13 @@ static FLAC__StreamDecoderWriteStatus write_callback( return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } + flacData = (flacData_t *)malloc(sizeof(flacData_t)); + if (flacData == NULL) { + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + memset(flacData, 0, sizeof(flacData_t)); + flacData->bytes = frame->header.blocksize * frame->header.channels * (frame->header.bits_per_sample / 8); @@ -359,6 +399,8 @@ static FLAC__StreamDecoderWriteStatus write_callback( xQueueSend(decoderWriteQHdl, &flacData, portMAX_DELAY); + // ESP_LOGE(TAG, "%s: data processed", __func__); + // xSemaphoreGive(flacWriteSemaphore); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; @@ -367,7 +409,7 @@ static FLAC__StreamDecoderWriteStatus write_callback( void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { - flacData_t *flacData = &flacOutData; + flacData_t *flacData; // = &flacOutData; snapcastSetting_t *scSet = (snapcastSetting_t *)client_data; (void)decoder; @@ -377,12 +419,26 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { // ESP_LOGI(TAG, "in flac meta cb"); + flacData = (flacData_t *)malloc(sizeof(flacData_t)); + if (flacData == NULL) { + ESP_LOGE(TAG, "in flac meta cb, malloc failed"); + + return; + } + + memset(flacData, 0, sizeof(flacData_t)); + // 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; + ESP_LOGI(TAG, "fLaC sampleformat: %d:%d:%d", scSet->sr, scSet->bits, + scSet->ch); + xQueueSend(decoderWriteQHdl, &flacData, portMAX_DELAY); + + // ESP_LOGE(TAG, "%s: data processed", __func__); } // xSemaphoreGive(flacReadSemaphore); @@ -482,26 +538,34 @@ void flac_task(void *pvParameters) { // (uint64_t)currentTimestamp.sec * 1000000 + // (uint64_t)currentTimestamp.usec); - xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); + // xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); // send data to flac decoder + // ESP_LOGE(TAG, "%s: decoderReadQHdl start", __func__); + xQueueSend(decoderReadQHdl, &pFlacData, portMAX_DELAY); + + // ESP_LOGE(TAG, "%s: decoderReadQHdl done", __func__); // and wait until data was // processed - xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); + // xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY); // need to release mutex // afterwards for next round - xSemaphoreGive(decoderReadSemaphore); + // xSemaphoreGive(decoderReadSemaphore); - free(pFlacData->inData); - free(pFlacData); + // free(pFlacData->inData); + // free(pFlacData); } else { pcm_chunk_message_t *pcmData = NULL; - xSemaphoreGive(decoderWriteSemaphore); + // xSemaphoreGive(decoderWriteSemaphore); // and wait until it is done + // ESP_LOGE(TAG, "%s: decoderWriteQHdl start", __func__); + xQueueReceive(decoderWriteQHdl, &pFlacData, portMAX_DELAY); + // ESP_LOGE(TAG, "%s: decoderWriteQHdl done", __func__); + if (pFlacData->outData != NULL) { pcmData = pFlacData->outData; pcmData->timestamp = currentTimestamp; @@ -522,12 +586,39 @@ void flac_task(void *pvParameters) { } #if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow(500, scSet->sr, scSet->chkInFrames); + if (flow_drain_counter > 0) { + flow_drain_counter--; + double dynamic_vol = + ((double)scSet.volume / 100 / (20 - flow_drain_counter)); + if (flow_drain_counter == 0) { +#if SNAPCAST_USE_SOFT_VOL + dynamic_vol = 0; +#else + dynamic_vol = 1; +#endif + audio_hal_set_mute(board_handle->audio_hal, + server_settings_message.muted); + } + dsp_set_vol(dynamic_vol); + } + dsp_setup_flow(500, scSet.sr, scSet.chkInFrames); dsp_processor(pcmData->fragment->payload, pcmData->fragment->size, dspFlow); #endif insert_pcm_chunk(pcmData); + + if (pFlacData->inData) { + free(pFlacData->inData); + pFlacData->inData = NULL; + } + + if (pFlacData) { + free(pFlacData); + pFlacData = NULL; + } + } else { + free_flac_data(pFlacData); } } } @@ -556,7 +647,8 @@ static void http_get_task(void *pvParameters) { OpusDecoder *opusDecoder = NULL; codec_type_t codec = NONE; snapcastSetting_t scSet; - flacData_t flacData = {NULL, {0, 0}, NULL, 0}; + // flacData_t flacData = {SNAPCAST_MESSAGE_CODEC_HEADER, NULL, {0, 0}, NULL, + // 0}; flacData_t *pFlacData; pcm_chunk_message_t *pcmData = NULL; ip_addr_t remote_ip; @@ -808,7 +900,7 @@ static void http_get_task(void *pvParameters) { firstNetBuf = NULL; -#define TEST_DECODER_TASK 0 +#define TEST_DECODER_TASK 1 decoderWriteSemaphore = xSemaphoreCreateMutex(); xSemaphoreTake(decoderWriteSemaphore, portMAX_DELAY); @@ -1206,13 +1298,13 @@ static void http_get_task(void *pvParameters) { pFlacData = (flacData_t *)malloc(sizeof(flacData_t)); pFlacData->bytes = tmp; - pFlacData->timestamp = - wire_chnk.timestamp; // store timestamp for - // later use - pFlacData->inData = - (char *)malloc(tmp * sizeof(char)); + // store timestamp for + // later use + pFlacData->timestamp = wire_chnk.timestamp; + pFlacData->inData = (char *)malloc(tmp); memcpy(pFlacData->inData, start, tmp); pFlacData->outData = NULL; + pFlacData->type = SNAPCAST_MESSAGE_WIRE_CHUNK; // send data to seperate task which will handle this xQueueSend(flacTaskQHdl, &pFlacData, portMAX_DELAY); @@ -1400,8 +1492,12 @@ static void http_get_task(void *pvParameters) { pFlacData = NULL; // send NULL so we know to wait // for decoded data in task + // ESP_LOGE(TAG, "%s: flacTaskQHdl start + // wireChnk", __func__); xQueueSend(flacTaskQHdl, &pFlacData, portMAX_DELAY); + // ESP_LOGE(TAG, "%s: flacTaskQHdl stop wireChnk", + // __func__); #else xSemaphoreGive(decoderWriteSemaphore); // and wait until it is done @@ -1812,6 +1908,48 @@ static void http_get_task(void *pvParameters) { FLAC_DECODER_TASK_CORE_ID); } +#if TEST_DECODER_TASK + if (t_flac_task == NULL) { + xTaskCreatePinnedToCore( + &flac_task, "flac_task", 9 * 256, &scSet, + FLAC_TASK_PRIORITY, &t_flac_task, + FLAC_TASK_CORE_ID); + } + + pFlacData = (flacData_t *)malloc(sizeof(flacData_t)); + memset(pFlacData, 0, sizeof(flacData_t)); + + pFlacData->bytes = typedMsgLen; + pFlacData->inData = (char *)malloc(typedMsgLen); + memcpy(pFlacData->inData, tmp, typedMsgLen); + pFlacData->outData = NULL; + pFlacData->type = SNAPCAST_MESSAGE_CODEC_HEADER; + + // TODO: find a smarter way for + // this wait for task creation done + // maybe use task notification + while (flacTaskQHdl == NULL) { + vTaskDelay(10); + } + + // ESP_LOGE(TAG, "%s: flacTaskQHdl start codec + // header", __func__); + + // send codec header to flac decoder + xQueueSend(flacTaskQHdl, &pFlacData, portMAX_DELAY); + + // ESP_LOGE(TAG, "sent codec header"); + + // send NULL so we know to wait + // for decoded data in task + pFlacData = NULL; + xQueueSend(flacTaskQHdl, &pFlacData, portMAX_DELAY); + + // ESP_LOGE(TAG, "%s: flacTaskQHdl done codec header", + // __func__); + +#else + if (flacData.outData != NULL) { free(flacData.outData); flacData.outData = NULL; @@ -1844,13 +1982,6 @@ static void http_get_task(void *pvParameters) { ESP_LOGI(TAG, "fLaC sampleformat: %d:%d:%d", scSet.sr, scSet.bits, scSet.ch); -#if TEST_DECODER_TASK - if (t_flac_task == NULL) { - xTaskCreatePinnedToCore( - &flac_task, "flac_task", 9 * 256, &scSet, - FLAC_TASK_PRIORITY, &t_flac_task, - FLAC_TASK_CORE_ID); - } #endif } else if (codec == PCM) { memcpy(&channels, tmp + 22, sizeof(channels)); @@ -2098,7 +2229,7 @@ static void http_get_task(void *pvParameters) { } internalState++; - // no break + // fall through } case 5: { @@ -2336,7 +2467,8 @@ static void http_get_task(void *pvParameters) { player_latency_insert(tmpDiffToServer); - ESP_LOGI(TAG, "Current latency:%lld:", tmpDiffToServer); + // ESP_LOGI(TAG, "Current latency:%lld:", + // tmpDiffToServer); // store current time lastTimeSync = now;