fix #54 for PCM

Signed-off-by: Karl Osterseher <karli_o@gmx.at>
This commit is contained in:
Karl Osterseher
2025-01-09 23:08:40 +01:00
Unverified
parent 3447855781
commit c2285846f4
2 changed files with 202 additions and 591 deletions

View File

@@ -148,18 +148,23 @@ static esp_err_t player_setup_i2s(i2s_port_t i2sNum,
const int __dmaBufMaxLen = 1024;
int __dmaBufCnt;
int __dmaBufLen;
int factor = 2;
__dmaBufCnt = 1;
__dmaBufLen = setting->chkInFrames;
while ((__dmaBufLen >= __dmaBufMaxLen) || (__dmaBufCnt <= 1)) {
if ((__dmaBufLen % 2) == 0) {
__dmaBufCnt *= 2;
__dmaBufLen /= 2;
if ((__dmaBufLen % factor) == 0) {
__dmaBufCnt *= factor;
__dmaBufLen /= factor;
} else {
ESP_LOGE(TAG,
"player_setup_i2s: Can't setup i2s with this configuration");
return -1;
factor++;
if ((__dmaBufLen / factor) == 0) {
ESP_LOGE(TAG,
"player_setup_i2s: Can't setup i2s with this configuration, "
"dma_buf_len is %d, dma_buf_count is %d",
__dmaBufLen, __dmaBufCnt);
return -1;
}
}
}
@@ -1333,14 +1338,16 @@ static void player_task(void *pvParameters) {
age = serverNow - chunkStart - buf_us + clientDacLatency_us;
#if USE_BIG_DMA_BUFFER && USE_SAMPLE_INSERTION
savedAge = age;
int divider = (scSet.chkInFrames / i2sDmaBufMaxLen);
if (insertedSamplesCounter > 0) {
age -= (((1 + insertedSamplesCounter / i2sDmaBufMaxLen) * chkDur_us /
2) -
divider) -
(insertedSamplesCounter * 1000000UL / scSet.sr));
} else if (insertedSamplesCounter < 0) {
age +=
(((-insertedSamplesCounter / i2sDmaBufMaxLen) * chkDur_us / 2) -
(-insertedSamplesCounter * 1000000UL / scSet.sr));
age += (((-insertedSamplesCounter / i2sDmaBufMaxLen) * chkDur_us /
divider) -
(-insertedSamplesCounter * 1000000UL / scSet.sr));
}
#endif

View File

@@ -74,40 +74,18 @@ static void error_callback(const FLAC__StreamDecoder *decoder,
FLAC__StreamDecoderErrorStatus status,
void *client_data);
// #include "ma120.h"
static FLAC__StreamDecoder *flacDecoder = NULL;
static QueueHandle_t decoderReadQHdl = NULL;
static QueueHandle_t decoderWriteQHdl = NULL;
static QueueHandle_t decoderTaskQHdl = NULL;
SemaphoreHandle_t decoderReadSemaphore = NULL;
SemaphoreHandle_t decoderWriteSemaphore = NULL;
const char *VERSION_STRING = "0.0.2";
const char *VERSION_STRING = "0.0.3";
#define HTTP_TASK_PRIORITY 9
#define HTTP_TASK_CORE_ID tskNO_AFFINITY // 1 // tskNO_AFFINITY
#define OTA_TASK_PRIORITY 6
#define OTA_TASK_CORE_ID tskNO_AFFINITY
// 1 // tskNO_AFFINITY
#define FLAC_DECODER_TASK_PRIORITY 7
#define FLAC_DECODER_TASK_CORE_ID tskNO_AFFINITY
// HTTP_TASK_CORE_ID // 1 // tskNO_AFFINITY
#define FLAC_TASK_PRIORITY 8
#define FLAC_TASK_CORE_ID tskNO_AFFINITY
#define OPUS_TASK_PRIORITY 8
#define OPUS_TASK_CORE_ID tskNO_AFFINITY
// 1 // tskNO_AFFINITY
TaskHandle_t t_ota_task = NULL;
TaskHandle_t t_http_get_task = NULL;
TaskHandle_t t_flac_decoder_task = NULL;
TaskHandle_t dec_task_handle = NULL;
#define FAST_SYNC_LATENCY_BUF 10000 // in µs
#define NORMAL_SYNC_LATENCY_BUF 1000000 // in µs
@@ -157,7 +135,7 @@ typedef struct decoderData_s {
void time_sync_msg_cb(void *args);
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,
.dispatch_method = ESP_TIMER_TASK,
@@ -266,26 +244,6 @@ void time_sync_msg_cb(void *args) {
// }
}
/**
*
*/
void free_flac_data(decoderData_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;
}
}
/**
*
*/
@@ -361,10 +319,8 @@ static FLAC__StreamDecoderWriteStatus write_callback(
const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
const FLAC__int32 *const buffer[], void *client_data) {
size_t i;
decoderData_t *flacData = NULL;
snapcastSetting_t *scSet = (snapcastSetting_t *)client_data;
int ret = 0;
uint32_t fragmentCnt = 0;
size_t bytes = frame->header.blocksize * frame->header.channels *
frame->header.bits_per_sample / 8;
@@ -374,10 +330,6 @@ static FLAC__StreamDecoderWriteStatus write_callback(
cachedBlocks += frame->header.blocksize;
}
// xSemaphoreTake(decoderWriteSemaphore, portMAX_DELAY);
// xQueueReceive (flacReadQHdl, &flacData, portMAX_DELAY);
// ESP_LOGI(TAG, "in flac write cb %ld %d, pcmChunk.bytes %ld",
// frame->header.blocksize, bytes, pcmChunk.bytes);
@@ -423,69 +375,6 @@ static FLAC__StreamDecoderWriteStatus write_callback(
scSet->chkInFrames = frame->header.blocksize;
// flacData = (decoderData_t *)malloc(sizeof(decoderData_t));
// if (flacData == NULL) {
// return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
// }
//
// memset(flacData, 0, sizeof(decoderData_t));
//
// flacData->bytes = frame->header.blocksize * frame->header.channels *
// (frame->header.bits_per_sample / 8);
//
// ret = allocate_pcm_chunk_memory(&(flacData->outData), flacData->bytes);
//
//// ESP_LOGW (TAG, "block size: %ld", frame->header.blocksize);
//
// // 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 (fragment->payload != NULL) {
// 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);
//
// // TODO: for now fragmented payload is not supported and the whole
// // chunk is expected to be in the first fragment
// uint32_t tmpData;
// 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) {
// volatile uint32_t *test =
// (volatile uint32_t *)(&(fragment->payload[fragmentCnt]));
// *test = (volatile uint32_t)tmpData;
// }
//
// fragmentCnt += 4;
// if (fragmentCnt >= fragment->size) {
// fragmentCnt = 0;
//
// fragment = fragment->nextFragment;
// }
// }
// }
// }
// else {
// flacData->outData = NULL;
// }
// xQueueSend(decoderWriteQHdl, &flacData, portMAX_DELAY);
// ESP_LOGE(TAG, "%s: data processed", __func__);
// xSemaphoreGive(flacWriteSemaphore);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
@@ -495,25 +384,13 @@ static FLAC__StreamDecoderWriteStatus write_callback(
void metadata_callback(const FLAC__StreamDecoder *decoder,
const FLAC__StreamMetadata *metadata,
void *client_data) {
decoderData_t *flacData; // = &flacOutData;
snapcastSetting_t *scSet = (snapcastSetting_t *)client_data;
(void)decoder;
// xQueueReceive (flacReadQHdl, &flacData, portMAX_DELAY);
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
// ESP_LOGI(TAG, "in flac meta cb");
// flacData = (decoderData_t *)malloc(sizeof(decoderData_t));
// if (flacData == NULL) {
// ESP_LOGE(TAG, "in flac meta cb, malloc failed");
//
// return;
// }
//
// memset(flacData, 0, sizeof(decoderData_t));
// save for later
scSet->sr = metadata->data.stream_info.sample_rate;
scSet->ch = metadata->data.stream_info.channels;
@@ -522,12 +399,8 @@ void metadata_callback(const FLAC__StreamDecoder *decoder,
ESP_LOGI(TAG, "fLaC sampleformat: %ld:%d:%d", scSet->sr, scSet->bits,
scSet->ch);
// xQueueSend(decoderWriteQHdl, &flacData, portMAX_DELAY);
// ESP_LOGE(TAG, "%s: data processed", __func__);
}
// xSemaphoreGive(flacReadSemaphore);
}
/**
@@ -541,43 +414,6 @@ void error_callback(const FLAC__StreamDecoder *decoder,
FLAC__StreamDecoderErrorStatusString[status]);
}
/**
*
*/
static void flac_decoder_task(void *pvParameters) {
// FLAC__bool ok = true;
FLAC__StreamDecoderInitStatus init_status;
snapcastSetting_t *scSet = (snapcastSetting_t *)pvParameters;
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;
}
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;
}
while (1) {
FLAC__stream_decoder_process_until_end_of_stream(flacDecoder);
}
}
/*
* Add one timeval to another.
*/
@@ -594,323 +430,6 @@ tv_t timeval_add(tv_t *a, tv_t *b) {
return result;
} // timeval_add
/**
*
*/
void flac_task(void *pvParameters) {
tv_t currentTimestamp;
decoderData_t *pFlacData = NULL;
snapcastSetting_t *scSet = (snapcastSetting_t *)pvParameters;
FLAC__StreamDecoderInitStatus init_status;
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;
}
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;
}
while (1) {
xQueueReceive(decoderTaskQHdl, &pFlacData,
portMAX_DELAY); // get data from http task
if (pFlacData != NULL) {
currentTimestamp = pFlacData->timestamp;
// ESP_LOGE(TAG, "Got data with length %ld", pFlacData->bytes);
// ESP_LOGE(TAG, "1");
// ESP_LOGE(TAG, "Got timestamp %lld",
// (uint64_t)currentTimestamp.sec * 1000000 +
// (uint64_t)currentTimestamp.usec);
// xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY);
// send data to flac decoder
// ESP_LOGE(TAG, "%s: decoderReadQHdl start", __func__);
xQueueSend(decoderReadQHdl, &pFlacData, portMAX_DELAY);
// ESP_LOGE(TAG, "2");
// ESP_LOGE(TAG, "%s: decoderReadQHdl done", __func__);
// and wait until data was
// processed
// xSemaphoreTake(decoderReadSemaphore, portMAX_DELAY);
// need to release mutex
// afterwards for next round
// xSemaphoreGive(decoderReadSemaphore);
// free(pFlacData->inData);
// free(pFlacData);
// }
// else
// {
uint64_t frameCounter = 0;
if (FLAC__stream_decoder_process_until_end_of_stream(flacDecoder) ==
false) {
// if (FLAC__stream_decoder_process_single(flacDecoder) == false) {
ESP_LOGE(TAG, "%s: decoder error", __func__);
}
// else {
// ESP_LOGW(TAG, "%s: decoder done", __func__);
//}
while (xQueueReceive(decoderWriteQHdl, &pFlacData, pdMS_TO_TICKS(10))) {
pcm_chunk_message_t *pcmData = NULL;
// ESP_LOGE(TAG, "3");
if (pFlacData->outData != NULL) {
pcmData = pFlacData->outData;
size_t decodedSize = pcmData->totalSize; // pFlacData->bytes;
scSet->chkInFrames =
decodedSize / ((size_t)scSet->ch * (size_t)(scSet->bits / 8));
tv_t chunkDuration = {
.sec = 0,
.usec =
(frameCounter * 1000000ULL * (uint64_t)scSet->chkInFrames) /
scSet->sr,
};
pcmData->timestamp = currentTimestamp =
timeval_add(&currentTimestamp, &chunkDuration);
frameCounter++;
// ESP_LOGI(TAG, "%s: got one frame of size %ld, timestamp %ld.%ld",
// __func__, scSet->chkInFrames, currentTimestamp.sec,
// currentTimestamp.usec);
// ESP_LOGW(TAG, "got FLAC decoded chunk size: %ld frames",
// scSet->chkInFrames);
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_processor_worker(pcmData->fragment->payload,
pcmData->fragment->size, scSet->sr);
#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);
}
}
}
// else {
// pcm_chunk_message_t *pcmData = NULL;
//
// // 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;
//
// size_t decodedSize = pcmData->totalSize; // pFlacData->bytes;
// scSet->chkInFrames =
// decodedSize / ((size_t)scSet->ch * (size_t)(scSet->bits / 8));
//
// ESP_LOGW(TAG, "got FLAC decoded chunk size: %ld frames",
// scSet->chkInFrames);
//
// 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_processor_worker(pcmData->fragment->payload,
// pcmData->fragment->size, scSet->sr);
// #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);
// }
// }
}
}
/**
*
*/
void opus_decoder_task(void *pvParameters) {
tv_t currentTimestamp;
decoderData_t *pOpusData = NULL;
snapcastSetting_t *scSet = (snapcastSetting_t *)pvParameters;
while (1) {
// get data from tcp task
xQueueReceive(decoderTaskQHdl, &pOpusData, portMAX_DELAY);
if (pOpusData) {
currentTimestamp = pOpusData->timestamp;
// ESP_LOGE(TAG, "%s: Got timestamp %lld", __func__,
// (uint64_t)currentTimestamp.sec *
// 1000000 +
// (uint64_t)currentTimestamp.usec);
if (pOpusData->inData) {
int frame_size = 0;
int sample_count = 0;
int samples_per_frame = 0;
int frame_count;
opus_int16 *audio;
samples_per_frame =
opus_packet_get_samples_per_frame(pOpusData->inData, scSet->sr);
if (samples_per_frame < 0) {
ESP_LOGE(TAG,
"couldn't get samples per frame count "
"of packet");
}
scSet->chkInFrames = samples_per_frame;
ESP_LOGW(TAG, "got OPUS decoded chunk size: %ld frames",
scSet->chkInFrames);
size_t bytes = samples_per_frame * scSet->ch * scSet->bits / 8;
if (samples_per_frame > 480) {
ESP_LOGE(TAG, "samples_per_frame: %d, pOpusData->bytes %ld, bytes %u",
samples_per_frame, pOpusData->bytes, bytes);
}
// TODO: insert some break condition if we wait
// too long
while ((audio = (opus_int16 *)malloc(bytes)) == NULL) {
ESP_LOGE(TAG, "couldn't get memory for audio");
vTaskDelay(pdMS_TO_TICKS(1));
}
frame_size =
opus_decode(opusDecoder, pOpusData->inData, pOpusData->bytes,
(opus_int16 *)audio, samples_per_frame, 0);
free(pOpusData->inData);
pOpusData->inData = NULL;
if (frame_size < 0) {
ESP_LOGE(TAG, "Decode error : %d \n", frame_size);
} else {
pcm_chunk_message_t *pcmData = NULL;
bytes = frame_size * scSet->ch * scSet->bits / 8;
if (allocate_pcm_chunk_memory(&pcmData, bytes) < 0) {
pcmData = NULL;
} else {
pcmData->timestamp = currentTimestamp;
if (pcmData->fragment->payload) {
volatile uint32_t *sample;
uint32_t tmpData;
uint32_t cnt = 0;
for (int i = 0; i < bytes; i += 4) {
sample =
(volatile uint32_t *)(&(pcmData->fragment->payload[i]));
tmpData = (((uint32_t)audio[cnt] << 16) & 0xFFFF0000) |
(((uint32_t)audio[cnt + 1] << 0) & 0x0000FFFF);
*sample = (volatile uint32_t)tmpData;
cnt += 2;
}
}
free(audio);
audio = NULL;
}
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_processor_worker(pcmData->fragment->payload,
pcmData->fragment->size, scSet->sr);
#endif
insert_pcm_chunk(pcmData);
}
}
free(pOpusData);
pOpusData = NULL;
}
}
}
/**
*
*/
@@ -945,11 +464,7 @@ static void http_get_task(void *pvParameters) {
mdns_result_t *r;
codec_type_t codec = NONE;
snapcastSetting_t scSet;
// flacData_t flacData = {SNAPCAST_MESSAGE_CODEC_HEADER, NULL, {0, 0}, NULL,
// 0};
decoderData_t *pDecData = NULL;
pcm_chunk_message_t *pcmData = NULL;
uint8_t *opusData = NULL;
ip_addr_t remote_ip;
uint16_t remotePort = 0;
int rc1 = ERR_OK, rc2 = ERR_OK;
@@ -984,37 +499,12 @@ static void http_get_task(void *pvParameters) {
opusDecoder = NULL;
}
// if (t_flac_decoder_task != NULL) {
// vTaskDelete(t_flac_decoder_task);
// t_flac_decoder_task = NULL;
// }
if (dec_task_handle != NULL) {
vTaskDelete(dec_task_handle);
dec_task_handle = 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 (decoderTaskQHdl != NULL) {
vQueueDelete(decoderTaskQHdl);
decoderTaskQHdl = NULL;
}
#if SNAPCAST_SERVER_USE_MDNS
// Find snapcast server
// Connect to first snapcast server found
@@ -1187,8 +677,6 @@ static void http_get_task(void *pvParameters) {
uint32_t tmpData = 0;
int32_t payloadDataShift = 0;
int16_t pcm_size = 120;
#define BASE_MESSAGE_STATE 0
#define TYPED_MESSAGE_STATE 1
@@ -1564,6 +1052,7 @@ static void http_get_task(void *pvParameters) {
internalState++;
// TODO: we could use wire chunk directly maybe?
decoderChunk.bytes = wire_chnk.size;
while (!decoderChunk.inData) {
decoderChunk.inData =
@@ -1596,58 +1085,83 @@ static void http_get_task(void *pvParameters) {
if (received_header == true) {
switch (codec) {
case OPUS: {
if (opusData == NULL) {
// TODO: insert some break condition if we wait
// too long
while ((opusData = (uint8_t *)malloc(
wire_chnk.size)) == NULL) {
ESP_LOGE(TAG, "couldn't memory for opusData");
vTaskDelay(pdMS_TO_TICKS(1));
}
payloadOffset = 0;
}
memcpy(&opusData[payloadOffset], start, tmp_size);
payloadOffset += tmp_size;
// case OPUS: {
// if (opusData == NULL)
// {
// // TODO: insert some
// break condition if
// we wait
// // too long
// while ((opusData =
// (uint8_t *)malloc(
// wire_chnk.size))
// == NULL)
// {
// ESP_LOGE(TAG,
// "couldn't memory
// for opusData");
//
// vTaskDelay(pdMS_TO_TICKS(1));
// }
//
// payloadOffset = 0;
// }
//
// memcpy(&opusData[payloadOffset],
// start, tmp_size);
// payloadOffset +=
// tmp_size;
//
// //
// ESP_LOGE(TAG,"payloadOffset
// %d, wire_chnk.size
// %d", payloadOffset,
// wire_chnk.size);
if (payloadOffset >= wire_chnk.size) {
pDecData = NULL;
while (!pDecData) {
pDecData = (decoderData_t *)malloc(
sizeof(decoderData_t));
if (!pDecData) {
vTaskDelay(pdMS_TO_TICKS(1));
}
}
// store timestamp for
// later use
pDecData->timestamp = wire_chnk.timestamp;
pDecData->inData = opusData;
pDecData->bytes = wire_chnk.size;
pDecData->outData = NULL;
pDecData->type = SNAPCAST_MESSAGE_WIRE_CHUNK;
// send data to separate task which will handle
// this
xQueueSend(decoderTaskQHdl, &pDecData,
portMAX_DELAY);
opusData = NULL;
pDecData = NULL;
}
break;
}
// // %d, wire_chnk.size
// // %d", payloadOffset,
// // wire_chnk.size);
//
// if (payloadOffset >=
// wire_chnk.size) {
// pDecData = NULL;
// while (!pDecData) {
// pDecData =
// (decoderData_t
// *)malloc(
// sizeof(decoderData_t));
// if (!pDecData) {
// vTaskDelay(pdMS_TO_TICKS(1));
// }
// }
//
// // store timestamp
// for
// // later use
// pDecData->timestamp
// =
// wire_chnk.timestamp;
// pDecData->inData =
// opusData;
// pDecData->bytes =
// wire_chnk.size;
// pDecData->outData =
// NULL; pDecData->type
// =
// SNAPCAST_MESSAGE_WIRE_CHUNK;
//
// // send data to
// separate task which
// will handle
// // this
// xQueueSend(decoderTaskQHdl,
// &pDecData,
// portMAX_DELAY);
//
// opusData = NULL;
// pDecData = NULL;
// }
//
// break;
// }
case OPUS:
case FLAC: {
memcpy(&decoderChunk.inData[payloadOffset], start,
tmp_size);
@@ -1738,7 +1252,104 @@ static void http_get_task(void *pvParameters) {
if (received_header == true) {
switch (codec) {
case OPUS: {
// nothing to do here
int frame_size = 0;
int samples_per_frame = 0;
opus_int16 *audio;
samples_per_frame =
opus_packet_get_samples_per_frame(
decoderChunk.inData, scSet.sr);
if (samples_per_frame < 0) {
ESP_LOGE(TAG,
"couldn't get samples per frame count "
"of packet");
}
scSet.chkInFrames = samples_per_frame;
// ESP_LOGW(TAG, "got OPUS decoded chunk size: %ld
// frames from encoded chunk with size %d",
// scSet.chkInFrames, wire_chnk.size);
size_t bytes =
samples_per_frame * scSet.ch * scSet.bits / 8;
// TODO: insert some break condition if we wait
// too long
while ((audio = (opus_int16 *)malloc(bytes)) ==
NULL) {
ESP_LOGE(TAG,
"couldn't get memory for OPUS audio");
vTaskDelay(pdMS_TO_TICKS(1));
}
frame_size = opus_decode(
opusDecoder, decoderChunk.inData,
decoderChunk.bytes, (opus_int16 *)audio,
samples_per_frame, 0);
free(decoderChunk.inData);
decoderChunk.inData = NULL;
if (frame_size < 0) {
ESP_LOGE(TAG, "Decode error : %d \n",
frame_size);
} else {
pcm_chunk_message_t *new_pcmChunk = NULL;
bytes = frame_size * scSet.ch * scSet.bits / 8;
if (allocate_pcm_chunk_memory(&new_pcmChunk,
bytes) < 0) {
pcmData = NULL;
} else {
new_pcmChunk->timestamp = wire_chnk.timestamp;
if (new_pcmChunk->fragment->payload) {
volatile uint32_t *sample;
uint32_t tmpData;
uint32_t cnt = 0;
for (int i = 0; i < bytes; i += 4) {
sample = (volatile uint32_t *)(&(
new_pcmChunk->fragment->payload[i]));
tmpData =
(((uint32_t)audio[cnt] << 16) &
0xFFFF0000) |
(((uint32_t)audio[cnt + 1] << 0) &
0x0000FFFF);
*sample = (volatile uint32_t)tmpData;
cnt += 2;
}
}
free(audio);
audio = NULL;
#if CONFIG_USE_DSP_PROCESSOR
if (new_pcmChunk->fragment->payload) {
dsp_processor_worker(
new_pcmChunk->fragment->payload,
new_pcmChunk->fragment->size, scSet.sr);
}
#endif
insert_pcm_chunk(new_pcmChunk);
}
if (player_send_snapcast_setting(&scSet) !=
pdPASS) {
ESP_LOGE(TAG,
"Failed to notify "
"sync task about "
"codec. Did you "
"init player?");
return;
}
}
break;
}
@@ -1829,10 +1440,10 @@ static void http_get_task(void *pvParameters) {
new_pcmChunk->timestamp = wire_chnk.timestamp;
#if CONFIG_USE_DSP_PROCESSOR
if (new_pcmChunk.fragment->payload) {
if (new_pcmChunk->fragment->payload) {
dsp_processor_worker(
new_pcmChunk.fragment->payload,
new_pcmChunk.fragment->size, scSet.sr);
new_pcmChunk->fragment->payload,
new_pcmChunk->fragment->size, scSet.sr);
}
#endif
@@ -1875,9 +1486,9 @@ static void http_get_task(void *pvParameters) {
decodedSize /
((size_t)scSet.ch * (size_t)(scSet.bits / 8));
ESP_LOGW(TAG,
"got PCM decoded chunk size: %ld frames",
scSet.chkInFrames);
// ESP_LOGW(TAG,
// "got PCM decoded chunk size: %ld
// frames", scSet.chkInFrames);
if (player_send_snapcast_setting(&scSet) !=
pdPASS) {
@@ -2194,13 +1805,6 @@ static void http_get_task(void *pvParameters) {
}
ESP_LOGI(TAG, "Initialized opus Decoder: %d", error);
if (dec_task_handle == NULL) {
xTaskCreatePinnedToCore(
&opus_decoder_task, "opus_task", 8 * 1024,
&scSet, OPUS_TASK_PRIORITY, &dec_task_handle,
OPUS_TASK_CORE_ID);
}
} else if (codec == FLAC) {
decoderChunk.bytes = typedMsgLen;
decoderChunk.inData =
@@ -2962,7 +2566,7 @@ void app_main(void) {
xTaskCreatePinnedToCore(&ota_server_task, "ota", 14 * 256, NULL,
OTA_TASK_PRIORITY, &t_ota_task, OTA_TASK_CORE_ID);
xTaskCreatePinnedToCore(&http_get_task, "http", 4 * 1024, NULL,
xTaskCreatePinnedToCore(&http_get_task, "http", 15 * 1024, NULL,
HTTP_TASK_PRIORITY, &t_http_get_task,
HTTP_TASK_CORE_ID);