@@ -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
|
||||
|
||||
|
||||
764
main/main.c
764
main/main.c
@@ -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(¤tTimestamp, &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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user