Compare commits

..

6 Commits

Author SHA1 Message Date
philippe44
38fee20680 better handling of AIrPlay network issues - release 2023-09-11 18:36:08 -07:00
philippe44
12ae3d08b6 Update README.md 2023-09-11 13:28:06 -07:00
github-actions
2931a5100e Update prebuilt objects [skip actions] 2023-09-11 05:32:43 +00:00
philippe44
c148cd16ae Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into master-v4.3 2023-09-10 22:27:41 -07:00
philippe44
38fb90d179 pseudo-idle task requires more stack (cJSON) - release 2023-09-10 22:27:36 -07:00
github-actions
61ff6a8915 Update prebuilt objects [skip actions] 2023-09-10 05:15:25 +00:00
29 changed files with 76 additions and 55 deletions

View File

@@ -498,7 +498,7 @@ model=dm9051|w5500,cs=<gpio>,speed=<clk_in_Hz>,intr=<gpio>[,rst=<gpio>]
### Battery / ADC
The NVS parameter "bat_config" sets the ADC1 channel used to measure battery/DC voltage. The "atten" value attenuates the input voltage to the ADC input (the read value maintains a 0-1V rage) where: 0=no attenuation(0..800mV), 1=2.5dB attenuation(0..1.1V), 2=6dB attenuation(0..1.35V), 3=11dB attenuation(0..2.6V). Scale is a float ratio applied to every sample of the 12 bits ADC. A measure is taken every 10s and an average is made every 5 minutes (not a sliding window). Syntax is
```
channel=0..7,scale=<scale>,cells=<2|3>[,atten=<0|1|2|3>]
channel=0..7,scale=<scale>,cells=<1..3>[,atten=<0|1|2|3>]
```
NB: Set parameter to empty to disable battery reading. For named configurations (SqueezeAMP, Muse ...), this is ignored (except for SqueezeAMP where number of cells is required)

View File

@@ -276,6 +276,7 @@ bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
free(ctx);
}
/*----------------------------------------------------------------------------*/
bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
struct sockaddr_in addr;
@@ -325,7 +326,7 @@ bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
break;
}
default:
break;
break;
}
// no command to send to remote or no remote found yet
@@ -348,16 +349,19 @@ bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
asprintf(&method, "GET /ctrl-int/1/%s HTTP/1.0", command);
kd_add(headers, "Active-Remote", ctx->active_remote.id);
kd_add(headers, "Connection", "close");
kd_add(headers, "Connection", "close");
buf = http_send(sock, method, headers);
len = recv(sock, resp, 512, 0);
if (len > 0) resp[len-1] = '\0';
if (len > 0) resp[len-1] = '\0';
LOG_INFO("[%p]: sending airplay remote\n%s<== received ==>\n%s", ctx, buf, resp);
NFREE(method);
NFREE(buf);
kd_free(headers);
success = true;
} else {
kd_free(headers);
LOG_INFO("[%p]: can't connect to remote for %s", ctx, command);
}
free(command);

View File

@@ -119,7 +119,12 @@ static bool cmd_handler(raop_event_t event, ...) {
break;
case RAOP_FLUSH:
displayer_control(DISPLAYER_TIMER_PAUSE);
break;
break;
case RAOP_STALLED:
raop_abort(raop);
actrls_unset();
displayer_control(DISPLAYER_SHUTDOWN);
break;
case RAOP_STOP:
actrls_unset();
displayer_control(DISPLAYER_SUSPEND);
@@ -191,8 +196,7 @@ void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) {
*/
void raop_disconnect(void) {
LOG_INFO("forced disconnection");
displayer_control(DISPLAYER_SHUTDOWN);
// in case we can't communicate with AirPlay controller, abort session
if (!raop_cmd(raop, RAOP_STOP, NULL)) raop_abort(raop);
actrls_unset();
if (!raop_cmd(raop, RAOP_STOP, NULL)) cmd_handler(RAOP_STALLED);
else displayer_control(DISPLAYER_SHUTDOWN);
}

View File

@@ -14,7 +14,7 @@
#define RAOP_SAMPLE_RATE 44100
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_ARTWORK, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP,
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_ARTWORK, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP, RAOP_STALLED,
RAOP_VOLUME, RAOP_TIMING, RAOP_PREV, RAOP_NEXT, RAOP_REW, RAOP_FWD,
RAOP_VOLUME_UP, RAOP_VOLUME_DOWN, RAOP_RESUME, RAOP_TOGGLE } raop_event_t ;

View File

@@ -82,7 +82,7 @@ static log_level *loglevel = &raop_loglevel;
#define RTP_SYNC (0x01)
#define NTP_SYNC (0x02)
#define RESEND_TO 200
#define RESEND_TO 250
enum { DATA = 0, CONTROL, TIMING };
@@ -149,6 +149,7 @@ typedef struct rtp_s {
struct alac_codec_s *alac_codec;
int flush_seqno;
bool playing;
int stalled;
raop_data_cb_t data_cb;
raop_cmd_cb_t cmd_cb;
} rtp_t;
@@ -466,26 +467,27 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
abuf = ctx->audio_buffer + BUFIDX(seqno);
ctx->ab_write = seqno;
LOG_SDEBUG("packet expected seqno:%hu rtptime:%u (W:%hu R:%hu)", seqno, rtptime, ctx->ab_write, ctx->ab_read);
} else if (seq_order(ctx->ab_write, seqno)) {
seq_t i;
u32_t now;
// newer than expected
if (ctx->latency && seq_order(ctx->latency / ctx->frame_size, seqno - ctx->ab_write - 1)) {
// only get rtp latency-1 frames back (last one is seqno)
LOG_WARN("[%p] too many missing frames %hu seq: %hu, (W:%hu R:%hu)", ctx, seqno - ctx->ab_write - 1, seqno, ctx->ab_write, ctx->ab_read);
ctx->ab_write = seqno - ctx->latency / ctx->frame_size;
}
// this is a shitstorm, reset buffer
LOG_WARN("[%p] too many missing frames %hu seq: %hu, (W:%hu R:%hu)", ctx, seqno - ctx->ab_write - 1, seqno, ctx->ab_write, ctx->ab_read);
ctx->ab_read = seqno;
} else {
// request re-send missed frames and evaluate resent date as a whole *after*
rtp_request_resend(ctx, ctx->ab_write + 1, seqno-1);
// resend date is after all requests have been sent
u32_t now = gettime_ms();
// set expected timing of missed frames for buffer_push_packet and set last_resend date
for (seq_t i = ctx->ab_write + 1; seq_order(i, seqno); i++) {
ctx->audio_buffer[BUFIDX(i)].rtptime = rtptime - (seqno-i)*ctx->frame_size;
ctx->audio_buffer[BUFIDX(i)].last_resend = now;
}
LOG_DEBUG("[%p]: packet newer seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);
}
// need to request re-send and adjust timing of gaps
rtp_request_resend(ctx, ctx->ab_write + 1, seqno-1);
for (now = gettime_ms(), i = ctx->ab_write + 1; seq_order(i, seqno); i++) {
ctx->audio_buffer[BUFIDX(i)].rtptime = rtptime - (seqno-i)*ctx->frame_size;
ctx->audio_buffer[BUFIDX(i)].last_resend = now;
}
LOG_DEBUG("[%p]: packet newer seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);
abuf = ctx->audio_buffer + BUFIDX(seqno);
ctx->ab_write = seqno;
} else if (seq_order(ctx->ab_read, seqno + 1)) {
@@ -524,10 +526,9 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
static void buffer_push_packet(rtp_t *ctx) {
abuf_t *curframe = NULL;
u32_t now, playtime, hold = max((ctx->latency * 1000) / (8 * RAOP_SAMPLE_RATE), 100);
int i;
// not ready to play yet
if (!ctx->playing || ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return;
if (!ctx->playing || ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return;
// there is always at least one frame in the buffer
do {
@@ -573,10 +574,11 @@ static void buffer_push_packet(rtp_t *ctx) {
LOG_SDEBUG("playtime %u %d [W:%hu R:%hu] %d", playtime, playtime - now, ctx->ab_write, ctx->ab_read, curframe->ready);
// each missing packet will be requested up to (latency_frames / 16) times
for (i = 0; seq_order(ctx->ab_read + i, ctx->ab_write); i += 16) {
for (int i = 0; seq_order(ctx->ab_read + i, ctx->ab_write); i += 16) {
abuf_t *frame = ctx->audio_buffer + BUFIDX(ctx->ab_read + i);
if (!frame->ready && now - frame->last_resend > RESEND_TO) {
rtp_request_resend(ctx, ctx->ab_read + i, ctx->ab_read + i);
// stop if one fails
if (!rtp_request_resend(ctx, ctx->ab_read + i, ctx->ab_read + i)) break;
frame->last_resend = now;
}
}
@@ -613,7 +615,10 @@ static void rtp_thread_func(void *arg) {
FD_ZERO(&fds);
for (i = 0; i < 3; i++) { FD_SET(ctx->rtp_sockets[i].sock, &fds); }
if (select(sock + 1, &fds, NULL, NULL, &timeout) <= 0) {
if (ctx->stalled++ == 30*10) ctx->cmd_cb(RAOP_STALLED);
continue;
}
for (i = 0; i < 3; i++)
@@ -631,6 +636,7 @@ static void rtp_thread_func(void *arg) {
continue;
}
assert(plen <= MAX_PACKET);
ctx->stalled = 0;
type = packet[1] & ~0x80;
@@ -823,6 +829,7 @@ static bool rtp_request_resend(rtp_t *ctx, seq_t first, seq_t last) {
ctx->rtp_host.sin_port = htons(ctx->rtp_sockets[CONTROL].rport);
if (sizeof(req) != sendto(ctx->rtp_sockets[CONTROL].sock, req, sizeof(req), MSG_DONTWAIT, (struct sockaddr*) &ctx->rtp_host, sizeof(ctx->rtp_host))) {
LOG_WARN("[%p]: SENDTO failed (%s)", ctx, strerror(errno));
return false;
}

View File

@@ -26,7 +26,7 @@
#include "cJSON.h"
#include "tools.h"
#define PSEUDO_IDLE_STACK_SIZE (3*1024)
#define PSEUDO_IDLE_STACK_SIZE (6*1024)
#define MONITOR_TIMER (10*1000)
#define SCRATCH_SIZE 256
@@ -62,7 +62,7 @@ static void task_stats( cJSON* top ) {
current.n = uxTaskGetSystemState( current.tasks, current.n, &current.total );
cJSON_AddNumberToObject(top,"ntasks",current.n);
char scratch[SCRATCH_SIZE] = { 0 };
char scratch[SCRATCH_SIZE] = { };
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
#pragma message("Compiled with runtime stats")

View File

@@ -289,6 +289,7 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
raop_sync.enabled = !strcasestr(output.device, "BT");
output.next_sample_rate = output.current_sample_rate = RAOP_SAMPLE_RATE;
break;
case RAOP_STALLED:
case RAOP_STOP:
output.external = 0;
__attribute__ ((fallthrough));
@@ -492,7 +493,6 @@ void decode_restore(int external) {
#if CONFIG_AIRPLAY_SINK
case DECODE_RAOP:
raop_disconnect();
raop_state = RAOP_STOP;
break;
#endif
#if CONFIG_CSPOT_SINK

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -60,6 +60,8 @@ declare function getStatus(): {};
declare function getStatus(): {};
declare function getStatus(): {};
declare function getStatus(): {};
declare function getStatus(): {};
declare function getStatus(): {};
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
@@ -122,6 +124,10 @@ declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function pushStatus(): void;
declare function pushStatus(): void;
declare function pushStatus(): void;
declare function pushStatus(): void;
declare function pushStatus(): void;

View File

@@ -1,5 +1,5 @@
target_add_binary_data( __idf_wifi-manager webapp/dist/css/index.99c86edb045064f0ff9e.css.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/favicon-32x32.png BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/index.html.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/js/index.3bdc2f.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/js/node_vendors.3bdc2f.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/js/index.60b519.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/js/node_vendors.60b519.bundle.js.gz BINARY)

View File

@@ -6,29 +6,29 @@ extern const uint8_t _favicon_32x32_png_start[] asm("_binary_favicon_32x32_png_s
extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end");
extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start");
extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end");
extern const uint8_t _index_3bdc2f_bundle_js_gz_start[] asm("_binary_index_3bdc2f_bundle_js_gz_start");
extern const uint8_t _index_3bdc2f_bundle_js_gz_end[] asm("_binary_index_3bdc2f_bundle_js_gz_end");
extern const uint8_t _node_vendors_3bdc2f_bundle_js_gz_start[] asm("_binary_node_vendors_3bdc2f_bundle_js_gz_start");
extern const uint8_t _node_vendors_3bdc2f_bundle_js_gz_end[] asm("_binary_node_vendors_3bdc2f_bundle_js_gz_end");
extern const uint8_t _index_60b519_bundle_js_gz_start[] asm("_binary_index_60b519_bundle_js_gz_start");
extern const uint8_t _index_60b519_bundle_js_gz_end[] asm("_binary_index_60b519_bundle_js_gz_end");
extern const uint8_t _node_vendors_60b519_bundle_js_gz_start[] asm("_binary_node_vendors_60b519_bundle_js_gz_start");
extern const uint8_t _node_vendors_60b519_bundle_js_gz_end[] asm("_binary_node_vendors_60b519_bundle_js_gz_end");
const char * resource_lookups[] = {
"/css/index.99c86edb045064f0ff9e.css.gz",
"/favicon-32x32.png",
"/index.html.gz",
"/js/index.3bdc2f.bundle.js.gz",
"/js/node_vendors.3bdc2f.bundle.js.gz",
"/js/index.60b519.bundle.js.gz",
"/js/node_vendors.60b519.bundle.js.gz",
""
};
const uint8_t * resource_map_start[] = {
_index_99c86edb045064f0ff9e_css_gz_start,
_favicon_32x32_png_start,
_index_html_gz_start,
_index_3bdc2f_bundle_js_gz_start,
_node_vendors_3bdc2f_bundle_js_gz_start
_index_60b519_bundle_js_gz_start,
_node_vendors_60b519_bundle_js_gz_start
};
const uint8_t * resource_map_end[] = {
_index_99c86edb045064f0ff9e_css_gz_end,
_favicon_32x32_png_end,
_index_html_gz_end,
_index_3bdc2f_bundle_js_gz_end,
_node_vendors_3bdc2f_bundle_js_gz_end
_index_60b519_bundle_js_gz_end,
_node_vendors_60b519_bundle_js_gz_end
};

View File

@@ -1,6 +1,6 @@
/***********************************
webpack_headers
dist/css/index.99c86edb045064f0ff9e.css.gz,dist/favicon-32x32.png,dist/index.html.gz,dist/js/index.3bdc2f.bundle.js.gz,dist/js/node_vendors.3bdc2f.bundle.js.gz
dist/css/index.99c86edb045064f0ff9e.css.gz,dist/favicon-32x32.png,dist/index.html.gz,dist/js/index.60b519.bundle.js.gz,dist/js/node_vendors.60b519.bundle.js.gz
***********************************/
#pragma once
#include <inttypes.h>

Binary file not shown.

Binary file not shown.

BIN
server_certs/r2m01.cer.22 Normal file

Binary file not shown.

BIN
server_certs/r2m01.cer.23 Normal file

Binary file not shown.