From 02206b21fb18a0a2a11bfe27525f2a09806d6aa9 Mon Sep 17 00:00:00 2001 From: Karl Osterseher Date: Wed, 14 Dec 2022 22:52:57 +0100 Subject: [PATCH] add support for sample rates different to 48kHz (#15) - instead of storing chunk duration in ms store the frame count and do calculations based on that - add updated snapserver.conf for reference (#17) - some code clean up - move Kconfig entries to correct place - remove unnecessary Kconfig entries - add necessary dependencies in Kconfig files Signed-off-by: Karl Osterseher --- components/dsp_processor/Kconfig.projbuild | 32 +- components/dsp_processor/dsp_processor.c | 549 ++++++++---------- .../dsp_processor/include/dsp_processor.h | 2 +- components/lightsnapcast/include/player.h | 2 +- components/lightsnapcast/player.c | 70 +-- main/Kconfig.projbuild | 33 -- main/main.c | 32 +- sdkconfig | 86 +-- sdkconfig.old | 99 +++- snapcast/snapserver.conf | 90 ++- 10 files changed, 466 insertions(+), 529 deletions(-) diff --git a/components/dsp_processor/Kconfig.projbuild b/components/dsp_processor/Kconfig.projbuild index b3c01f3..68a66e5 100644 --- a/components/dsp_processor/Kconfig.projbuild +++ b/components/dsp_processor/Kconfig.projbuild @@ -1,23 +1,41 @@ # Config file for ESP32 DSP Processor menu "ESP32 audio buffer and I2S config" - config USE_PSRAM - bool "Use PSRAM" - default true - depends on ESP32_SPIRAM_SUPPORT - help - Need wrover class modules with large SPRAM to have buffers >1s and chunks >20ms for Snapcast network delay - config USE_DSP_PROCESSOR bool "enable signal processing on audio data" default false help enable audio filtering before queueing it to player component + choice SNAPCLIENT_DSP_FLOW + prompt "DSP flow" + default SNAPCLIENT_DSP_FLOW_STEREO + depends on USE_DSP_PROCESSOR + help + Select the DSP flow to use. + + config SNAPCLIENT_DSP_FLOW_STEREO + bool "Stereo flow" + + config SNAPCLIENT_DSP_FLOW_BASSBOOST + bool "Bassboost flow" + + config SNAPCLIENT_DSP_FLOW_BIAMP + bool "Bi-Amp flow" + endchoice + config USE_BIQUAD_ASM bool "Use uptimized asm version of Biquad_f32" default true + depends on USE_DSP_PROCESSOR help Asm version 2 x speed on ESP32 - not working on ESP32-S2 + config SNAPCLIENT_USE_SOFT_VOL + bool "Use software volume" + default false + depends on USE_DSP_PROCESSOR + help + Use software volume mixer instead of hardware mixer. + endmenu diff --git a/components/dsp_processor/dsp_processor.c b/components/dsp_processor/dsp_processor.c index 052e38a..c48e50a 100644 --- a/components/dsp_processor/dsp_processor.c +++ b/components/dsp_processor/dsp_processor.c @@ -33,211 +33,185 @@ static float *sbufout0 = NULL; static float *sbuftmp0 = NULL; static uint32_t currentSamplerate = 0; -static uint32_t currentChunkDurationMs = 0; +static uint32_t currentChunkInFrames = 0; static ptype_t bq[8]; static double dynamic_vol = 1.0; -int -dsp_processor (char *audio, size_t chunk_size, dspFlows_t dspFlow) -{ +int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) { int16_t len = chunk_size / 4; int16_t valint; uint16_t i; - volatile uint32_t *audio_tmp = (uint32_t *)audio; //volatile needed to ensure 32 bit access + volatile uint32_t *audio_tmp = + (uint32_t *)audio; // volatile needed to ensure 32 bit access - if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) - { - ESP_LOGE (TAG, "No Memory allocated for dsp_processor %p %p %p", - sbuffer0, sbufout0, sbuftmp0); + if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) { + ESP_LOGE(TAG, "No Memory allocated for dsp_processor %p %p %p", sbuffer0, + sbufout0, sbuftmp0); - return -1; - } + return -1; + } - switch (dspFlow) - { - case dspfStereo: - { - //set volume - if (dynamic_vol != 1.0) - { - for (i = 0; i < len; i++) - { - audio_tmp[i] = ((uint32_t) (dynamic_vol - * ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16)))) << 16) - + (uint32_t) (dynamic_vol - * ((float)((int16_t)(audio_tmp[i] & 0xFFFF)))); - } - } + switch (dspFlow) { + case dspfStereo: { + // set volume + if (dynamic_vol != 1.0) { + for (i = 0; i < len; i++) { + audio_tmp[i] = + ((uint32_t)( + dynamic_vol * + ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16)))) + << 16) + + (uint32_t)(dynamic_vol * + ((float)((int16_t)(audio_tmp[i] & 0xFFFF)))); + } } - break; + } break; - case dspfBassBoost: - { // CH0 low shelf 6dB @ 400Hz - // channel 0 - for (i = 0; i < len; i++) - { - sbuffer0[i] = dynamic_vol * 0.5 - * ((float)((int16_t)(audio_tmp[i] & 0xFFFF))) - / 32768; - } - BIQUAD (sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w); - - for (i = 0; i < len; i++) - { - valint = (int16_t) (sbufout0[i] * 32768); - audio_tmp[i] = (audio_tmp[i]&0xFFFF0000) + (uint32_t)valint; - } - - // channel 1 - for (i = 0; i < len; i++) - { - sbuffer0[i] = dynamic_vol * 0.5 - * ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))) - / 32768; - } - BIQUAD (sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w); - - for (i = 0; i < len; i++) - { - valint = (int16_t) (sbufout0[i] * 32768); - audio_tmp[i] = (audio_tmp[i]&0xFFFF) + ((uint32_t)valint << 16); - } + case dspfBassBoost: { // CH0 low shelf 6dB @ 400Hz + // channel 0 + for (i = 0; i < len; i++) { + sbuffer0[i] = dynamic_vol * 0.5 * + ((float)((int16_t)(audio_tmp[i] & 0xFFFF))) / 32768; } - break; + BIQUAD(sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w); - case dspfBiamp: - { - // Process audio ch0 LOW PASS FILTER - for (i = 0; i < len; i++) - { - sbuffer0[i] = dynamic_vol * 0.5 - * ((float)((int16_t)(audio_tmp[i] & 0xFFFF))) - / 32768; - } - BIQUAD (sbuffer0, sbuftmp0, len, bq[0].coeffs, bq[0].w); - BIQUAD (sbuftmp0, sbufout0, len, bq[1].coeffs, bq[1].w); - - for (i = 0; i < len; i++) - { - valint = (int16_t) (sbufout0[i] * 32768); - audio_tmp[i] = (audio_tmp[i]&0xFFFF0000) + (uint32_t)valint; - } - - // Process audio ch1 HIGH PASS FILTER - for (i = 0; i < len; i++) - { - sbuffer0[i] = dynamic_vol * 0.5 - * ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))) - / 32768; - } - BIQUAD (sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w); - BIQUAD (sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w); - - for (i = 0; i < len; i++) - { - valint = (int16_t) (sbufout0[i] * 32768); - audio_tmp[i] = (audio_tmp[i]&0xFFFF) + ((uint32_t)valint << 16); - } + for (i = 0; i < len; i++) { + valint = (int16_t)(sbufout0[i] * 32768); + audio_tmp[i] = (audio_tmp[i] & 0xFFFF0000) + (uint32_t)valint; } - break; - case dspf2DOT1: - { // Process audio L + R LOW PASS FILTER - /* - BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w); - BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w); - - // Process audio L HIGH PASS FILTER - BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w); - BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w); - - // Process audio R HIGH PASS FILTER - BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w); - BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w); - - int16_t valint[5]; - for (uint16_t i = 0; i < len; i++) { - valint[0] = - (muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * - 32768); valint[1] = (muteCH[1] == 1) ? (int16_t)0 : - (int16_t)(sbufout1[i] * 32768); valint[2] = (muteCH[2] == 1) ? - (int16_t)0 : (int16_t)(sbufout2[i] * 32768); dsp_audio[i * 4 + 0] = - (valint[2] & 0xff); dsp_audio[i * 4 + 1] = ((valint[2] & 0xff00) >> - 8); dsp_audio[i * 4 + 2] = 0; dsp_audio[i * 4 + 3] = 0; - - dsp_audio1[i * 4 + 0] = (valint[0] & 0xff); - dsp_audio1[i * 4 + 1] = ((valint[0] & 0xff00) >> 8); - dsp_audio1[i * 4 + 2] = (valint[1] & 0xff); - dsp_audio1[i * 4 + 3] = ((valint[1] & 0xff00) >> 8); - } - - // TODO: this copy could be avoided if dsp_audio buffers are - // allocated dynamically and pointers are exchanged after - // audio was freed - memcpy(audio, dsp_audio, chunk_size); - - ESP_LOGW(TAG, "Don't know what to do with dsp_audio1"); - */ - ESP_LOGW (TAG, "dspf2DOT1, not implemented yet, using stereo instead"); + // channel 1 + for (i = 0; i < len; i++) { + sbuffer0[i] = dynamic_vol * 0.5 * + ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))) / + 32768; } - break; + BIQUAD(sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w); - case dspfFunkyHonda: - { // Process audio L + R LOW PASS FILTER - /* - BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w); - BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w); - - // Process audio L HIGH PASS FILTER - BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w); - BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w); - - // Process audio R HIGH PASS FILTER - BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w); - BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w); - - uint16_t scale = 16384; // 32768 - int16_t valint[5]; - for (uint16_t i = 0; i < len; i++) { - valint[0] = - (muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * scale); - valint[1] = - (muteCH[1] == 1) ? (int16_t)0 : (int16_t)(sbufout1[i] * scale); - valint[2] = - (muteCH[2] == 1) ? (int16_t)0 : (int16_t)(sbufout2[i] * scale); - valint[3] = valint[0] + valint[2]; - valint[4] = -valint[2]; - valint[5] = -valint[1] - valint[2]; - dsp_audio[i * 4 + 0] = (valint[3] & 0xff); - dsp_audio[i * 4 + 1] = ((valint[3] & 0xff00) >> 8); - dsp_audio[i * 4 + 2] = (valint[2] & 0xff); - dsp_audio[i * 4 + 3] = ((valint[2] & 0xff00) >> 8); - - dsp_audio1[i * 4 + 0] = (valint[4] & 0xff); - dsp_audio1[i * 4 + 1] = ((valint[4] & 0xff00) >> 8); - dsp_audio1[i * 4 + 2] = (valint[5] & 0xff); - dsp_audio1[i * 4 + 3] = ((valint[5] & 0xff00) >> 8); - } - - // TODO: this copy could be avoided if dsp_audio buffers are - // allocated dynamically and pointers are exchanged after - // audio was freed - memcpy(audio, dsp_audio, chunk_size); - - ESP_LOGW(TAG, "Don't know what to do with dsp_audio1"); - */ - ESP_LOGW (TAG, - "dspfFunkyHonda, not implemented yet, using stereo instead"); + for (i = 0; i < len; i++) { + valint = (int16_t)(sbufout0[i] * 32768); + audio_tmp[i] = (audio_tmp[i] & 0xFFFF) + ((uint32_t)valint << 16); } - break; + } break; - default: - { + case dspfBiamp: { + // Process audio ch0 LOW PASS FILTER + for (i = 0; i < len; i++) { + sbuffer0[i] = dynamic_vol * 0.5 * + ((float)((int16_t)(audio_tmp[i] & 0xFFFF))) / 32768; } - break; - } + BIQUAD(sbuffer0, sbuftmp0, len, bq[0].coeffs, bq[0].w); + BIQUAD(sbuftmp0, sbufout0, len, bq[1].coeffs, bq[1].w); + + for (i = 0; i < len; i++) { + valint = (int16_t)(sbufout0[i] * 32768); + audio_tmp[i] = (audio_tmp[i] & 0xFFFF0000) + (uint32_t)valint; + } + + // Process audio ch1 HIGH PASS FILTER + for (i = 0; i < len; i++) { + sbuffer0[i] = dynamic_vol * 0.5 * + ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))) / + 32768; + } + BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w); + BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w); + + for (i = 0; i < len; i++) { + valint = (int16_t)(sbufout0[i] * 32768); + audio_tmp[i] = (audio_tmp[i] & 0xFFFF) + ((uint32_t)valint << 16); + } + } break; + + case dspf2DOT1: { // Process audio L + R LOW PASS FILTER + /* + BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w); + BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w); + + // Process audio L HIGH PASS FILTER + BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w); + BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w); + + // Process audio R HIGH PASS FILTER + BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w); + BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w); + + int16_t valint[5]; + for (uint16_t i = 0; i < len; i++) { + valint[0] = + (muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * + 32768); valint[1] = (muteCH[1] == 1) ? (int16_t)0 : + (int16_t)(sbufout1[i] * 32768); valint[2] = (muteCH[2] == 1) ? + (int16_t)0 : (int16_t)(sbufout2[i] * 32768); dsp_audio[i * 4 + 0] = + (valint[2] & 0xff); dsp_audio[i * 4 + 1] = ((valint[2] & 0xff00) >> + 8); dsp_audio[i * 4 + 2] = 0; dsp_audio[i * 4 + 3] = 0; + + dsp_audio1[i * 4 + 0] = (valint[0] & 0xff); + dsp_audio1[i * 4 + 1] = ((valint[0] & 0xff00) >> 8); + dsp_audio1[i * 4 + 2] = (valint[1] & 0xff); + dsp_audio1[i * 4 + 3] = ((valint[1] & 0xff00) >> 8); + } + + // TODO: this copy could be avoided if dsp_audio buffers are + // allocated dynamically and pointers are exchanged after + // audio was freed + memcpy(audio, dsp_audio, chunk_size); + + ESP_LOGW(TAG, "Don't know what to do with dsp_audio1"); + */ + ESP_LOGW(TAG, "dspf2DOT1, not implemented yet, using stereo instead"); + } break; + + case dspfFunkyHonda: { // Process audio L + R LOW PASS FILTER + /* + BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w); + BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w); + + // Process audio L HIGH PASS FILTER + BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w); + BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w); + + // Process audio R HIGH PASS FILTER + BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w); + BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w); + + uint16_t scale = 16384; // 32768 + int16_t valint[5]; + for (uint16_t i = 0; i < len; i++) { + valint[0] = + (muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * scale); + valint[1] = + (muteCH[1] == 1) ? (int16_t)0 : (int16_t)(sbufout1[i] * scale); + valint[2] = + (muteCH[2] == 1) ? (int16_t)0 : (int16_t)(sbufout2[i] * scale); + valint[3] = valint[0] + valint[2]; + valint[4] = -valint[2]; + valint[5] = -valint[1] - valint[2]; + dsp_audio[i * 4 + 0] = (valint[3] & 0xff); + dsp_audio[i * 4 + 1] = ((valint[3] & 0xff00) >> 8); + dsp_audio[i * 4 + 2] = (valint[2] & 0xff); + dsp_audio[i * 4 + 3] = ((valint[2] & 0xff00) >> 8); + + dsp_audio1[i * 4 + 0] = (valint[4] & 0xff); + dsp_audio1[i * 4 + 1] = ((valint[4] & 0xff00) >> 8); + dsp_audio1[i * 4 + 2] = (valint[5] & 0xff); + dsp_audio1[i * 4 + 3] = ((valint[5] & 0xff00) >> 8); + } + + // TODO: this copy could be avoided if dsp_audio buffers are + // allocated dynamically and pointers are exchanged after + // audio was freed + memcpy(audio, dsp_audio, chunk_size); + + ESP_LOGW(TAG, "Don't know what to do with dsp_audio1"); + */ + ESP_LOGW(TAG, + "dspfFunkyHonda, not implemented yet, using stereo instead"); + } break; + + default: { } break; } return 0; } @@ -256,144 +230,115 @@ dsp_processor (char *audio, size_t chunk_size, dspFlows_t dspFlow) // ---------------------------------------- // Fixed 2x2 biquad flow Xover for biAmp systems // Interface for cross over frequency and level -void -dsp_setup_flow (double freq, uint32_t samplerate, uint32_t chunkDurationMs) -{ +void dsp_setup_flow(double freq, uint32_t samplerate, uint32_t chunkInFrames) { float f = freq / samplerate / 2.0; - uint16_t len = (samplerate * chunkDurationMs / 1000); + uint16_t len = chunkInFrames; - if (((currentSamplerate == samplerate) - && (currentChunkDurationMs == chunkDurationMs)) - || (samplerate == 0) || (chunkDurationMs == 0)) - { - return; - } + if (((currentSamplerate == samplerate) && + (currentChunkInFrames == chunkInFrames)) || + (samplerate == 0) || (chunkInFrames == 0)) { + return; + } currentSamplerate = samplerate; - currentChunkDurationMs = chunkDurationMs; + currentChunkInFrames = chunkInFrames; - bq[0] - = (ptype_t){ LPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[1] - = (ptype_t){ LPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[2] - = (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[3] - = (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[4] - = (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[5] - = (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[6] = (ptype_t){ LOWSHELF, f, 6, 0.707, NULL, NULL, - { 0, 0, 0, 0, 0 }, { 0, 0 } }; - bq[7] = (ptype_t){ LOWSHELF, f, 6, 0.707, NULL, NULL, - { 0, 0, 0, 0, 0 }, { 0, 0 } }; + bq[0] = (ptype_t){LPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[1] = (ptype_t){LPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[2] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[3] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[4] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[5] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[6] = (ptype_t){LOWSHELF, f, 6, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; + bq[7] = (ptype_t){LOWSHELF, f, 6, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}}; - for (uint8_t n = 0; n <= 7; n++) - { - switch (bq[n].filtertype) - { - case LOWSHELF: - dsps_biquad_gen_lowShelf_f32 (bq[n].coeffs, bq[n].freq, bq[n].gain, - bq[n].q); - break; - case LPF: - dsps_biquad_gen_lpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q); - break; - case HPF: - dsps_biquad_gen_hpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q); - break; - default: - break; - } - // for (uint8_t i = 0; i <= 4; i++) { - // printf("%.6f ", bq[n].coeffs[i]); - // } - // printf("\n"); + for (uint8_t n = 0; n <= 7; n++) { + switch (bq[n].filtertype) { + case LOWSHELF: + dsps_biquad_gen_lowShelf_f32(bq[n].coeffs, bq[n].freq, bq[n].gain, + bq[n].q); + break; + case LPF: + dsps_biquad_gen_lpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q); + break; + case HPF: + dsps_biquad_gen_hpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q); + break; + default: + break; } + // for (uint8_t i = 0; i <= 4; i++) { + // printf("%.6f ", bq[n].coeffs[i]); + // } + // printf("\n"); + } - if (sbuffer0 != NULL) - { - free (sbuffer0); - sbuffer0 = NULL; - } - if (sbufout0 != NULL) - { - free (sbufout0); - sbufout0 = NULL; - } - if (sbuftmp0 != NULL) - { - free (sbuftmp0); - sbuftmp0 = NULL; - } + if (sbuffer0 != NULL) { + free(sbuffer0); + sbuffer0 = NULL; + } + if (sbufout0 != NULL) { + free(sbufout0); + sbufout0 = NULL; + } + if (sbuftmp0 != NULL) { + free(sbuftmp0); + sbuftmp0 = NULL; + } - sbuffer0 = (float *)heap_caps_malloc (sizeof (float) * len, MALLOC_CAP_8BIT); - sbufout0 = (float *)heap_caps_malloc (sizeof (float) * len, MALLOC_CAP_8BIT); - sbuftmp0 = (float *)heap_caps_malloc (sizeof (float) * len, MALLOC_CAP_8BIT); - if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) - { - ESP_LOGE (TAG, - "Failed to allocate initial memory for dsp_processor %p %p %p", - sbuffer0, sbufout0, sbuftmp0); + sbuffer0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT); + sbufout0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT); + sbuftmp0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT); + if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) { + ESP_LOGE(TAG, + "Failed to allocate initial memory for dsp_processor %p %p %p", + sbuffer0, sbufout0, sbuftmp0); - if (sbuffer0) - { - free (sbuffer0); - } - if (sbufout0) - { - free (sbufout0); - } - if (sbuftmp0) - { - free (sbuftmp0); - } + if (sbuffer0) { + free(sbuffer0); } - else - { - ESP_LOGI (TAG, "GOT memory for dsp_processor %p %p", sbuffer0, sbufout0); + if (sbufout0) { + free(sbufout0); } + if (sbuftmp0) { + free(sbuftmp0); + } + } else { + ESP_LOGI(TAG, "GOT memory for dsp_processor %p %p", sbuffer0, sbufout0); + } } -void -dsp_set_xoverfreq (uint8_t freqh, uint8_t freql, uint32_t samplerate) -{ +void dsp_set_xoverfreq(uint8_t freqh, uint8_t freql, uint32_t samplerate) { float freq = freqh * 256 + freql; // printf("%f\n", freq); float f = freq / samplerate / 2.; - for (int8_t n = 0; n <= 5; n++) - { - bq[n].freq = f; - switch (bq[n].filtertype) - { - case LPF: - // for (uint8_t i = 0; i <= 4; i++) { - // printf("%.6f ", bq[n].coeffs[i]); - // } - // printf("\n"); - dsps_biquad_gen_lpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q); - // for (uint8_t i = 0; i <= 4; i++) { - // printf("%.6f ", bq[n].coeffs[i]); - // } - // printf("%f \n", bq[n].freq); - break; - case HPF: - dsps_biquad_gen_hpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q); - break; - default: - break; - } + for (int8_t n = 0; n <= 5; n++) { + bq[n].freq = f; + switch (bq[n].filtertype) { + case LPF: + // for (uint8_t i = 0; i <= 4; i++) { + // printf("%.6f ", bq[n].coeffs[i]); + // } + // printf("\n"); + dsps_biquad_gen_lpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q); + // for (uint8_t i = 0; i <= 4; i++) { + // printf("%.6f ", bq[n].coeffs[i]); + // } + // printf("%f \n", bq[n].freq); + break; + case HPF: + dsps_biquad_gen_hpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q); + break; + default: + break; } + } } -void -dsp_set_vol (double volume) -{ - if (volume >= 0 && volume <= 1.0) - { - ESP_LOGI (TAG, "Set volume to %f", volume); - dynamic_vol = volume; - } +void dsp_set_vol(double volume) { + if (volume >= 0 && volume <= 1.0) { + ESP_LOGI(TAG, "Set volume to %f", volume); + dynamic_vol = volume; + } } #endif diff --git a/components/dsp_processor/include/dsp_processor.h b/components/dsp_processor/include/dsp_processor.h index 5865a0c..227a689 100644 --- a/components/dsp_processor/include/dsp_processor.h +++ b/components/dsp_processor/include/dsp_processor.h @@ -39,7 +39,7 @@ typedef struct pnode { struct pnode *next; } pnode_t; -void dsp_setup_flow(double freq, uint32_t samplerate, uint32_t chunkDurationMs); +void dsp_setup_flow(double freq, uint32_t samplerate, uint32_t chunkInFrames); int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow); void dsp_set_xoverfreq(uint8_t, uint8_t, uint32_t); void dsp_set_vol(double volume); diff --git a/components/lightsnapcast/include/player.h b/components/lightsnapcast/include/player.h index 7c4efcd..fee59f3 100644 --- a/components/lightsnapcast/include/player.h +++ b/components/lightsnapcast/include/player.h @@ -35,7 +35,7 @@ typedef enum codec_type_e { NONE = 0, PCM, FLAC, OGG, OPUS } codec_type_t; typedef struct snapcastSetting_s { uint32_t buf_ms; - uint32_t chkDur_ms; + uint32_t chkInFrames; int32_t cDacLat_ms; codec_type_t codec; diff --git a/components/lightsnapcast/player.c b/components/lightsnapcast/player.c index 5fb3cc5..08cbc6e 100644 --- a/components/lightsnapcast/player.c +++ b/components/lightsnapcast/player.c @@ -67,8 +67,6 @@ static TaskHandle_t playerTaskHandle = NULL; static QueueHandle_t snapcastSettingQueueHandle = NULL; -static size_t chkInBytes; - static uint32_t i2sDmaBufCnt; static uint32_t i2sDmaBufMaxLen; @@ -93,19 +91,13 @@ static void player_task(void *pvParameters); */ 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; - chunkInFrames = chkInBytes / (setting->ch * (setting->bits / 8)); - __dmaBufCnt = 1; - __dmaBufLen = chunkInFrames; + __dmaBufLen = setting->chkInFrames; while ((__dmaBufLen >= __dmaBufMaxLen) || (__dmaBufCnt <= 1)) { if ((__dmaBufLen % 2) == 0) { __dmaBufCnt *= 2; @@ -251,7 +243,7 @@ int init_player(void) { int ret = 0; currentSnapcastSetting.buf_ms = 1000; - currentSnapcastSetting.chkDur_ms = 20; + currentSnapcastSetting.chkInFrames = 1152; currentSnapcastSetting.codec = NONE; currentSnapcastSetting.sr = 48000; currentSnapcastSetting.ch = 2; @@ -373,7 +365,8 @@ int32_t player_send_snapcast_setting(snapcastSetting_t *setting) { 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.ch != setting->ch) || + (curSet.chkInFrames != setting->chkInFrames) || (curSet.codec != setting->codec) || (curSet.muted != setting->muted) || (curSet.sr != setting->sr) || (curSet.volume != setting->volume) || (curSet.cDacLat_ms != setting->cDacLat_ms)) { @@ -383,7 +376,7 @@ int32_t player_send_snapcast_setting(snapcastSetting_t *setting) { (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.chkInFrames == setting->chkInFrames) && (curSet.codec == setting->codec) && (curSet.sr == setting->sr) && (curSet.cDacLat_ms == setting->cDacLat_ms))) { // no notify needed, only set changed parameters @@ -868,40 +861,6 @@ int32_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk, return -2; } - //#if CONFIG_SPIRAM && CONFIG_SPIRAM_BOOT_INIT - // (*pcmChunk)->fragment->payload = - // (char *)heap_caps_malloc(bytes, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - // if ((*pcmChunk)->fragment->payload == NULL) { - // // size_t largestFreeBlock, freeMem; - // // 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; - // } - //#elif CONFIG_SPIRAM - // (*pcmChunk)->fragment->payload = (char *)malloc(bytes); - // if ((*pcmChunk)->fragment->payload == NULL) { - // // size_t largestFreeBlock, freeMem; - // // 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 #if CONFIG_SPIRAM && CONFIG_SPIRAM_BOOT_INIT ret = allocate_pcm_chunk_memory_caps(*pcmChunk, bytes, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); @@ -923,8 +882,6 @@ int32_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk, } #endif - //#endif - if (ret < 0) { ESP_LOGE(TAG, "couldn't get memory to insert chunk"); @@ -1037,10 +994,8 @@ static void player_task(void *pvParameters) { 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; + chkDur_us = + (int64_t)__scSet.chkInFrames * (int64_t)1E6 / (int64_t)__scSet.sr; clientDacLatency_us = (int64_t)__scSet.cDacLat_ms * 1000; // this value is highly coupled with I2S DMA buffer @@ -1048,7 +1003,7 @@ static void player_task(void *pvParameters) { // so next chunk we get from queue will be -20ms outputBufferDacTime = chkDur_us * CHNK_CTRL_CNT; - if ((__scSet.buf_ms > 0) && (__scSet.chkDur_ms > 0)) { + if ((__scSet.buf_ms > 0) && (__scSet.chkInFrames > 0)) { if ((scSet.sr != __scSet.sr) || (scSet.bits != __scSet.bits) || (scSet.ch != __scSet.ch)) { i2s_custom_stop(I2S_NUM_0); @@ -1069,14 +1024,15 @@ static void player_task(void *pvParameters) { } if ((__scSet.buf_ms != scSet.buf_ms) || - (__scSet.chkDur_ms != scSet.chkDur_ms)) { + (__scSet.chkInFrames != scSet.chkInFrames)) { if (pcmChkQHdl != NULL) { destroy_pcm_queue(&pcmChkQHdl); } } if (pcmChkQHdl == NULL) { - int entries = ceil((float)__scSet.buf_ms / (float)__scSet.chkDur_ms); + int entries = ceil(((float)__scSet.sr / (float)__scSet.chkInFrames) * + ((float)__scSet.buf_ms / 1000)); pcmChkQHdl = xQueueCreate(entries, sizeof(pcm_chunk_message_t *)); @@ -1085,9 +1041,9 @@ static void player_task(void *pvParameters) { } ESP_LOGI(TAG, - "snapserver config changed, buffer %dms, chunk %dms, " + "snapserver config changed, buffer %dms, chunk %d frames, " "sample rate %d, ch %d, bits %d mute %d latency %d", - __scSet.buf_ms, __scSet.chkDur_ms, __scSet.sr, __scSet.ch, + __scSet.buf_ms, __scSet.chkInFrames, __scSet.sr, __scSet.ch, __scSet.bits, __scSet.muted, __scSet.cDacLat_ms); scSet = __scSet; // store for next round diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index e8a67e3..f8fc769 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -25,37 +25,4 @@ menu "Snapcast Configuration" default "ESP32-Caster" help Name of the client to register the snapserver. - - config SNAPCLIENT_USE_SOFT_VOL - bool "Use software volume" - default false - depends on USE_DSP_PROCESSOR - help - Use software volume mixer instead of hardware mixer. - - choice SNAPCLIENT_DSP_FLOW - prompt "DSP flow" - default SNAPCLIENT_DSP_FLOW_STEREO - help - Select the DSP flow to use. - - config SNAPCLIENT_DSP_FLOW_STEREO - bool "Stereo flow" - - config SNAPCLIENT_DSP_FLOW_BASSBOOST - bool "Bassboost flow" - - config SNAPCLIENT_DSP_FLOW_BIAMP - bool "Bi-Amp flow" - endchoice - -endmenu - -menu "SNTP Configuration" - - config SNPACLIENT_SNTP_ENABLE - bool "Enable SNTP" - default true - help - Enable the setup of RTC time using the SNTP protocol. endmenu diff --git a/main/main.c b/main/main.c index a5ef994..cfc7ad5 100644 --- a/main/main.c +++ b/main/main.c @@ -114,7 +114,8 @@ SemaphoreHandle_t timeSyncSemaphoreHandle = NULL; #if CONFIG_USE_DSP_PROCESSOR #if CONFIG_SNAPCLIENT_DSP_FLOW_STEREO -dspFlows_t dspFlow = dspfStereo; // dspfBiamp; // dspfStereo; // dspfBassBoost; +// dspFlows_t dspFlow = dspfStereo; // dspfBiamp; // dspfStereo; // +// dspfBassBoost; #endif #if CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST dspFlows_t dspFlow = dspfBassBoost; @@ -499,9 +500,8 @@ void flac_task(void *pvParameters) { pcmData->timestamp = currentTimestamp; size_t decodedSize = pcmData->totalSize; // pFlacData->bytes; - scSet->chkDur_ms = (1000UL * decodedSize) / - (uint32_t)(scSet->ch * (scSet->bits / 8)) / - scSet->sr; + scSet->chkInFrames = + decodedSize / ((size_t)scSet->ch * (size_t)(scSet->bits / 8)); if (player_send_snapcast_setting(scSet) != pdPASS) { ESP_LOGE(TAG, "Failed to " @@ -515,7 +515,7 @@ void flac_task(void *pvParameters) { } #if CONFIG_USE_DSP_PROCESSOR - dsp_setup_flow(500, scSet->sr, scSet->chkDur_ms); + dsp_setup_flow(500, scSet->sr, scSet->chkInFrames); dsp_processor(pcmData->fragment->payload, pcmData->fragment->size, dspFlow); #endif @@ -781,7 +781,7 @@ static void http_get_task(void *pvParameters) { scSet.bits = 0; scSet.ch = 0; scSet.sr = 0; - scSet.chkDur_ms = 0; + scSet.chkInFrames = 0; scSet.volume = 0; scSet.muted = true; @@ -1400,10 +1400,9 @@ static void http_get_task(void *pvParameters) { // %d", // decodedSize); - scSet.chkDur_ms = - (1000UL * decodedSize) / - (uint32_t)(scSet.ch * (scSet.bits / 8)) / - scSet.sr; + scSet.chkInFrames = + decodedSize / ((size_t)scSet.ch * + (size_t)(scSet.bits / 8)); if (player_send_snapcast_setting(&scSet) != pdPASS) { ESP_LOGE(TAG, @@ -1437,7 +1436,8 @@ static void http_get_task(void *pvParameters) { } dsp_set_vol(dynamic_vol); } - dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_setup_flow(500, scSet.sr, + scSet.chkInFrames); dsp_processor(pcmData->fragment->payload, pcmData->fragment->size, dspFlow); #endif @@ -1459,10 +1459,10 @@ static void http_get_task(void *pvParameters) { pcmData->timestamp = wire_chnk.timestamp; - scSet.chkDur_ms = - (1000UL * decodedSize) / - (uint32_t)(scSet.ch * (scSet.bits / 8)) / - scSet.sr; + scSet.chkInFrames = + decodedSize / + ((size_t)scSet.ch * (size_t)(scSet.bits / 8)); + if (player_send_snapcast_setting(&scSet) != pdPASS) { ESP_LOGE(TAG, @@ -1492,7 +1492,7 @@ static void http_get_task(void *pvParameters) { } dsp_set_vol(dynamic_vol); } - dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms); + dsp_setup_flow(500, scSet.sr, scSet.chkInFrames); dsp_processor(pcmData->fragment->payload, pcmData->fragment->size, dspFlow); #endif diff --git a/sdkconfig b/sdkconfig index e8d4489..4f92049 100644 --- a/sdkconfig +++ b/sdkconfig @@ -143,9 +143,7 @@ CONFIG_ESP_LYRAT_V4_3_BOARD=y # # ESP32 audio buffer and I2S config # -CONFIG_USE_PSRAM=y # CONFIG_USE_DSP_PROCESSOR is not set -CONFIG_USE_BIQUAD_ASM=y # end of ESP32 audio buffer and I2S config # @@ -167,17 +165,8 @@ CONFIG_WIFI_MAXIMUM_RETRY=0 # CONFIG_SNAPSERVER_USE_MDNS=y CONFIG_SNAPCLIENT_NAME="esp-snapclient" -CONFIG_SNAPCLIENT_DSP_FLOW_STEREO=y -# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set -# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set # end of Snapcast Configuration -# -# SNTP Configuration -# -# CONFIG_SNPACLIENT_SNTP_ENABLE is not set -# end of SNTP Configuration - # # Compiler options # @@ -334,7 +323,6 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # # ESP32-specific # -CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y CONFIG_ESP32_REV_MIN_0=y # CONFIG_ESP32_REV_MIN_1 is not set # CONFIG_ESP32_REV_MIN_2 is not set @@ -345,66 +333,7 @@ CONFIG_ESP32_DPORT_WORKAROUND=y # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -CONFIG_ESP32_SPIRAM_SUPPORT=y - -# -# SPI RAM config -# -CONFIG_SPIRAM_TYPE_AUTO=y -# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set -CONFIG_SPIRAM_SIZE=-1 -CONFIG_SPIRAM_SPEED_40M=y -# CONFIG_SPIRAM_SPEED_80M is not set -CONFIG_SPIRAM=y -CONFIG_SPIRAM_BOOT_INIT=y -# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set -# CONFIG_SPIRAM_USE_MEMMAP is not set -# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set -CONFIG_SPIRAM_USE_MALLOC=y -CONFIG_SPIRAM_MEMTEST=y -CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 -# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set -CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 -# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set -CONFIG_SPIRAM_CACHE_WORKAROUND=y - -# -# SPIRAM cache workaround debugging -# -CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y -# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set -# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set -# end of SPIRAM cache workaround debugging - -CONFIG_SPIRAM_BANKSWITCH_ENABLE=y -CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 -# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set - -# -# PSRAM clock and cs IO for ESP32-DOWD -# -CONFIG_D0WD_PSRAM_CLK_IO=17 -CONFIG_D0WD_PSRAM_CS_IO=16 -# end of PSRAM clock and cs IO for ESP32-DOWD - -# -# PSRAM clock and cs IO for ESP32-D2WD -# -CONFIG_D2WD_PSRAM_CLK_IO=9 -CONFIG_D2WD_PSRAM_CS_IO=10 -# end of PSRAM clock and cs IO for ESP32-D2WD - -# -# PSRAM clock and cs IO for ESP32-PICO -# -CONFIG_PICO_PSRAM_CS_IO=10 -# end of PSRAM clock and cs IO for ESP32-PICO - -# CONFIG_SPIRAM_2T_MODE is not set -# end of SPI RAM config - +# CONFIG_ESP32_SPIRAM_SUPPORT is not set # CONFIG_ESP32_TRAX is not set CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set @@ -570,6 +499,7 @@ CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y # CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +CONFIG_ESP_SYSTEM_PD_FLASH=y # # Memory protection @@ -594,15 +524,14 @@ CONFIG_ESP_TIMER_IMPL_TG0_LAC=y CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +# CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 -CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 # CONFIG_ESP32_WIFI_CSI_ENABLED is not set CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_TX_BA_WIN=32 CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y CONFIG_ESP32_WIFI_RX_BA_WIN=16 -# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set CONFIG_ESP32_WIFI_NVS_ENABLED=y CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set @@ -614,8 +543,8 @@ CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO=y # CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_ESP32_WIFI_IRAM_OPT=y -CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +# CONFIG_ESP32_WIFI_IRAM_OPT is not set +# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y # CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set # CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set @@ -670,7 +599,6 @@ CONFIG_FATFS_LFN_NONE=y CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y -CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # CONFIG_FATFS_USE_FASTSEEK is not set # end of FAT Filesystem support @@ -914,7 +842,6 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y # mbedTLS # CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y -# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y @@ -1301,8 +1228,7 @@ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0 CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 CONFIG_ADC2_DISABLE_DAC=y -CONFIG_SPIRAM_SUPPORT=y -# CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST is not set +# CONFIG_SPIRAM_SUPPORT is not set CONFIG_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y diff --git a/sdkconfig.old b/sdkconfig.old index 9213c6e..ab558f5 100644 --- a/sdkconfig.old +++ b/sdkconfig.old @@ -143,8 +143,12 @@ CONFIG_ESP_LYRAT_V4_3_BOARD=y # # ESP32 audio buffer and I2S config # -# CONFIG_USE_DSP_PROCESSOR is not set +CONFIG_USE_DSP_PROCESSOR=y +CONFIG_SNAPCLIENT_DSP_FLOW_STEREO=y +# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set +# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set CONFIG_USE_BIQUAD_ASM=y +# CONFIG_SNAPCLIENT_USE_SOFT_VOL is not set # end of ESP32 audio buffer and I2S config # @@ -166,17 +170,8 @@ CONFIG_WIFI_MAXIMUM_RETRY=0 # CONFIG_SNAPSERVER_USE_MDNS=y CONFIG_SNAPCLIENT_NAME="esp-snapclient" -CONFIG_SNAPCLIENT_DSP_FLOW_STEREO=y -# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set -# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set # end of Snapcast Configuration -# -# SNTP Configuration -# -# CONFIG_SNPACLIENT_SNTP_ENABLE is not set -# end of SNTP Configuration - # # Compiler options # @@ -333,6 +328,7 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # # ESP32-specific # +CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y CONFIG_ESP32_REV_MIN_0=y # CONFIG_ESP32_REV_MIN_1 is not set # CONFIG_ESP32_REV_MIN_2 is not set @@ -343,7 +339,69 @@ CONFIG_ESP32_DPORT_WORKAROUND=y # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -# CONFIG_ESP32_SPIRAM_SUPPORT is not set +CONFIG_ESP32_SPIRAM_SUPPORT=y + +# +# SPI RAM config +# +CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SIZE=-1 +# CONFIG_SPIRAM_SPEED_40M is not set +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +# CONFIG_SPIRAM_USE_MEMMAP is not set +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 +# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set +CONFIG_SPIRAM_CACHE_WORKAROUND=y + +# +# SPIRAM cache workaround debugging +# +CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set +# end of SPIRAM cache workaround debugging + +CONFIG_SPIRAM_BANKSWITCH_ENABLE=y +CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 +# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set +# CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set +CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y +# CONFIG_SPIRAM_OCCUPY_NO_HOST is not set + +# +# PSRAM clock and cs IO for ESP32-DOWD +# +CONFIG_D0WD_PSRAM_CLK_IO=17 +CONFIG_D0WD_PSRAM_CS_IO=16 +# end of PSRAM clock and cs IO for ESP32-DOWD + +# +# PSRAM clock and cs IO for ESP32-D2WD +# +CONFIG_D2WD_PSRAM_CLK_IO=9 +CONFIG_D2WD_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-D2WD + +# +# PSRAM clock and cs IO for ESP32-PICO +# +CONFIG_PICO_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-PICO + +# CONFIG_SPIRAM_2T_MODE is not set +# end of SPI RAM config + # CONFIG_ESP32_TRAX is not set CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set @@ -509,7 +567,6 @@ CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y # CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set -CONFIG_ESP_SYSTEM_PD_FLASH=y # # Memory protection @@ -533,15 +590,16 @@ CONFIG_ESP_TIMER_IMPL_TG0_LAC=y # CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16 -# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y -CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 # CONFIG_ESP32_WIFI_CSI_ENABLED is not set CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_TX_BA_WIN=32 CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y CONFIG_ESP32_WIFI_RX_BA_WIN=16 +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set CONFIG_ESP32_WIFI_NVS_ENABLED=y CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set @@ -553,8 +611,8 @@ CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO=y # CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_ESP32_WIFI_IRAM_OPT=y -CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +# CONFIG_ESP32_WIFI_IRAM_OPT is not set +# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y # CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set # CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set @@ -609,6 +667,7 @@ CONFIG_FATFS_LFN_NONE=y CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y +CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # CONFIG_FATFS_USE_FASTSEEK is not set # end of FAT Filesystem support @@ -852,6 +911,7 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y # mbedTLS # CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y @@ -1238,7 +1298,8 @@ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0 CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 CONFIG_ADC2_DISABLE_DAC=y -# CONFIG_SPIRAM_SUPPORT is not set +CONFIG_SPIRAM_SUPPORT=y +# CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST is not set CONFIG_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y diff --git a/snapcast/snapserver.conf b/snapcast/snapserver.conf index 9c8f315..845c41a 100644 --- a/snapcast/snapserver.conf +++ b/snapcast/snapserver.conf @@ -14,6 +14,38 @@ # default values are commented # uncomment and edit to change them +# Settings can be overwritten on command line with: +# "--
.=", e.g. --server.threads=4 + + +# General server settings ##################################################### +# +[server] +# Number of additional worker threads to use +# - For values < 0 the number of threads will be 2 (on single and dual cores) +# or 4 (for quad and more cores) +# - 0 will utilize just the processes main thread and might cause audio drops +# in case there are a couple of longer running tasks, such as encoding +# multiple audio streams +#threads = -1 + +# the pid file when running as daemon +#pidfile = /var/run/snapserver/pid + +# the user to run as when daemonized +user = root +# the group to run as when daemonized +group = root + +# directory where persistent data is stored (server.json) +# if empty, data dir will be +# - "/var/lib/snapserver/" when running as daemon +# - "$HOME/.config/snapserver/" when not running as daemon +datadir = /overlay/work/snapserver/config.json + +# +############################################################################### + # HTTP RPC #################################################################### # @@ -32,7 +64,14 @@ #port = 1780 # serve a website from the doc_root location -#doc_root = +# disabled if commented or empty +doc_root = /usr/share/snapserver/snapweb + +# Hostname or IP under which clients can reach this host +# used to serve cached cover art +# use as placeholder for your actual host name +#host = + # ############################################################################### @@ -69,9 +108,32 @@ # which port the server should listen to #port = 1704 -# stream URI of the PCM input stream, can be configured multiple times -# Format: TYPE://host/path?name=NAME[&codec=CODEC][&sampleformat=SAMPLEFORMAT] -stream = pipe:///tmp/snapfifo?name=default +# source URI of the PCM input stream, can be configured multiple times +# The following notation is used in this paragraph: +# : the whole expression must be replaced with your specific setting +# [square brackets]: the whole expression is optional and can be left out +# [key=value]: if you leave this option out, "value" will be the default for "key" +# +# Format: TYPE://host/path?name=[&codec=][&sampleformat=][&chunk_ms=] +# parameters have the form "key=value", they are concatenated with an "&" character +# parameter "name" is mandatory for all sources, while codec, sampleformat and chunk_ms are optional +# and will override the default codec, sampleformat or chunk_ms settings +# Non blocking sources support the dryout_ms parameter: when no new data is read from the source, send silence to the clients +# Available types are: +# pipe: pipe:///?name=[&mode=create][&dryout_ms=2000], mode can be "create" or "read" +# librespot: librespot:///?name=[&dryout_ms=2000][&username=&password=][&devicename=Snapcast][&bitrate=320][&wd_timeout=7800][&volume=100][&onevent=""][&nomalize=false][&autoplay=false][¶ms=] +# note that you need to have the librespot binary on your machine +# sampleformat will be set to "44100:16:2" +# file: file:///?name= +# process: process:///?name=[&dryout_ms=2000][&wd_timeout=0][&log_stderr=false][¶ms=] +# airplay: airplay:///?name=[&dryout_ms=2000][&port=5000] +# note that you need to have the airplay binary on your machine +# sampleformat will be set to "44100:16:2" +# tcp server: tcp://:?name=[&mode=server] +# tcp client: tcp://:?name=&mode=client +# alsa: alsa://?name=&device=[&send_silence=false][&idle_threshold=100][&silence_threshold_percent=0.0] +# meta: meta://///.../?name= +source = pipe:///tmp/snapfifo?name=default # Default sample format sampleformat = 48000:16:2 @@ -79,14 +141,14 @@ sampleformat = 48000:16:2 # Default transport codec # (flac|ogg|opus|pcm)[:options] # Type codec:? to get codec specific options -codec = opus +codec = flac - -# Default stream read buffer [ms] -stream_buffer = 20 +# Default source stream read chunk size [ms] +#chunk_ms = 20 # Buffer [ms] -buffer = 1000 +buffer = 504 + # Send audio to muted clients #send_to_muted = false @@ -98,10 +160,12 @@ buffer = 1000 # [logging] -# enable debug logging -#debug = false +# log sink [null,system,stdout,stderr,file:] +# when left empty: if running as daemon "system" else "stdout" +#sink = -# log file name for the debug logs (debug must be enabled) -#debug_logfile = +# log filter :[,:]* +# with tag = * or and level = [trace,debug,info,notice,warning,error,fatal] +filter = *:error # ###############################################################################