mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 04:27:12 +03:00
Give some love to AIrPlay/BT screens + better "safe TCB release" - release
This commit is contained in:
@@ -98,12 +98,14 @@ void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y,
|
||||
}
|
||||
}
|
||||
|
||||
bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) {
|
||||
struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) {
|
||||
const struct GDS_FontDef* OldFont = Display->Font;
|
||||
|
||||
Display->FontForceProportional = false;
|
||||
Display->FontForceMonospace = false;
|
||||
Display->Font = Font;
|
||||
|
||||
return true;
|
||||
return OldFont;
|
||||
}
|
||||
|
||||
void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) {
|
||||
|
||||
@@ -46,7 +46,7 @@ typedef enum {
|
||||
TextAnchor_Center
|
||||
} TextAnchor;
|
||||
|
||||
bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font );
|
||||
struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font );
|
||||
|
||||
void GDS_FontForceProportional( struct GDS_Device* Display, bool Force );
|
||||
void GDS_FontForceMonospace( struct GDS_Device* Display, bool Force );
|
||||
@@ -59,7 +59,8 @@ int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display );
|
||||
|
||||
int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character );
|
||||
int GDS_FontGetCharHeight( struct GDS_Device* Display );
|
||||
int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text );\
|
||||
int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text );
|
||||
int GDS_FontMeasureStringLine( struct GDS_Device* Display, int Line, const char* Text );
|
||||
|
||||
void GDS_FontDrawChar( struct GDS_Device* Display, char Character, int x, int y, int Color );
|
||||
void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color );
|
||||
|
||||
@@ -121,6 +121,19 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
|
||||
return Width + X < Device->Width;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text) {
|
||||
struct GDS_FontDef *Font = GDS_SetFont( Device, Device->Lines[N-1].Font );
|
||||
|
||||
if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true );
|
||||
int Width = GDS_FontMeasureString( Device, Text );
|
||||
GDS_SetFont( Device, Font );
|
||||
|
||||
return Width;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Try to align string for better scrolling visual. there is probably much better to do
|
||||
*/
|
||||
|
||||
@@ -31,5 +31,6 @@ struct GDS_Device;
|
||||
bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space);
|
||||
bool GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space);
|
||||
bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text);
|
||||
int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text);
|
||||
int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max);
|
||||
void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...);
|
||||
@@ -41,7 +41,12 @@ static EXT_RAM_ATTR struct {
|
||||
int offset, boundary;
|
||||
char *metadata_config;
|
||||
bool timer, refresh;
|
||||
uint32_t elapsed, duration;
|
||||
uint32_t elapsed;
|
||||
struct {
|
||||
uint32_t value;
|
||||
char string[8]; // H:MM:SS
|
||||
bool visible;
|
||||
} duration;
|
||||
TickType_t tick;
|
||||
} displayer;
|
||||
|
||||
@@ -126,7 +131,7 @@ void display_init(char *welcome) {
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
|
||||
static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
|
||||
GDS_SetLayout( display, strcasestr(config, "HFlip"), strcasestr(config, "VFlip"), strcasestr(config, "rotate"));
|
||||
GDS_SetLayout(display, strcasestr(config, "HFlip"), strcasestr(config, "VFlip"), strcasestr(config, "rotate"));
|
||||
GDS_SetFont(display, &Font_droid_sans_fallback_15x17 );
|
||||
GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome);
|
||||
|
||||
@@ -193,23 +198,34 @@ static void displayer_task(void *args) {
|
||||
|
||||
// handler elapsed track time
|
||||
if (displayer.timer && displayer.state == DISPLAYER_ACTIVE) {
|
||||
char line[20], duration[12] = "";
|
||||
char line[19] = "-", *_line = line + 1; // [-]H:MM:SS / H:MM:SS
|
||||
TickType_t tick = xTaskGetTickCount();
|
||||
uint32_t elapsed = (tick - displayer.tick) * portTICK_PERIOD_MS;
|
||||
|
||||
if (elapsed >= 1000) {
|
||||
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
|
||||
displayer.tick = tick;
|
||||
displayer.elapsed += elapsed / 1000;
|
||||
elapsed = displayer.elapsed += elapsed / 1000;
|
||||
xSemaphoreGive(displayer.mutex);
|
||||
if (displayer.duration > 0) {
|
||||
if (displayer.duration < 3600) snprintf(duration, sizeof(duration), " / %u:%02u", displayer.duration / 60, displayer.duration % 60);
|
||||
else snprintf(duration, sizeof(duration), " / %u:%02u:%02u", (displayer.duration / 3600) % 100, (displayer.duration % 3600) / 60, displayer.duration % 60);
|
||||
|
||||
// when we have duration but no space, display remaining time
|
||||
if (displayer.duration.value && !displayer.duration.visible) elapsed = displayer.duration.value - elapsed;
|
||||
|
||||
if (elapsed < 3600) sprintf(_line, "%u:%02u", elapsed / 60, elapsed % 60);
|
||||
else sprintf(_line, "%u:%02u:%02u", (elapsed / 3600) % 100, (elapsed % 3600) / 60, elapsed % 60);
|
||||
|
||||
// concatenate if we have room for elapsed / duration
|
||||
if (displayer.duration.visible) {
|
||||
strcat(_line, "/");
|
||||
strcat(_line, displayer.duration.string);
|
||||
} else if (displayer.duration.value) {
|
||||
_line--;
|
||||
}
|
||||
if (displayer.elapsed < 3600) snprintf(line, sizeof(line), "%*u:%02u", sizeof(line) - 1 - strlen(duration) - 3, displayer.elapsed / 60, displayer.elapsed % 60);
|
||||
else snprintf(line, sizeof(line), "%*u:%02u:%02u", sizeof(line) - 1 - strlen(duration) - 6, (displayer.elapsed / 3600) % 100, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60);
|
||||
strcat(line, duration);
|
||||
GDS_TextLine(display, 1, GDS_TEXT_RIGHT, (GDS_TEXT_CLEAR | GDS_TEXT_CLEAR_EOL) | GDS_TEXT_UPDATE, line);
|
||||
|
||||
// just re-write the whole line it's easier
|
||||
GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR, displayer.header);
|
||||
GDS_TextLine(display, 1, GDS_TEXT_RIGHT, GDS_TEXT_UPDATE, _line);
|
||||
|
||||
timer_sleep = 1000;
|
||||
} else timer_sleep = max(1000 - elapsed, 0);
|
||||
} else timer_sleep = DEFAULT_SLEEP;
|
||||
@@ -323,9 +339,27 @@ void displayer_timer(enum displayer_time_e mode, int elapsed, int duration) {
|
||||
|
||||
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
|
||||
|
||||
if (elapsed >= 0) displayer.elapsed = elapsed / 1000;
|
||||
if (duration >= 0) displayer.duration = duration / 1000;
|
||||
if (displayer.timer) displayer.tick = xTaskGetTickCount();
|
||||
if (elapsed >= 0) displayer.elapsed = elapsed / 1000;
|
||||
if (duration > 0) {
|
||||
displayer.duration.visible = true;
|
||||
displayer.duration.value = duration / 1000;
|
||||
|
||||
if (displayer.duration.value > 3600) sprintf(displayer.duration.string, "%u:%02u:%02u", (displayer.duration.value / 3600) % 10,
|
||||
(displayer.duration.value % 3600) / 60, displayer.duration.value % 60);
|
||||
else sprintf(displayer.duration.string, "%u:%02u", displayer.duration.value / 60, displayer.duration.value % 60);
|
||||
|
||||
char *buf;
|
||||
asprintf(&buf, "%s %s/%s", displayer.header, displayer.duration.string, displayer.duration.string);
|
||||
if (GDS_GetTextWidth(display, 1, 0, buf) > GDS_GetWidth(display)) {
|
||||
ESP_LOGW(TAG, "Can't fit duration %s (%d) on screen using elapsed only", buf, GDS_GetTextWidth(display, 1, 0, buf));
|
||||
displayer.duration.visible = false;
|
||||
}
|
||||
free(buf);
|
||||
} else if (!duration) {
|
||||
displayer.duration.visible = false;
|
||||
displayer.duration.value = 0;
|
||||
}
|
||||
|
||||
xSemaphoreGive(displayer.mutex);
|
||||
}
|
||||
@@ -350,7 +384,8 @@ void displayer_control(enum displayer_cmd_e cmd, ...) {
|
||||
displayer.timer = false;
|
||||
displayer.refresh = true;
|
||||
displayer.string[0] = '\0';
|
||||
displayer.elapsed = displayer.duration = 0;
|
||||
displayer.elapsed = displayer.duration.value = 0;
|
||||
displayer.duration.visible = false;
|
||||
displayer.offset = displayer.boundary = 0;
|
||||
display_bus(&displayer, DISPLAY_BUS_TAKE);
|
||||
vTaskResume(displayer.task);
|
||||
|
||||
@@ -26,7 +26,7 @@ static const uint8_t Square721_BT11x14[] = {
|
||||
0x02, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char ,
|
||||
0x04, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char -
|
||||
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char .
|
||||
0x04, 0x00, 0x0C, 0x80, 0x03, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char /
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x80, 0x03, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char /
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 0
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x04, 0x08, 0x04, 0xF8, 0x07, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 1
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x30, 0x07, 0x08, 0x05, 0x88, 0x04, 0x88, 0x04, 0x88, 0x04, 0x70, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 2
|
||||
|
||||
@@ -255,7 +255,7 @@ void raop_delete(struct raop_ctx_s *ctx) {
|
||||
|
||||
// brute-force exit of accept()
|
||||
shutdown(ctx->sock, SHUT_RDWR);
|
||||
closesocket(ctx->sock);
|
||||
closesocket(ctx->sock);
|
||||
|
||||
// wait to make sure LWIP if scheduled (avoid issue with NotifyTake)
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
@@ -607,7 +607,6 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
volume = (volume == -144.0) ? 0 : (1 + volume / 30);
|
||||
success = ctx->cmd_cb(RAOP_VOLUME, volume);
|
||||
} else if (body && (p = strcasestr(body, "progress")) != NULL) {
|
||||
int start, current, stop = 0;
|
||||
int start, current, stop = 0;
|
||||
|
||||
// we want ms, not s
|
||||
@@ -674,7 +673,7 @@ void cleanup_rtsp(raop_ctx_t *ctx, bool abort) {
|
||||
if (ctx->active_remote.running) {
|
||||
#ifdef WIN32
|
||||
pthread_join(ctx->active_remote.thread, NULL);
|
||||
close_mDNS(ctx->active_remote.handle);
|
||||
close_mDNS(ctx->active_remote.handle);
|
||||
#else
|
||||
// need to make sure no search is on-going and reclaim task memory
|
||||
ctx->active_remote.running = false;
|
||||
|
||||
@@ -313,7 +313,7 @@ void rtp_end(rtp_t *ctx)
|
||||
#else
|
||||
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
|
||||
vTaskDelete(ctx->thread);
|
||||
SAFE_TCB_FREE(ctx->xTaskBuffer);
|
||||
SAFE_PTR_FREE(ctx->xTaskBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
#include "platform.h"
|
||||
#include "pthread.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#endif
|
||||
|
||||
#define NFREE(p) if (p) { free(p); p = NULL; }
|
||||
|
||||
typedef struct metadata_s {
|
||||
@@ -46,19 +51,21 @@ char *strndup(const char *s, size_t n);
|
||||
char *strndup(const char *s, size_t n);
|
||||
int asprintf(char **strp, const char *fmt, ...);
|
||||
void winsock_init(void);
|
||||
void winsock_close(void);
|
||||
void winsock_close(void);
|
||||
#define SAFE_PTR_FREE(P) free(P)
|
||||
#else
|
||||
char *strlwr(char *str);
|
||||
|
||||
|
||||
// reason is that TCB might be cleanup in idle task
|
||||
#define SAFE_TCB_FREE(T) \
|
||||
do { \
|
||||
int priority = uxTaskPriorityGet(NULL); \
|
||||
vTaskPrioritySet(NULL, tskIDLE_PRIORITY); \
|
||||
vTaskDelay(1); \
|
||||
#define SAFE_PTR_FREE(P) \
|
||||
do { \
|
||||
TimerHandle_t timer = xTimerCreate("cleanup", pdMS_TO_TICKS(5000), pdFALSE, P, _delayed_free); \
|
||||
xTimerStart(timer, portMAX_DELAY); \
|
||||
} while (0)
|
||||
static void inline _delayed_free(TimerHandle_t xTimer) {
|
||||
free(pvTimerGetTimerID(xTimer));
|
||||
xTimerDelete(xTimer, portMAX_DELAY);
|
||||
}
|
||||
#endif
|
||||
|
||||
char* strextract(char *s1, char *beg, char *end);
|
||||
|
||||
Reference in New Issue
Block a user