status: spotify_error, the last Spotify session error and when it happened
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,8 @@ typedef struct {
|
|||||||
bool spotify_now_playing(spotify_track_t *t);
|
bool spotify_now_playing(spotify_track_t *t);
|
||||||
// Current state for status.spotify_state.
|
// Current state for status.spotify_state.
|
||||||
const char *spotify_state(void);
|
const char *spotify_state(void);
|
||||||
|
// Last session error (exception text and uptime) for status.spotify_error. False if none yet.
|
||||||
|
bool spotify_last_error(char *out, size_t len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "SpircHandler.h"
|
#include "SpircHandler.h"
|
||||||
#include "TrackPlayer.h"
|
#include "TrackPlayer.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "mdns.h"
|
#include "mdns.h"
|
||||||
@@ -39,6 +40,8 @@ static std::atomic<bool> s_got_blob{false};
|
|||||||
static std::atomic<bool> s_in_session{false}; // session() running (its tasks may exist)
|
static std::atomic<bool> s_in_session{false}; // session() running (its tasks may exist)
|
||||||
static std::atomic<int> s_volume{65535}; // player volume in Spotify units (0..65535)
|
static std::atomic<int> s_volume{65535}; // player volume in Spotify units (0..65535)
|
||||||
static std::atomic<const char *> s_state{"disabled"};
|
static std::atomic<const char *> s_state{"disabled"};
|
||||||
|
static std::mutex s_error_mutex;
|
||||||
|
static std::string s_error; // last session error, kept for the status
|
||||||
static std::atomic<uint64_t> s_pcm_bytes{0};
|
static std::atomic<uint64_t> s_pcm_bytes{0};
|
||||||
static std::shared_ptr<cspot::SpircHandler> s_handler; // running session, else null
|
static std::shared_ptr<cspot::SpircHandler> s_handler; // running session, else null
|
||||||
static spotify_pcm_cb_t s_pcm_cb;
|
static spotify_pcm_cb_t s_pcm_cb;
|
||||||
@@ -230,6 +233,13 @@ const char *spotify_state(void)
|
|||||||
return s_state.load();
|
return s_state.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool spotify_last_error(char *out, size_t len)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(s_error_mutex);
|
||||||
|
snprintf(out, len, "%s", s_error.c_str());
|
||||||
|
return !s_error.empty();
|
||||||
|
}
|
||||||
|
|
||||||
/* ----- cspot/bell logging -> esp_log (UART + syslog) ----- */
|
/* ----- cspot/bell logging -> esp_log (UART + syslog) ----- */
|
||||||
|
|
||||||
// cspot logs through bell::bellGlobalLogger; without one, CSPOT_LOG dereferences NULL.
|
// cspot logs through bell::bellGlobalLogger; without one, CSPOT_LOG dereferences NULL.
|
||||||
@@ -494,6 +504,8 @@ static void spotify_task(void *arg)
|
|||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
s_state = "error";
|
s_state = "error";
|
||||||
ESP_LOGE(TAG, "session ended: %s", e.what());
|
ESP_LOGE(TAG, "session ended: %s", e.what());
|
||||||
|
std::lock_guard<std::mutex> lock(s_error_mutex);
|
||||||
|
s_error = std::string(e.what()) + " (at " + std::to_string(esp_timer_get_time() / 1000000) + " s)";
|
||||||
}
|
}
|
||||||
s_handler.reset();
|
s_handler.reset();
|
||||||
s_in_session = false;
|
s_in_session = false;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ source (cspot Spotify Connect | HLS player) -> decode (Vorbis/AAC/MP3) -> SRC 44
|
|||||||
## Project config group
|
## Project config group
|
||||||
- source: {mode: spotify|hls|auto|tone|pink|off, spotify_name, spotify_bitrate, hls_url, autoplay, gain_db, failover_delay_s, failover_on_pause, spotify_client_id, spotify_client_secret}
|
- source: {mode: spotify|hls|auto|tone|pink|off, spotify_name, spotify_bitrate, hls_url, autoplay, gain_db, failover_delay_s, failover_on_pause, spotify_client_id, spotify_client_secret}
|
||||||
- spotify_client_id / spotify_client_secret: each user's own Spotify developer app (developer.spotify.com, Premium account), needed by the maintained cspot fork (philippe44/cspot) since Spotify's 2025 API restrictions. The secret is write-only (never returned by GET /api/config). spotify_state reports "no client credentials" while either is missing.
|
- spotify_client_id / spotify_client_secret: each user's own Spotify developer app (developer.spotify.com, Premium account), needed by the maintained cspot fork (philippe44/cspot) since Spotify's 2025 API restrictions. The secret is write-only (never returned by GET /api/config). spotify_state reports "no client credentials" while either is missing.
|
||||||
- Project status fields: active_source, source_state, spotify_state, buffer_ms
|
- Project status fields: active_source, source_state, spotify_state, buffer_ms; spotify_error (last session error with the uptime it happened at, e.g. "Can't connect to spotify servers (at 412 s)"; only present after one)
|
||||||
- mode "tone": the core's 1 kHz / -18 dBFS test tone, phase-locked to PTP (commissioning, e.g. Riedel import tests). "pink": the core's pink noise, -18 dBFS RMS (peaks about -6 dBFS), same on L and R (level/EQ checks). Neither is affected by volume or gain. "off": silence.
|
- mode "tone": the core's 1 kHz / -18 dBFS test tone, phase-locked to PTP (commissioning, e.g. Riedel import tests). "pink": the core's pink noise, -18 dBFS RMS (peaks about -6 dBFS), same on L and R (level/EQ checks). Neither is affected by volume or gain. "off": silence.
|
||||||
|
|
||||||
## Player control API (project routes)
|
## Player control API (project routes)
|
||||||
|
|||||||
@@ -390,6 +390,10 @@ static void player_status(cJSON *st)
|
|||||||
cJSON_AddStringToObject(st, "active_source", SRC_NAME[src]);
|
cJSON_AddStringToObject(st, "active_source", SRC_NAME[src]);
|
||||||
cJSON_AddStringToObject(st, "source_state", state);
|
cJSON_AddStringToObject(st, "source_state", state);
|
||||||
cJSON_AddStringToObject(st, "spotify_state", spotify_state());
|
cJSON_AddStringToObject(st, "spotify_state", spotify_state());
|
||||||
|
char err[96];
|
||||||
|
if (spotify_last_error(err, sizeof(err))) {
|
||||||
|
cJSON_AddStringToObject(st, "spotify_error", err);
|
||||||
|
}
|
||||||
cJSON_AddNumberToObject(st, "buffer_ms", (double)(audio_ring_level() * 1000 / RATE));
|
cJSON_AddNumberToObject(st, "buffer_ms", (double)(audio_ring_level() * 1000 / RATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user