- clean up code
- add pre commit using GNU style - remove some minor issues regarding the use of global variables and such
This commit is contained in:
23
.pre-commit-config.yaml
Normal file
23
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v1.16.0
|
||||
hooks:
|
||||
- id: codespell
|
||||
|
||||
- repo: https://github.com/pocc/pre-commit-hooks
|
||||
rev: v1.1.1
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [-i, --style=GNU]
|
||||
# args: [-i, --style=Google]
|
||||
# - id: clang-tidy
|
||||
# args: [-checks=clang-diagnostic-return-type]
|
||||
# - id: uncrustify
|
||||
# - id: cppcheck
|
||||
# args: [--enable=all]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,13 +14,11 @@
|
||||
#include "dsps_biquad_gen.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
//#include "websocket_if.h"
|
||||
#include "board_pins_config.h"
|
||||
#include "driver/dac.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "dsp_processor.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
//#include "adc1_i2s_private.h"
|
||||
#include "board_pins_config.h"
|
||||
|
||||
#ifdef CONFIG_USE_BIQUAD_ASM
|
||||
#define BIQUAD dsps_biquad_f32_ae32
|
||||
@@ -30,226 +28,212 @@
|
||||
|
||||
static const char *TAG = "dspProc";
|
||||
|
||||
//static const uint8_t chunkDurationMs = CONFIG_WIRE_CHUNK_DURATION_MS;
|
||||
//static const uint32_t sampleRate = CONFIG_PCM_SAMPLE_RATE;
|
||||
//static const uint8_t channels = CONFIG_CHANNELS;
|
||||
//static const uint8_t bitsPerSample = CONFIG_BITS_PER_SAMPLE;
|
||||
|
||||
// TODO: allocate these buffers dynamically from heap
|
||||
static float *sbuffer0 = NULL;//[1024];
|
||||
//static float sbuffer1[1024];
|
||||
//static float sbuffer2[1024];
|
||||
static float *sbufout0 = NULL;//[1024];
|
||||
//static float sbufout1[1024];
|
||||
//static float sbufout2[1024];
|
||||
static float *sbuftmp0 = NULL;//[1024];
|
||||
//static uint8_t dsp_audio[4 * 1024];
|
||||
//static uint8_t dsp_audio1[4 * 1024];
|
||||
|
||||
extern uint8_t muteCH[4];
|
||||
static float *sbuffer0 = NULL;
|
||||
static float *sbufout0 = NULL;
|
||||
static float *sbuftmp0 = NULL;
|
||||
|
||||
static uint32_t currentSamplerate = 0;
|
||||
static uint32_t currentChunkDurationMs = 0;
|
||||
|
||||
ptype_t bq[8];
|
||||
static ptype_t bq[8];
|
||||
|
||||
|
||||
int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
int
|
||||
dsp_processor (char *audio, size_t chunk_size, dspFlows_t dspFlow)
|
||||
{
|
||||
double dynamic_vol = 1.0;
|
||||
int16_t len = chunk_size / 4;
|
||||
int16_t valint;
|
||||
uint16_t i;
|
||||
|
||||
// ESP_LOGI(TAG,
|
||||
// "got data %p, %d, %u", audio, chunk_size, dspFlow);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 1] << 8) + audio[i * 4 + 0])) / 32768;
|
||||
sbuffer1[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 3] << 8) + audio[i * 4 + 2])) / 32768;
|
||||
sbuffer2[i] = ((sbuffer0[i] / 2) + (sbuffer1[i] / 2));
|
||||
}
|
||||
*/
|
||||
|
||||
switch (dspFlow) {
|
||||
case dspfStereo: {
|
||||
// for (i = 0; i < len; i++) {
|
||||
// audio[i * 4 + 0] = (muteCH[0] == 1) ? 0 : audio[i * 4 + 0];
|
||||
// audio[i * 4 + 1] = (muteCH[0] == 1) ? 0 : audio[i * 4 + 1];
|
||||
// audio[i * 4 + 2] = (muteCH[1] == 1) ? 0 : audio[i * 4 + 2];
|
||||
// audio[i * 4 + 3] = (muteCH[1] == 1) ? 0 : audio[i * 4 + 3];
|
||||
// }
|
||||
|
||||
// mute is done through audio_hal_set_mute()
|
||||
} 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[i * 4 + 1] << 8) + audio[i * 4 + 0])) / 32768;
|
||||
switch (dspFlow)
|
||||
{
|
||||
case dspfStereo:
|
||||
{
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w);
|
||||
break;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
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[i * 4 + 1] << 8)
|
||||
+ audio[i * 4 + 0]))
|
||||
/ 32768;
|
||||
}
|
||||
BIQUAD (sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w);
|
||||
|
||||
audio[i * 4 + 0] = (valint & 0x00ff);
|
||||
audio[i * 4 + 1] = ((valint & 0xff00) >> 8);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
valint = (int16_t) (sbufout0[i] * 32768);
|
||||
|
||||
audio[i * 4 + 0] = (valint & 0x00ff);
|
||||
audio[i * 4 + 1] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
// channel 1
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
sbuffer0[i] = dynamic_vol * 0.5
|
||||
* ((float)((int16_t) (audio[i * 4 + 3] << 8)
|
||||
+ audio[i * 4 + 2]))
|
||||
/ 32768;
|
||||
}
|
||||
BIQUAD (sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
valint = (int16_t) (sbufout0[i] * 32768);
|
||||
audio[i * 4 + 2] = (valint & 0x00ff);
|
||||
audio[i * 4 + 3] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// channel 1
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 3] << 8) + audio[i * 4 + 2])) / 32768;
|
||||
case dspfBiamp:
|
||||
{
|
||||
// Process audio ch0 LOW PASS FILTER
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
sbuffer0[i] = dynamic_vol * 0.5
|
||||
* ((float)((int16_t) (audio[i * 4 + 1] << 8)
|
||||
+ audio[i * 4 + 0]))
|
||||
/ 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[i * 4 + 0] = (valint & 0x00ff);
|
||||
audio[i * 4 + 1] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
// Process audio ch1 HIGH PASS FILTER
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
sbuffer0[i] = dynamic_vol * 0.5
|
||||
* ((float)((int16_t) (audio[i * 4 + 3] << 8)
|
||||
+ audio[i * 4 + 2]))
|
||||
/ 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[i * 4 + 2] = (valint & 0x00ff);
|
||||
audio[i * 4 + 3] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w);
|
||||
break;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
audio[i * 4 + 2] = (valint & 0x00ff);
|
||||
audio[i * 4 + 3] = ((valint & 0xff00) >> 8);
|
||||
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;
|
||||
|
||||
} 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);
|
||||
|
||||
case dspfBiamp: {
|
||||
// Process audio ch0 LOW PASS FILTER
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 1] << 8) + audio[i * 4 + 0])) / 32768;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbuftmp0, len, bq[0].coeffs, bq[0].w);
|
||||
BIQUAD(sbuftmp0, sbufout0, 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);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
audio[i * 4 + 0] = (valint & 0x00ff);
|
||||
audio[i * 4 + 1] = ((valint & 0xff00) >> 8);
|
||||
// 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;
|
||||
|
||||
// Process audio ch1 HIGH PASS FILTER
|
||||
for (i = 0; i < len; i++) {
|
||||
sbuffer0[i] =
|
||||
dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(audio[i * 4 + 3] << 8) + audio[i * 4 + 2])) / 32768;
|
||||
default:
|
||||
{
|
||||
}
|
||||
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[i * 4 + 2] = (valint & 0x00ff);
|
||||
audio[i * 4 + 3] = ((valint & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
} 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; }
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -268,117 +252,134 @@ int 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 chunkDurationMs)
|
||||
{
|
||||
float f = freq / samplerate / 2.0;
|
||||
uint16_t len = (samplerate * chunkDurationMs / 1000);
|
||||
|
||||
if (((currentSamplerate == samplerate) && (currentChunkDurationMs == chunkDurationMs)) ||
|
||||
(samplerate == 0) || (chunkDurationMs == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (((currentSamplerate == samplerate)
|
||||
&& (currentChunkDurationMs == chunkDurationMs))
|
||||
|| (samplerate == 0) || (chunkDurationMs == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentSamplerate = samplerate;
|
||||
currentChunkDurationMs = chunkDurationMs;
|
||||
|
||||
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 } };
|
||||
|
||||
// pnode_t *aflow = NULL;
|
||||
// aflow = malloc(sizeof(pnode_t));
|
||||
// if (aflow == NULL) {
|
||||
// printf("Could not create node");
|
||||
// }
|
||||
|
||||
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 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 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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(
|
||||
TAG,
|
||||
"GOT memory for dsp_processor %p %p", sbuffer0, sbufout0);
|
||||
}
|
||||
if (sbuffer0)
|
||||
{
|
||||
free (sbuffer0);
|
||||
}
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13,37 +13,43 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "dsps_sqrt.h"
|
||||
#include "esp_err.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
inline float dsps_sqrtf_f32_ansi(float f)
|
||||
inline float
|
||||
dsps_sqrtf_f32_ansi (float f)
|
||||
{
|
||||
const int result = 0x1fbb4000 + (*(int*)&f >> 1);
|
||||
return *(float*)&result;
|
||||
const int result = 0x1fbb4000 + (*(int *)&f >> 1);
|
||||
return *(float *)&result;
|
||||
}
|
||||
|
||||
esp_err_t dsps_sqrt_f32_ansi(const float *input, float *output, int len)
|
||||
esp_err_t
|
||||
dsps_sqrt_f32_ansi (const float *input, float *output, int len)
|
||||
{
|
||||
if (NULL == input) return ESP_ERR_DSP_PARAM_OUTOFRANGE;
|
||||
if (NULL == output) return ESP_ERR_DSP_PARAM_OUTOFRANGE;
|
||||
if (NULL == input)
|
||||
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
|
||||
if (NULL == output)
|
||||
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
|
||||
|
||||
for (int i = 0 ; i < len ; i++) {
|
||||
output[i] = dsps_sqrtf_f32_ansi(input[i]);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
output[i] = dsps_sqrtf_f32_ansi (input[i]);
|
||||
}
|
||||
return ESP_OK;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
float dsps_inverted_sqrtf_f32_ansi(float data )
|
||||
{
|
||||
const float x2 = data * 0.5F;
|
||||
const float threehalfs = 1.5F;
|
||||
float
|
||||
dsps_inverted_sqrtf_f32_ansi (float data)
|
||||
{
|
||||
const float x2 = data * 0.5F;
|
||||
const float threehalfs = 1.5F;
|
||||
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} conv = {data}; // member 'f' set to value of 'data'.
|
||||
conv.i = 0x5f3759df - ( conv.i >> 1 );
|
||||
conv.f *= ( threehalfs - ( x2 * conv.f * conv.f ) );
|
||||
return conv.f;
|
||||
union
|
||||
{
|
||||
float f;
|
||||
uint32_t i;
|
||||
} conv = { data }; // member 'f' set to value of 'data'.
|
||||
conv.i = 0x5f3759df - (conv.i >> 1);
|
||||
conv.f *= (threehalfs - (x2 * conv.f * conv.f));
|
||||
return conv.f;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,60 +1,69 @@
|
||||
#ifndef __PLAYER_H__
|
||||
#define __PLAYER_H__
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_types.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "i2s.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "snapcast.h"
|
||||
#include "i2s.h"
|
||||
|
||||
#define I2S_PORT I2S_NUM_0
|
||||
|
||||
extern volatile int64_t clientDacLatency;
|
||||
|
||||
#define LATENCY_MEDIAN_FILTER_LEN 99
|
||||
|
||||
#define SHORT_BUFFER_LEN 29
|
||||
|
||||
typedef struct pcm_chunk_fragment pcm_chunk_fragment_t;
|
||||
struct pcm_chunk_fragment {
|
||||
struct pcm_chunk_fragment
|
||||
{
|
||||
size_t size;
|
||||
char *payload;
|
||||
pcm_chunk_fragment_t *nextFragment;
|
||||
};
|
||||
|
||||
typedef struct pcm_chunk_message {
|
||||
typedef struct pcm_chunk_message
|
||||
{
|
||||
tv_t timestamp;
|
||||
pcm_chunk_fragment_t *fragment;
|
||||
} pcm_chunk_message_t;
|
||||
|
||||
typedef enum codec_type_e { NONE, PCM, FLAC, OGG, OPUS } codec_type_t;
|
||||
typedef enum codec_type_e
|
||||
{
|
||||
NONE,
|
||||
PCM,
|
||||
FLAC,
|
||||
OGG,
|
||||
OPUS
|
||||
} codec_type_t;
|
||||
|
||||
typedef struct snapcastSetting_s {
|
||||
uint32_t buffer_ms;
|
||||
uint32_t chunkDuration_ms;
|
||||
typedef struct snapcastSetting_s
|
||||
{
|
||||
uint32_t buffer_ms;
|
||||
uint32_t chunkDuration_ms;
|
||||
int32_t clientDacLatency_ms;
|
||||
|
||||
codec_type_t codec;
|
||||
int32_t sampleRate;
|
||||
uint8_t channels;
|
||||
i2s_bits_per_sample_t bits;
|
||||
codec_type_t codec;
|
||||
int32_t sampleRate;
|
||||
uint8_t channels;
|
||||
i2s_bits_per_sample_t bits;
|
||||
|
||||
bool muted;
|
||||
uint32_t volume;
|
||||
bool muted;
|
||||
uint32_t volume;
|
||||
} snapcastSetting_t;
|
||||
|
||||
QueueHandle_t init_player(void);
|
||||
int deinit_player(void);
|
||||
QueueHandle_t init_player (void);
|
||||
int deinit_player (void);
|
||||
|
||||
int8_t insert_pcm_chunk(wire_chunk_message_t *decodedWireChunk);
|
||||
int8_t free_pcm_chunk(pcm_chunk_message_t *pcmChunk);
|
||||
int8_t insert_pcm_chunk (wire_chunk_message_t *decodedWireChunk);
|
||||
int8_t free_pcm_chunk (pcm_chunk_message_t *pcmChunk);
|
||||
|
||||
int8_t player_latency_insert(int64_t newValue);
|
||||
int8_t player_notify_buffer_ms(uint32_t ms);
|
||||
int8_t player_send_snapcast_setting(snapcastSetting_t setting);
|
||||
int8_t player_latency_insert (int64_t newValue);
|
||||
int8_t player_notify_buffer_ms (uint32_t ms);
|
||||
int8_t player_send_snapcast_setting (snapcastSetting_t setting);
|
||||
|
||||
int8_t reset_latency_buffer(void);
|
||||
int8_t latency_buffer_full(void);
|
||||
int8_t get_diff_to_server(int64_t *tDiff);
|
||||
int8_t server_now(int64_t *sNow);
|
||||
int8_t reset_latency_buffer (void);
|
||||
int8_t latency_buffer_full (void);
|
||||
int8_t get_diff_to_server (int64_t *tDiff);
|
||||
int8_t server_now (int64_t *sNow);
|
||||
|
||||
#endif // __PLAYER_H__
|
||||
#endif // __PLAYER_H__
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,128 +24,136 @@ static const char *TAG = "NETF";
|
||||
|
||||
extern EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
static const char *if_str[] = {"STA", "AP", "ETH", "MAX"};
|
||||
static const char *ip_protocol_str[] = {"V4", "V6", "MAX"};
|
||||
static const char *if_str[] = { "STA", "AP", "ETH", "MAX" };
|
||||
static const char *ip_protocol_str[] = { "V4", "V6", "MAX" };
|
||||
|
||||
void net_mdns_register(const char *clientname) {
|
||||
ESP_LOGI(TAG, "Setup mdns");
|
||||
ESP_ERROR_CHECK(mdns_init());
|
||||
ESP_ERROR_CHECK(mdns_hostname_set(clientname));
|
||||
ESP_ERROR_CHECK(mdns_instance_name_set("ESP32 SNAPcast client OTA"));
|
||||
ESP_ERROR_CHECK(mdns_service_add(NULL, "_http", "_tcp", 8032, NULL, 0));
|
||||
void
|
||||
net_mdns_register (const char *clientname)
|
||||
{
|
||||
ESP_LOGI (TAG, "Setup mdns");
|
||||
ESP_ERROR_CHECK (mdns_init ());
|
||||
ESP_ERROR_CHECK (mdns_hostname_set (clientname));
|
||||
ESP_ERROR_CHECK (mdns_instance_name_set ("ESP32 SNAPcast client OTA"));
|
||||
ESP_ERROR_CHECK (mdns_service_add (NULL, "_http", "_tcp", 8032, NULL, 0));
|
||||
}
|
||||
|
||||
void mdns_print_results(mdns_result_t *results) {
|
||||
void
|
||||
mdns_print_results (mdns_result_t *results)
|
||||
{
|
||||
mdns_result_t *r = results;
|
||||
mdns_ip_addr_t *a = NULL;
|
||||
int i = 1, t;
|
||||
while (r) {
|
||||
printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if],
|
||||
ip_protocol_str[r->ip_protocol]);
|
||||
if (r->instance_name) {
|
||||
printf(" PTR : %s\n", r->instance_name);
|
||||
while (r)
|
||||
{
|
||||
printf ("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if],
|
||||
ip_protocol_str[r->ip_protocol]);
|
||||
if (r->instance_name)
|
||||
{
|
||||
printf (" PTR : %s\n", r->instance_name);
|
||||
}
|
||||
if (r->hostname)
|
||||
{
|
||||
printf (" SRV : %s.local:%u\n", r->hostname, r->port);
|
||||
}
|
||||
if (r->txt_count)
|
||||
{
|
||||
printf (" TXT : [%u] ", r->txt_count);
|
||||
for (t = 0; t < r->txt_count; t++)
|
||||
{
|
||||
printf ("%s=%s; ", r->txt[t].key, r->txt[t].value);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
a = r->addr;
|
||||
while (a)
|
||||
{
|
||||
if (a->addr.type == IPADDR_TYPE_V6)
|
||||
{
|
||||
printf (" AAAA: " IPV6STR "\n", IPV62STR (a->addr.u_addr.ip6));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" A : " IPSTR "\n", IP2STR (&(a->addr.u_addr.ip4)));
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
if (r->hostname) {
|
||||
printf(" SRV : %s.local:%u\n", r->hostname, r->port);
|
||||
}
|
||||
if (r->txt_count) {
|
||||
printf(" TXT : [%u] ", r->txt_count);
|
||||
for (t = 0; t < r->txt_count; t++) {
|
||||
printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
a = r->addr;
|
||||
while (a) {
|
||||
if (a->addr.type == IPADDR_TYPE_V6) {
|
||||
printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
|
||||
} else {
|
||||
printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t find_mdns_service(const char *service_name, const char *proto) {
|
||||
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
|
||||
uint32_t
|
||||
find_mdns_service (const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI (TAG, "Query PTR: %s.%s.local", service_name, proto);
|
||||
|
||||
mdns_result_t *r = NULL;
|
||||
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &r);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Query Failed");
|
||||
return -1;
|
||||
}
|
||||
if (!r) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return -1;
|
||||
}
|
||||
esp_err_t err = mdns_query_ptr (service_name, proto, 3000, 20, &r);
|
||||
if (err)
|
||||
{
|
||||
ESP_LOGE (TAG, "Query Failed");
|
||||
return -1;
|
||||
}
|
||||
if (!r)
|
||||
{
|
||||
ESP_LOGW (TAG, "No results found!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (r->instance_name) {
|
||||
printf(" PTR : %s\n", r->instance_name);
|
||||
}
|
||||
if (r->hostname) {
|
||||
printf(" SRV : %s.local:%u\n", r->hostname, r->port);
|
||||
return r->port;
|
||||
}
|
||||
mdns_query_results_free(r);
|
||||
if (r->instance_name)
|
||||
{
|
||||
printf (" PTR : %s\n", r->instance_name);
|
||||
}
|
||||
if (r->hostname)
|
||||
{
|
||||
printf (" SRV : %s.local:%u\n", r->hostname, r->port);
|
||||
return r->port;
|
||||
}
|
||||
mdns_query_results_free (r);
|
||||
return 0;
|
||||
}
|
||||
static int sntp_synced = 0;
|
||||
|
||||
/*
|
||||
void sntp_sync_time(struct timeval *tv_ntp) {
|
||||
if ((sntp_synced%10) == 0) {
|
||||
settimeofday(tv_ntp,NULL);
|
||||
sntp_synced++;
|
||||
ESP_LOGI(TAG,"SNTP time set from server number :%d",sntp_synced);
|
||||
return;
|
||||
}
|
||||
sntp_synced++;
|
||||
struct timeval tv_esp;
|
||||
gettimeofday(&tv_esp, NULL);
|
||||
//ESP_LOGI(TAG,"SNTP diff s: %ld , %ld ", tv_esp.tv_sec , tv_ntp->tv_sec);
|
||||
ESP_LOGI(TAG,"SNTP diff us: %ld , %ld ", tv_esp.tv_usec , tv_ntp->tv_usec);
|
||||
ESP_LOGI(TAG,"SNTP diff us: %.2f", (double)((tv_esp.tv_usec -
|
||||
tv_ntp->tv_usec)/1000.0));
|
||||
|
||||
}*/
|
||||
|
||||
void sntp_cb(struct timeval *tv) {
|
||||
struct tm timeinfo = {0};
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
sntp_cb (struct timeval *tv)
|
||||
{
|
||||
struct tm timeinfo = { 0 };
|
||||
time_t now = tv->tv_sec;
|
||||
localtime_r(&now, &timeinfo);
|
||||
localtime_r (&now, &timeinfo);
|
||||
char strftime_buf[64];
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
ESP_LOGI(TAG, "sntp_cb called :%s", strftime_buf);
|
||||
strftime (strftime_buf, sizeof (strftime_buf), "%c", &timeinfo);
|
||||
ESP_LOGI (TAG, "sntp_cb called :%s", strftime_buf);
|
||||
}
|
||||
|
||||
void set_time_from_sntp() {
|
||||
xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, false, true,
|
||||
portMAX_DELAY);
|
||||
void
|
||||
set_time_from_sntp ()
|
||||
{
|
||||
xEventGroupWaitBits (s_wifi_event_group, WIFI_CONNECTED_BIT, false, true,
|
||||
portMAX_DELAY);
|
||||
// ESP_LOGI(TAG, "clock %");
|
||||
ESP_LOGI(TAG, "Initializing SNTP");
|
||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||
sntp_setservername(0, CONFIG_SNTP_SERVER);
|
||||
sntp_init();
|
||||
ESP_LOGI (TAG, "Initializing SNTP");
|
||||
sntp_setoperatingmode (SNTP_OPMODE_POLL);
|
||||
sntp_setservername (0, CONFIG_SNTP_SERVER);
|
||||
sntp_init ();
|
||||
// sntp_set_time_sync_notification_cb(sntp_cb);
|
||||
setenv("TZ", SNTP_TIMEZONE, 1);
|
||||
tzset();
|
||||
setenv ("TZ", SNTP_TIMEZONE, 1);
|
||||
tzset ();
|
||||
|
||||
time_t now = 0;
|
||||
struct tm timeinfo = {0};
|
||||
struct tm timeinfo = { 0 };
|
||||
int retry = 0;
|
||||
const int retry_count = 10;
|
||||
while (timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count) {
|
||||
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry,
|
||||
retry_count);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
}
|
||||
while (timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count)
|
||||
{
|
||||
ESP_LOGI (TAG, "Waiting for system time to be set... (%d/%d)", retry,
|
||||
retry_count);
|
||||
vTaskDelay (2000 / portTICK_PERIOD_MS);
|
||||
time (&now);
|
||||
localtime_r (&now, &timeinfo);
|
||||
}
|
||||
char strftime_buf[64];
|
||||
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
ESP_LOGI(TAG, "The current date/time in UTC is: %s", strftime_buf);
|
||||
strftime (strftime_buf, sizeof (strftime_buf), "%c", &timeinfo);
|
||||
ESP_LOGI (TAG, "The current date/time in UTC is: %s", strftime_buf);
|
||||
}
|
||||
|
||||
@@ -6,21 +6,22 @@
|
||||
*
|
||||
* \brief RTP audio stream receiver
|
||||
*
|
||||
* \warning This software is a PROTOTYPE version and is not designed or intended
|
||||
* for use in production, especially not for safety-critical applications! The
|
||||
* user represents and warrants that it will NOT use or redistribute the
|
||||
* Software for such purposes. This prototype is for research purposes only.
|
||||
* This software is provided "AS IS," without a warranty of any kind.
|
||||
* \warning This software is a PROTOTYPE version and is not designed or
|
||||
* intended for use in production, especially not for safety-critical
|
||||
* applications! The user represents and warrants that it will NOT use or
|
||||
* redistribute the Software for such purposes. This prototype is for research
|
||||
* purposes only. This software is provided "AS IS," without a warranty of any
|
||||
* kind.
|
||||
*/
|
||||
#include "rtprx.h"
|
||||
|
||||
#include <lwip/netdb.h>
|
||||
|
||||
#include "i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "i2s.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
@@ -31,34 +32,42 @@
|
||||
|
||||
static bool rtpRxState = 0;
|
||||
|
||||
void rtp_rx_start() {
|
||||
if (rtpRxState == 0) {
|
||||
setup_rtp_i2s();
|
||||
xTaskCreate(rtp_rx_task, "RTPRx", 12 * 1024, NULL, 0, NULL);
|
||||
rtpRxState = 1;
|
||||
}
|
||||
void
|
||||
rtp_rx_start ()
|
||||
{
|
||||
if (rtpRxState == 0)
|
||||
{
|
||||
setup_rtp_i2s ();
|
||||
xTaskCreate (rtp_rx_task, "RTPRx", 12 * 1024, NULL, 0, NULL);
|
||||
rtpRxState = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void rtp_rx_stop() {
|
||||
if (rtpRxState == 1) {
|
||||
i2s_custom_driver_uninstall(0);
|
||||
// vTaskDelete(xTaskSignal); xxx Fix me
|
||||
rtpRxState = 0;
|
||||
}
|
||||
void
|
||||
rtp_rx_stop ()
|
||||
{
|
||||
if (rtpRxState == 1)
|
||||
{
|
||||
i2s_custom_driver_uninstall (0);
|
||||
// vTaskDelete(xTaskSignal); xxx Fix me
|
||||
rtpRxState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rtp_rx_task(void *pvParameters) {
|
||||
void
|
||||
rtp_rx_task (void *pvParameters)
|
||||
{
|
||||
OpusDecoder *decoder;
|
||||
|
||||
// int size = opus_decoder_get_size(2);
|
||||
int oe = 0;
|
||||
decoder = opus_decoder_create(48000, 2, &oe);
|
||||
decoder = opus_decoder_create (48000, 2, &oe);
|
||||
// int error = opus_decoder_init(decoder, 48000, 2);
|
||||
printf("Initialized Decoder: %d", oe);
|
||||
printf ("Initialized Decoder: %d", oe);
|
||||
|
||||
// int32_t *audio32 = (int32_t*)malloc(960*sizeof(int32_t));
|
||||
int16_t *audio = (int16_t *)malloc(960 * 2 * sizeof(int16_t));
|
||||
i2s_custom_zero_dma_buffer(0);
|
||||
int16_t *audio = (int16_t *)malloc (960 * 2 * sizeof (int16_t));
|
||||
i2s_custom_zero_dma_buffer (0);
|
||||
static struct netconn *conn;
|
||||
static struct netbuf *buf;
|
||||
static uint32_t pkg = 0;
|
||||
@@ -66,115 +75,129 @@ void rtp_rx_task(void *pvParameters) {
|
||||
err_t err;
|
||||
uint16_t oldseq = 1;
|
||||
uint16_t first = 1;
|
||||
conn = netconn_new(NETCONN_UDP);
|
||||
if (conn != NULL) {
|
||||
printf("Net RTP RX\n");
|
||||
netconn_bind(conn, IP_ADDR_ANY, 1350);
|
||||
netconn_listen(conn);
|
||||
printf("Net RTP will enter loopn\n");
|
||||
while (1) {
|
||||
netconn_recv(conn, &buf);
|
||||
if (buf == NULL) {
|
||||
printf("NETCONN RX error \n");
|
||||
}
|
||||
pkg++;
|
||||
conn = netconn_new (NETCONN_UDP);
|
||||
if (conn != NULL)
|
||||
{
|
||||
printf ("Net RTP RX\n");
|
||||
netconn_bind (conn, IP_ADDR_ANY, 1350);
|
||||
netconn_listen (conn);
|
||||
printf ("Net RTP will enter loopn\n");
|
||||
while (1)
|
||||
{
|
||||
netconn_recv (conn, &buf);
|
||||
if (buf == NULL)
|
||||
{
|
||||
printf ("NETCONN RX error \n");
|
||||
}
|
||||
pkg++;
|
||||
|
||||
uint8_t *p = (buf->p->payload);
|
||||
uint16_t seq = (p[2] << 8) + p[3];
|
||||
if ((seq != oldseq + 1) & (first != 1)) {
|
||||
printf("seq : %d, oldseq : %d \n", seq, oldseq);
|
||||
uint16_t errors = seq - oldseq - 1;
|
||||
pkgerror = pkgerror + errors;
|
||||
printf("ERROR --- Package drop : %d %d \n", errors, pkgerror);
|
||||
size_t bWritten;
|
||||
// for (int i = 0; i;i++ )
|
||||
int ret = i2s_custom_write_expand(0, (char *)audio, 960 * 2 * sizeof(int16_t),
|
||||
16, 32, &bWritten, 100);
|
||||
printf("bWritten : %d ret : %d \n ", bWritten, ret);
|
||||
uint8_t *p = (buf->p->payload);
|
||||
uint16_t seq = (p[2] << 8) + p[3];
|
||||
if ((seq != oldseq + 1) & (first != 1))
|
||||
{
|
||||
printf ("seq : %d, oldseq : %d \n", seq, oldseq);
|
||||
uint16_t errors = seq - oldseq - 1;
|
||||
pkgerror = pkgerror + errors;
|
||||
printf ("ERROR --- Package drop : %d %d \n", errors, pkgerror);
|
||||
size_t bWritten;
|
||||
// for (int i = 0; i;i++ )
|
||||
int ret = i2s_custom_write_expand (0, (char *)audio,
|
||||
960 * 2 * sizeof (int16_t),
|
||||
16, 32, &bWritten, 100);
|
||||
printf ("bWritten : %d ret : %d \n ", bWritten, ret);
|
||||
|
||||
// opus_pkg = NULL;
|
||||
}
|
||||
// opus_pkg = NULL;
|
||||
}
|
||||
|
||||
if (seq < oldseq) {
|
||||
printf("ERROR --- Package order:");
|
||||
}
|
||||
oldseq = seq;
|
||||
first = 0;
|
||||
// printf("UDP package len : %d -> \n", buf->p->len);
|
||||
// printf("UDP package : %02x %02x %02x %02x\n",p[0],p[1],p[2],p[3]);
|
||||
// printf("Timestamp : %02x %02x %02x %02x\n",p[4],p[5],p[6],p[7]);
|
||||
// printf("Sync source : %02x %02x %02x
|
||||
// %02x\n",p[8],p[9],p[10],p[11]); printf("R1 : %d
|
||||
// \n",(p[12]&0xf8)>>3) ; int size = 240;
|
||||
unsigned char *opus_pkg = buf->p->payload + 12;
|
||||
int size = opus_decode(decoder, (unsigned char *)opus_pkg,
|
||||
if (seq < oldseq)
|
||||
{
|
||||
printf ("ERROR --- Package order:");
|
||||
}
|
||||
oldseq = seq;
|
||||
first = 0;
|
||||
// printf("UDP package len : %d -> \n", buf->p->len);
|
||||
// printf("UDP package : %02x %02x %02x
|
||||
// %02x\n",p[0],p[1],p[2],p[3]); printf("Timestamp : %02x %02x
|
||||
// %02x %02x\n",p[4],p[5],p[6],p[7]); printf("Sync source : %02x
|
||||
// %02x %02x %02x\n",p[8],p[9],p[10],p[11]); printf("R1 : %d
|
||||
// \n",(p[12]&0xf8)>>3) ; int size = 240;
|
||||
unsigned char *opus_pkg = buf->p->payload + 12;
|
||||
int size
|
||||
= opus_decode (decoder, (unsigned char *)opus_pkg,
|
||||
buf->p->len - 12, (opus_int16 *)audio, 960, 0);
|
||||
if (size < 0) {
|
||||
printf("Decode error : %d \n", size);
|
||||
}
|
||||
if (size < 0)
|
||||
{
|
||||
printf ("Decode error : %d \n", size);
|
||||
}
|
||||
|
||||
// for (int i = 0; i < size*2; i++) {
|
||||
// audio[i*2] = 0x0000;
|
||||
// audio[i*2+1] = 0x0000;
|
||||
//}
|
||||
// for (int i = 0; i < size*2; i++) {
|
||||
// audio[i*2] = 0x0000;
|
||||
// audio[i*2+1] = 0x0000;
|
||||
//}
|
||||
|
||||
size_t bWritten;
|
||||
int ret = i2s_custom_write_expand(0, (char *)audio, size * 2 * sizeof(int16_t),
|
||||
16, 32, &bWritten, 100);
|
||||
if (ret != 0)
|
||||
printf("Error I2S written: %d %d %d \n", ret,
|
||||
size * 2 * sizeof(int16_t), bWritten);
|
||||
size_t bWritten;
|
||||
int ret = i2s_custom_write_expand (0, (char *)audio,
|
||||
size * 2 * sizeof (int16_t), 16,
|
||||
32, &bWritten, 100);
|
||||
if (ret != 0)
|
||||
printf ("Error I2S written: %d %d %d \n", ret,
|
||||
size * 2 * sizeof (int16_t), bWritten);
|
||||
|
||||
if ((pkg % 1000) == 1) {
|
||||
// printf("I2S written: %d %d \n", size*sizeof(int32_t) ,bWritten);
|
||||
printf("%d > %d %d %d\n", pkg, size, buf->p->len, buf->p->tot_len);
|
||||
printf("UDP package len : %d -> \n", buf->p->len);
|
||||
printf("UDP package : %02x %02x %02x %02x\n", p[0], p[1], p[2],
|
||||
p[3]);
|
||||
printf("Timestamp : %02x %02x %02x %02x\n", p[4], p[5], p[6],
|
||||
p[7]);
|
||||
printf("Sync source : %02x %02x %02x %02x\n", p[8], p[9], p[10],
|
||||
p[11]);
|
||||
printf("R1 : %d \n", (p[12] & 0xf8) >> 3);
|
||||
if ((pkg % 1000) == 1)
|
||||
{
|
||||
// printf("I2S written: %d %d \n", size*sizeof(int32_t)
|
||||
// ,bWritten);
|
||||
printf ("%d > %d %d %d\n", pkg, size, buf->p->len,
|
||||
buf->p->tot_len);
|
||||
printf ("UDP package len : %d -> \n", buf->p->len);
|
||||
printf ("UDP package : %02x %02x %02x %02x\n", p[0], p[1],
|
||||
p[2], p[3]);
|
||||
printf ("Timestamp : %02x %02x %02x %02x\n", p[4], p[5],
|
||||
p[6], p[7]);
|
||||
printf ("Sync source : %02x %02x %02x %02x\n", p[8], p[9],
|
||||
p[10], p[11]);
|
||||
printf ("R1 : %d \n", (p[12] & 0xf8) >> 3);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
printf("%02d %04x %04x\n", i, audio[2 * i], audio[2 * i + 1]);
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
printf ("%02d %04x %04x\n", i, audio[2 * i], audio[2 * i + 1]);
|
||||
}
|
||||
|
||||
// netbuf_free(buf);
|
||||
netbuf_delete(buf);
|
||||
// netbuf_free(buf);
|
||||
netbuf_delete (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
netconn_close(conn);
|
||||
netconn_delete(conn);
|
||||
netconn_close (conn);
|
||||
netconn_delete (conn);
|
||||
}
|
||||
|
||||
void setup_rtp_i2s() {
|
||||
void
|
||||
setup_rtp_i2s ()
|
||||
{
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
|
||||
.sample_rate = 48000,
|
||||
.bits_per_sample = 32,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // 2-channels
|
||||
.communication_format = I2S_COMM_FORMAT_I2S,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 480,
|
||||
//.intr_alloc_flags = 1, //Default interrupt priority
|
||||
.use_apll = true,
|
||||
.fixed_mclk = 0,
|
||||
.tx_desc_auto_clear = true // Auto clear tx descriptor on underflow
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
|
||||
.sample_rate = 48000,
|
||||
.bits_per_sample = 32,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // 2-channels
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 480,
|
||||
//.intr_alloc_flags = 1, //Default interrupt priority
|
||||
.use_apll = true,
|
||||
.fixed_mclk = 0,
|
||||
.tx_desc_auto_clear = true // Auto clear tx descriptor on underflow
|
||||
};
|
||||
|
||||
i2s_custom_driver_install(0, &i2s_config, 0, NULL);
|
||||
i2s_custom_start(0);
|
||||
i2s_custom_zero_dma_buffer(0);
|
||||
i2s_custom_driver_install (0, &i2s_config, 0, NULL);
|
||||
i2s_custom_start (0);
|
||||
i2s_custom_zero_dma_buffer (0);
|
||||
|
||||
i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = 12, // CONFIG_EXAMPLE_I2S_BCK_PIN,
|
||||
.ws_io_num = 13, // CONFIG_EXAMPLE_I2S_LRCK_PIN,
|
||||
.data_out_num = 14, // CONFIG_EXAMPLE_I2S_DATA_PIN,
|
||||
.data_in_num = -1 // Not used
|
||||
.bck_io_num = 12, // CONFIG_EXAMPLE_I2S_BCK_PIN,
|
||||
.ws_io_num = 13, // CONFIG_EXAMPLE_I2S_LRCK_PIN,
|
||||
.data_out_num = 14, // CONFIG_EXAMPLE_I2S_DATA_PIN,
|
||||
.data_in_num = -1 // Not used
|
||||
};
|
||||
|
||||
i2s_custom_set_pin(0, &pin_config);
|
||||
printf("Here... set pin\n");
|
||||
i2s_custom_set_pin (0, &pin_config);
|
||||
printf ("Here... set pin\n");
|
||||
}
|
||||
|
||||
@@ -19,413 +19,504 @@ This program is free software: you can redistribute it and/or modify
|
||||
|
||||
#include "websocket_server.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include <string.h>
|
||||
|
||||
static SemaphoreHandle_t xwebsocket_mutex; // to lock the client array
|
||||
static QueueHandle_t xwebsocket_queue; // to hold the clients that send messages
|
||||
static ws_client_t clients[WEBSOCKET_SERVER_MAX_CLIENTS]; // holds list of clients
|
||||
static TaskHandle_t xtask; // the task itself
|
||||
static QueueHandle_t
|
||||
xwebsocket_queue; // to hold the clients that send messages
|
||||
static ws_client_t
|
||||
clients[WEBSOCKET_SERVER_MAX_CLIENTS]; // holds list of clients
|
||||
static TaskHandle_t xtask; // the task itself
|
||||
|
||||
static void background_callback(struct netconn* conn, enum netconn_evt evt,u16_t len) {
|
||||
switch(evt) {
|
||||
static void
|
||||
background_callback (struct netconn *conn, enum netconn_evt evt, u16_t len)
|
||||
{
|
||||
switch (evt)
|
||||
{
|
||||
case NETCONN_EVT_RCVPLUS:
|
||||
xQueueSendToBack(xwebsocket_queue,&conn,WEBSOCKET_SERVER_QUEUE_TIMEOUT);
|
||||
xQueueSendToBack (xwebsocket_queue, &conn,
|
||||
WEBSOCKET_SERVER_QUEUE_TIMEOUT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_read(uint8_t num) {
|
||||
static void
|
||||
handle_read (uint8_t num)
|
||||
{
|
||||
ws_header_t header;
|
||||
char* msg;
|
||||
char *msg;
|
||||
|
||||
header.received = 0;
|
||||
msg = ws_read(&clients[num],&header);
|
||||
msg = ws_read (&clients[num], &header);
|
||||
|
||||
if(!header.received) {
|
||||
if(msg) free(msg);
|
||||
return NULL;
|
||||
}
|
||||
if (!header.received)
|
||||
{
|
||||
if (msg)
|
||||
free (msg);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(clients[num].last_opcode) {
|
||||
switch (clients[num].last_opcode)
|
||||
{
|
||||
case WEBSOCKET_OPCODE_CONT:
|
||||
break;
|
||||
case WEBSOCKET_OPCODE_BIN:
|
||||
clients[num].scallback(num,WEBSOCKET_BIN,msg,header.length);
|
||||
clients[num].scallback (num, WEBSOCKET_BIN, msg, header.length);
|
||||
break;
|
||||
case WEBSOCKET_OPCODE_TEXT:
|
||||
clients[num].scallback(num,WEBSOCKET_TEXT,msg,header.length);
|
||||
clients[num].scallback (num, WEBSOCKET_TEXT, msg, header.length);
|
||||
break;
|
||||
case WEBSOCKET_OPCODE_PING:
|
||||
ws_send(&clients[num],WEBSOCKET_OPCODE_PONG,msg,header.length,0);
|
||||
clients[num].scallback(num,WEBSOCKET_PING,msg,header.length);
|
||||
ws_send (&clients[num], WEBSOCKET_OPCODE_PONG, msg, header.length, 0);
|
||||
clients[num].scallback (num, WEBSOCKET_PING, msg, header.length);
|
||||
break;
|
||||
case WEBSOCKET_OPCODE_PONG:
|
||||
if(clients[num].ping) {
|
||||
clients[num].scallback(num,WEBSOCKET_PONG,NULL,0);
|
||||
clients[num].ping = 0;
|
||||
}
|
||||
if (clients[num].ping)
|
||||
{
|
||||
clients[num].scallback (num, WEBSOCKET_PONG, NULL, 0);
|
||||
clients[num].ping = 0;
|
||||
}
|
||||
break;
|
||||
case WEBSOCKET_OPCODE_CLOSE:
|
||||
clients[num].scallback(num,WEBSOCKET_DISCONNECT_EXTERNAL,NULL,0);
|
||||
ws_disconnect_client(&clients[num], 0);
|
||||
clients[num].scallback (num, WEBSOCKET_DISCONNECT_EXTERNAL, NULL, 0);
|
||||
ws_disconnect_client (&clients[num], 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(msg) free(msg);
|
||||
}
|
||||
if (msg)
|
||||
free (msg);
|
||||
}
|
||||
|
||||
static void ws_server_task(void* pvParameters) {
|
||||
struct netconn* conn;
|
||||
static void
|
||||
ws_server_task (void *pvParameters)
|
||||
{
|
||||
struct netconn *conn;
|
||||
|
||||
xwebsocket_mutex = xSemaphoreCreateMutex();
|
||||
xwebsocket_queue = xQueueCreate(WEBSOCKET_SERVER_QUEUE_SIZE, sizeof(struct netconn*));
|
||||
xwebsocket_mutex = xSemaphoreCreateMutex ();
|
||||
xwebsocket_queue
|
||||
= xQueueCreate (WEBSOCKET_SERVER_QUEUE_SIZE, sizeof (struct netconn *));
|
||||
|
||||
// initialize all clients
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
clients[i].conn = NULL;
|
||||
clients[i].url = NULL;
|
||||
clients[i].ping = 0;
|
||||
clients[i].last_opcode = 0;
|
||||
clients[i].contin = NULL;
|
||||
clients[i].len = 0;
|
||||
clients[i].ccallback = NULL;
|
||||
clients[i].scallback = NULL;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
xQueueReceive(xwebsocket_queue,&conn,portMAX_DELAY);
|
||||
if(!conn) continue; // if the connection was NULL, ignore it
|
||||
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY); // take access
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(clients[i].conn == conn) {
|
||||
handle_read(i);
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
clients[i].conn = NULL;
|
||||
clients[i].url = NULL;
|
||||
clients[i].ping = 0;
|
||||
clients[i].last_opcode = 0;
|
||||
clients[i].contin = NULL;
|
||||
clients[i].len = 0;
|
||||
clients[i].ccallback = NULL;
|
||||
clients[i].scallback = NULL;
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex); // return access
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
xQueueReceive (xwebsocket_queue, &conn, portMAX_DELAY);
|
||||
if (!conn)
|
||||
continue; // if the connection was NULL, ignore it
|
||||
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY); // take access
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (clients[i].conn == conn)
|
||||
{
|
||||
handle_read (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive (xwebsocket_mutex); // return access
|
||||
}
|
||||
vTaskDelete (NULL);
|
||||
}
|
||||
|
||||
int ws_server_start() {
|
||||
if(xtask) return 0;
|
||||
#if WEBSOCKET_SERVER_PINNED
|
||||
xTaskCreatePinnedToCore(&ws_server_task,
|
||||
"ws_server_task",
|
||||
WEBSOCKET_SERVER_TASK_STACK_DEPTH,
|
||||
NULL,
|
||||
WEBSOCKET_SERVER_TASK_PRIORITY,
|
||||
&xtask,
|
||||
WEBSOCKET_SERVER_PINNED_CORE);
|
||||
#else
|
||||
xTaskCreate(&ws_server_task,
|
||||
"ws_server_task",
|
||||
WEBSOCKET_SERVER_TASK_STACK_DEPTH,
|
||||
NULL,
|
||||
WEBSOCKET_SERVER_TASK_PRIORITY,
|
||||
&xtask);
|
||||
#endif
|
||||
int
|
||||
ws_server_start ()
|
||||
{
|
||||
if (xtask)
|
||||
return 0;
|
||||
#if WEBSOCKET_SERVER_PINNED
|
||||
xTaskCreatePinnedToCore (&ws_server_task, "ws_server_task",
|
||||
WEBSOCKET_SERVER_TASK_STACK_DEPTH, NULL,
|
||||
WEBSOCKET_SERVER_TASK_PRIORITY, &xtask,
|
||||
WEBSOCKET_SERVER_PINNED_CORE);
|
||||
#else
|
||||
xTaskCreate (&ws_server_task, "ws_server_task",
|
||||
WEBSOCKET_SERVER_TASK_STACK_DEPTH, NULL,
|
||||
WEBSOCKET_SERVER_TASK_PRIORITY, &xtask);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ws_server_stop() {
|
||||
if(!xtask) return 0;
|
||||
vTaskDelete(xtask);
|
||||
int
|
||||
ws_server_stop ()
|
||||
{
|
||||
if (!xtask)
|
||||
return 0;
|
||||
vTaskDelete (xtask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool prepare_response(char* buf,uint32_t buflen,char* handshake,char* protocol) {
|
||||
static bool
|
||||
prepare_response (char *buf, uint32_t buflen, char *handshake, char *protocol)
|
||||
{
|
||||
const char WS_HEADER[] = "Upgrade: websocket\r\n";
|
||||
const char WS_KEY[] = "Sec-WebSocket-Key: ";
|
||||
const char WS_RSP[] = "HTTP/1.1 101 Switching Protocols\r\n" \
|
||||
"Upgrade: websocket\r\n" \
|
||||
"Connection: Upgrade\r\n" \
|
||||
"Sec-WebSocket-Accept: %s\r\n" \
|
||||
const char WS_RSP[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: %s\r\n"
|
||||
"%s\r\n";
|
||||
|
||||
char* key_start;
|
||||
char* key_end;
|
||||
char* hashed_key;
|
||||
char *key_start;
|
||||
char *key_end;
|
||||
char *hashed_key;
|
||||
|
||||
if(!strstr(buf,WS_HEADER)) return 0;
|
||||
if(!buflen) return 0;
|
||||
key_start = strstr(buf,WS_KEY);
|
||||
if(!key_start) return 0;
|
||||
if (!strstr (buf, WS_HEADER))
|
||||
return 0;
|
||||
if (!buflen)
|
||||
return 0;
|
||||
key_start = strstr (buf, WS_KEY);
|
||||
if (!key_start)
|
||||
return 0;
|
||||
key_start += 19;
|
||||
key_end = strstr(key_start,"\r\n");
|
||||
if(!key_end) return 0;
|
||||
key_end = strstr (key_start, "\r\n");
|
||||
if (!key_end)
|
||||
return 0;
|
||||
|
||||
hashed_key = ws_hash_handshake(key_start,key_end-key_start);
|
||||
if(!hashed_key) return 0;
|
||||
if(protocol) {
|
||||
char tmp[256];
|
||||
sprintf(tmp,WS_RSP,hashed_key,"Sec-WebSocket-Protocol: %s\r\n");
|
||||
sprintf(handshake,tmp,protocol);
|
||||
}
|
||||
else {
|
||||
sprintf(handshake,WS_RSP,hashed_key,"");
|
||||
}
|
||||
free(hashed_key);
|
||||
hashed_key = ws_hash_handshake (key_start, key_end - key_start);
|
||||
if (!hashed_key)
|
||||
return 0;
|
||||
if (protocol)
|
||||
{
|
||||
char tmp[256];
|
||||
sprintf (tmp, WS_RSP, hashed_key, "Sec-WebSocket-Protocol: %s\r\n");
|
||||
sprintf (handshake, tmp, protocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (handshake, WS_RSP, hashed_key, "");
|
||||
}
|
||||
free (hashed_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ws_server_add_client_protocol(struct netconn* conn,
|
||||
char* msg,
|
||||
uint16_t len,
|
||||
char* url,
|
||||
char* protocol,
|
||||
void (*callback)(uint8_t num,
|
||||
WEBSOCKET_TYPE_t type,
|
||||
char* msg,
|
||||
uint64_t len)) {
|
||||
int
|
||||
ws_server_add_client_protocol (struct netconn *conn, char *msg, uint16_t len,
|
||||
char *url, char *protocol,
|
||||
void (*callback) (uint8_t num,
|
||||
WEBSOCKET_TYPE_t type,
|
||||
char *msg, uint64_t len))
|
||||
{
|
||||
int ret;
|
||||
char handshake[256];
|
||||
|
||||
if(!prepare_response(msg,len,handshake,protocol)) {
|
||||
netconn_close(conn);
|
||||
netconn_delete(conn);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (!prepare_response (msg, len, handshake, protocol))
|
||||
{
|
||||
netconn_close (conn);
|
||||
netconn_delete (conn);
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
conn->callback = background_callback;
|
||||
netconn_write(conn,handshake,strlen(handshake),NETCONN_COPY);
|
||||
netconn_write (conn, handshake, strlen (handshake), NETCONN_COPY);
|
||||
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(clients[i].conn) continue;
|
||||
clients[i] = ws_connect_client(conn,url,NULL,callback);
|
||||
callback(i,WEBSOCKET_CONNECT,NULL,0);
|
||||
if(!ws_is_connected(clients[i])) {
|
||||
callback(i,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (clients[i].conn)
|
||||
continue;
|
||||
clients[i] = ws_connect_client (conn, url, NULL, callback);
|
||||
callback (i, WEBSOCKET_CONNECT, NULL, 0);
|
||||
if (!ws_is_connected (clients[i]))
|
||||
{
|
||||
callback (i, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
break;
|
||||
}
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_len_url(char* url) {
|
||||
int
|
||||
ws_server_len_url (char *url)
|
||||
{
|
||||
int ret;
|
||||
ret = 0;
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(clients[i].url && strcmp(url,clients[i].url)) ret++;
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (clients[i].url && strcmp (url, clients[i].url))
|
||||
ret++;
|
||||
}
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_add_client(struct netconn* conn,
|
||||
char* msg,
|
||||
uint16_t len,
|
||||
char* url,
|
||||
void (*callback)(uint8_t num,
|
||||
WEBSOCKET_TYPE_t type,
|
||||
char* msg,
|
||||
uint64_t len)) {
|
||||
|
||||
return ws_server_add_client_protocol(conn,msg,len,url,NULL,callback);
|
||||
int
|
||||
ws_server_add_client (struct netconn *conn, char *msg, uint16_t len, char *url,
|
||||
void (*callback) (uint8_t num, WEBSOCKET_TYPE_t type,
|
||||
char *msg, uint64_t len))
|
||||
{
|
||||
|
||||
return ws_server_add_client_protocol (conn, msg, len, url, NULL, callback);
|
||||
}
|
||||
|
||||
int ws_server_len_all() {
|
||||
int
|
||||
ws_server_len_all ()
|
||||
{
|
||||
int ret;
|
||||
ret = 0;
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(clients[i].conn) ret++;
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_remove_client(int num) {
|
||||
int ret = 0;
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
if(ws_is_connected(clients[num])) {
|
||||
clients[num].scallback(num,WEBSOCKET_DISCONNECT_INTERNAL,NULL,0);
|
||||
ws_disconnect_client(&clients[num], 0);
|
||||
ret = 1;
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_remove_clients(char* url) {
|
||||
int ret = 0;
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(ws_is_connected(clients[i]) && strcmp(url,clients[i].url)) {
|
||||
clients[i].scallback(i,WEBSOCKET_DISCONNECT_INTERNAL,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
ret += 1;
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (clients[i].conn)
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_remove_all() {
|
||||
int
|
||||
ws_server_remove_client (int num)
|
||||
{
|
||||
int ret = 0;
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(ws_is_connected(clients[i])) {
|
||||
clients[i].scallback(i,WEBSOCKET_DISCONNECT_INTERNAL,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
ret += 1;
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
if (ws_is_connected (clients[num]))
|
||||
{
|
||||
clients[num].scallback (num, WEBSOCKET_DISCONNECT_INTERNAL, NULL, 0);
|
||||
ws_disconnect_client (&clients[num], 0);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ws_server_remove_clients (char *url)
|
||||
{
|
||||
int ret = 0;
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ws_is_connected (clients[i]) && strcmp (url, clients[i].url))
|
||||
{
|
||||
clients[i].scallback (i, WEBSOCKET_DISCONNECT_INTERNAL, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
ret += 1;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ws_server_remove_all ()
|
||||
{
|
||||
int ret = 0;
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ws_is_connected (clients[i]))
|
||||
{
|
||||
clients[i].scallback (i, WEBSOCKET_DISCONNECT_INTERNAL, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
ret += 1;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// The following functions are already written below, but without the mutex.
|
||||
|
||||
int ws_server_send_text_client(int num,char* msg,uint64_t len) {
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
int ret = ws_server_send_text_client_from_callback(num, msg, len);
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
int
|
||||
ws_server_send_text_client (int num, char *msg, uint64_t len)
|
||||
{
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
int ret = ws_server_send_text_client_from_callback (num, msg, len);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_bin_client(int num,char* msg,uint64_t len) {
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
int ret = ws_server_send_bin_client_from_callback(num, msg, len);
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
int
|
||||
ws_server_send_bin_client (int num, char *msg, uint64_t len)
|
||||
{
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
int ret = ws_server_send_bin_client_from_callback (num, msg, len);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_text_clients(char* url,char* msg,uint64_t len) {
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
int ret = ws_server_send_text_clients_from_callback(url, msg, len);
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
int
|
||||
ws_server_send_text_clients (char *url, char *msg, uint64_t len)
|
||||
{
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
int ret = ws_server_send_text_clients_from_callback (url, msg, len);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_bin_clients(char* url,char* msg,uint64_t len) {
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
int ret = ws_server_send_bin_clients_from_callback(url, msg, len);
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
int
|
||||
ws_server_send_bin_clients (char *url, char *msg, uint64_t len)
|
||||
{
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
int ret = ws_server_send_bin_clients_from_callback (url, msg, len);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_text_all(char* msg,uint64_t len) {
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
int ret = ws_server_send_text_all_from_callback(msg, len);
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
int
|
||||
ws_server_send_text_all (char *msg, uint64_t len)
|
||||
{
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
int ret = ws_server_send_text_all_from_callback (msg, len);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
int ws_server_send_bin_all(char* msg,uint64_t len) {
|
||||
xSemaphoreTake(xwebsocket_mutex,portMAX_DELAY);
|
||||
int ret = ws_server_send_bin_all_from_callback(msg, len);
|
||||
xSemaphoreGive(xwebsocket_mutex);
|
||||
int
|
||||
ws_server_send_bin_all (char *msg, uint64_t len)
|
||||
{
|
||||
xSemaphoreTake (xwebsocket_mutex, portMAX_DELAY);
|
||||
int ret = ws_server_send_bin_all_from_callback (msg, len);
|
||||
xSemaphoreGive (xwebsocket_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// the following functions should be used inside of the callback. The regular versions
|
||||
// grab the mutex, but it is already grabbed from inside the callback so it will hang.
|
||||
// the following functions should be used inside of the callback. The regular
|
||||
// versions grab the mutex, but it is already grabbed from inside the callback
|
||||
// so it will hang.
|
||||
|
||||
int ws_server_send_text_client_from_callback(int num,char* msg,uint64_t len) {
|
||||
int
|
||||
ws_server_send_text_client_from_callback (int num, char *msg, uint64_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
if(ws_is_connected(clients[num])) {
|
||||
err = ws_send(&clients[num],WEBSOCKET_OPCODE_TEXT,msg,len,0);
|
||||
ret = 1;
|
||||
if(err) {
|
||||
clients[num].scallback(num,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[num], 0);
|
||||
ret = 0;
|
||||
if (ws_is_connected (clients[num]))
|
||||
{
|
||||
err = ws_send (&clients[num], WEBSOCKET_OPCODE_TEXT, msg, len, 0);
|
||||
ret = 1;
|
||||
if (err)
|
||||
{
|
||||
clients[num].scallback (num, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[num], 0);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int ws_server_send_bin_client_from_callback(int num,char* msg,uint64_t len) {
|
||||
int
|
||||
ws_server_send_bin_client_from_callback (int num, char *msg, uint64_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
if(ws_is_connected(clients[num])) {
|
||||
err = ws_send(&clients[num],WEBSOCKET_OPCODE_BIN,msg,len,0);
|
||||
ret = 1;
|
||||
if(err) {
|
||||
clients[num].scallback(num,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[num], 0);
|
||||
ret = 0;
|
||||
if (ws_is_connected (clients[num]))
|
||||
{
|
||||
err = ws_send (&clients[num], WEBSOCKET_OPCODE_BIN, msg, len, 0);
|
||||
ret = 1;
|
||||
if (err)
|
||||
{
|
||||
clients[num].scallback (num, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[num], 0);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_text_clients_from_callback(char* url,char* msg,uint64_t len) {
|
||||
int
|
||||
ws_server_send_text_clients_from_callback (char *url, char *msg, uint64_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(ws_is_connected(clients[i]) && strcmp(clients[i].url,url)) {
|
||||
err = ws_send(&clients[i],WEBSOCKET_OPCODE_TEXT,msg,len,0);
|
||||
if(!err) ret += 1;
|
||||
else {
|
||||
clients[i].scallback(i,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
}
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ws_is_connected (clients[i]) && strcmp (clients[i].url, url))
|
||||
{
|
||||
err = ws_send (&clients[i], WEBSOCKET_OPCODE_TEXT, msg, len, 0);
|
||||
if (!err)
|
||||
ret += 1;
|
||||
else
|
||||
{
|
||||
clients[i].scallback (i, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_bin_clients_from_callback(char* url,char* msg,uint64_t len) {
|
||||
int
|
||||
ws_server_send_bin_clients_from_callback (char *url, char *msg, uint64_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(ws_is_connected(clients[i]) && strcmp(clients[i].url,url)) {
|
||||
err = ws_send(&clients[i],WEBSOCKET_OPCODE_BIN,msg,len,0);
|
||||
if(!err) ret += 1;
|
||||
else {
|
||||
clients[i].scallback(i,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
}
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ws_is_connected (clients[i]) && strcmp (clients[i].url, url))
|
||||
{
|
||||
err = ws_send (&clients[i], WEBSOCKET_OPCODE_BIN, msg, len, 0);
|
||||
if (!err)
|
||||
ret += 1;
|
||||
else
|
||||
{
|
||||
clients[i].scallback (i, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_text_all_from_callback(char* msg,uint64_t len) {
|
||||
int
|
||||
ws_server_send_text_all_from_callback (char *msg, uint64_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(ws_is_connected(clients[i])) {
|
||||
err = ws_send(&clients[i],WEBSOCKET_OPCODE_TEXT,msg,len,0);
|
||||
if(!err) ret += 1;
|
||||
else {
|
||||
clients[i].scallback(i,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
}
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ws_is_connected (clients[i]))
|
||||
{
|
||||
err = ws_send (&clients[i], WEBSOCKET_OPCODE_TEXT, msg, len, 0);
|
||||
if (!err)
|
||||
ret += 1;
|
||||
else
|
||||
{
|
||||
clients[i].scallback (i, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ws_server_send_bin_all_from_callback(char* msg,uint64_t len) {
|
||||
int
|
||||
ws_server_send_bin_all_from_callback (char *msg, uint64_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
for(int i=0;i<WEBSOCKET_SERVER_MAX_CLIENTS;i++) {
|
||||
if(ws_is_connected(clients[i])) {
|
||||
err = ws_send(&clients[i],WEBSOCKET_OPCODE_BIN,msg,len,0);
|
||||
if(!err) ret += 1;
|
||||
else {
|
||||
clients[i].scallback(i,WEBSOCKET_DISCONNECT_ERROR,NULL,0);
|
||||
ws_disconnect_client(&clients[i], 0);
|
||||
}
|
||||
for (int i = 0; i < WEBSOCKET_SERVER_MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ws_is_connected (clients[i]))
|
||||
{
|
||||
err = ws_send (&clients[i], WEBSOCKET_OPCODE_BIN, msg, len, 0);
|
||||
if (!err)
|
||||
ret += 1;
|
||||
else
|
||||
{
|
||||
clients[i].scallback (i, WEBSOCKET_DISCONNECT_ERROR, NULL, 0);
|
||||
ws_disconnect_client (&clients[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
1739
main/main.c
1739
main/main.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user