status: hls download stats (last segment speed, failed requests, last error)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+49
-2
@@ -1,9 +1,11 @@
|
||||
#include "hls.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "esp_crt_bundle.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_http_client.h"
|
||||
@@ -39,6 +41,44 @@ static char s_media_url[URL_MAX];
|
||||
static uint8_t *s_seg; // current segment (PSRAM)
|
||||
static volatile unsigned s_suspended; // HLS_SUSPEND_* bits
|
||||
|
||||
// Download statistics for the status (hls_status), guarded by s_stat_lock.
|
||||
static portMUX_TYPE s_stat_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static struct {
|
||||
uint32_t seg_bytes, seg_ms; // last complete segment
|
||||
uint32_t errors; // failed requests since boot
|
||||
char error[128]; // last one, with the uptime it happened at
|
||||
} s_stat;
|
||||
|
||||
// Log a failed request and keep it for the status.
|
||||
static void fail(const char *fmt, ...)
|
||||
{
|
||||
char msg[96];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
ESP_LOGW(TAG, "%s", msg);
|
||||
taskENTER_CRITICAL(&s_stat_lock);
|
||||
s_stat.errors++;
|
||||
snprintf(s_stat.error, sizeof(s_stat.error), "%s (at %lld s)", msg, esp_timer_get_time() / 1000000);
|
||||
taskEXIT_CRITICAL(&s_stat_lock);
|
||||
}
|
||||
|
||||
void hls_status(cJSON *st)
|
||||
{
|
||||
taskENTER_CRITICAL(&s_stat_lock);
|
||||
typeof(s_stat) t = s_stat;
|
||||
taskEXIT_CRITICAL(&s_stat_lock);
|
||||
cJSON *o = cJSON_AddObjectToObject(st, "hls");
|
||||
cJSON_AddNumberToObject(o, "seg_bytes", t.seg_bytes);
|
||||
cJSON_AddNumberToObject(o, "seg_ms", t.seg_ms);
|
||||
cJSON_AddNumberToObject(o, "seg_mbit", t.seg_ms ? t.seg_bytes * 8.0 / t.seg_ms / 1000 : 0);
|
||||
cJSON_AddNumberToObject(o, "errors", t.errors);
|
||||
if (t.error[0]) {
|
||||
cJSON_AddStringToObject(o, "error", t.error);
|
||||
}
|
||||
}
|
||||
|
||||
void hls_suspend(unsigned reason, bool suspend)
|
||||
{
|
||||
if (suspend) {
|
||||
@@ -89,7 +129,7 @@ static esp_http_client_handle_t http_open(const char *url)
|
||||
for (int i = 0; i <= MAX_REDIRECTS; i++) {
|
||||
esp_err_t err = esp_http_client_open(c, 0);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "open %s: %s", url, esp_err_to_name(err));
|
||||
fail("open %s: %s", url, esp_err_to_name(err));
|
||||
break;
|
||||
}
|
||||
esp_http_client_fetch_headers(c);
|
||||
@@ -103,7 +143,7 @@ static esp_http_client_handle_t http_open(const char *url)
|
||||
if (st == 200) {
|
||||
return c;
|
||||
}
|
||||
ESP_LOGW(TAG, "GET %s: HTTP %d", url, st);
|
||||
fail("GET %s: HTTP %d", url, st);
|
||||
break;
|
||||
}
|
||||
esp_http_client_cleanup(c);
|
||||
@@ -238,10 +278,17 @@ static bool fetch_segment(long long seq, const char *url)
|
||||
}
|
||||
if (r < 0 || total == SEG_MAX) {
|
||||
ok = false;
|
||||
fail("segment %lld: %s after %u bytes", seq, r < 0 ? "read error" : "too large", (unsigned)total);
|
||||
}
|
||||
esp_http_client_close(c);
|
||||
esp_http_client_cleanup(c);
|
||||
int64_t us = esp_timer_get_time() - t0;
|
||||
if (ok) {
|
||||
taskENTER_CRITICAL(&s_stat_lock);
|
||||
s_stat.seg_bytes = total;
|
||||
s_stat.seg_ms = us / 1000;
|
||||
taskEXIT_CRITICAL(&s_stat_lock);
|
||||
}
|
||||
ESP_LOGD(TAG, "segment %lld: %u bytes in %.2f s (%.1f Mbit/s)%s", seq, (unsigned)total, us / 1e6,
|
||||
us ? total * 8.0 / us : 0.0, ok ? "" : ", failed");
|
||||
if (ok && s_sink) {
|
||||
|
||||
Reference in New Issue
Block a user