mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-07 20:17:04 +03:00
AirPlay: no realloc, safe TCB cleanup, tools convergence
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
#include "gds_private.h"
|
||||
#include "gds_image.h"
|
||||
|
||||
const char TAG[] = "ImageDec";
|
||||
const static char TAG[] = "ImageDec";
|
||||
|
||||
#define SCRATCH_SIZE 3100
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ static void displayer_task(void *args) {
|
||||
|
||||
// handler elapsed track time
|
||||
if (displayer.timer && displayer.state == DISPLAYER_ACTIVE) {
|
||||
char counter[16];
|
||||
char line[20], duration[12] = "";
|
||||
TickType_t tick = xTaskGetTickCount();
|
||||
uint32_t elapsed = (tick - displayer.tick) * portTICK_PERIOD_MS;
|
||||
|
||||
@@ -202,9 +202,14 @@ static void displayer_task(void *args) {
|
||||
displayer.tick = tick;
|
||||
displayer.elapsed += elapsed / 1000;
|
||||
xSemaphoreGive(displayer.mutex);
|
||||
if (displayer.elapsed < 3600) snprintf(counter, 16, "%5u:%02u", displayer.elapsed / 60, displayer.elapsed % 60);
|
||||
else snprintf(counter, 16, "%2u:%02u:%02u", displayer.elapsed / 3600, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60);
|
||||
GDS_TextLine(display, 1, GDS_TEXT_RIGHT, (GDS_TEXT_CLEAR | GDS_TEXT_CLEAR_EOL) | GDS_TEXT_UPDATE, counter);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
timer_sleep = 1000;
|
||||
} else timer_sleep = max(1000 - elapsed, 0);
|
||||
} else timer_sleep = DEFAULT_SLEEP;
|
||||
|
||||
@@ -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);
|
||||
@@ -525,15 +525,17 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
ctx->active_remote.destroy_mutex = xSemaphoreCreateBinary();
|
||||
ctx->active_remote.xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ctx->active_remote.thread = xTaskCreateStatic( (TaskFunction_t) search_remote, "search_remote", SEARCH_STACK_SIZE, ctx, ESP_TASK_PRIO_MIN + 2, ctx->active_remote.xStack, ctx->active_remote.xTaskBuffer);
|
||||
#endif
|
||||
|
||||
} else if (!strcmp(method, "SETUP") && ((buf = kd_lookup(headers, "Transport")) != NULL)) {
|
||||
|
||||
} else if (!strcmp(method, "SETUP") && ((buf = kd_lookup(headers, "Transport")) != NULL)) {
|
||||
char *p;
|
||||
rtp_resp_t rtp = { 0 };
|
||||
short unsigned tport = 0, cport = 0;
|
||||
uint8_t *buffer = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
// we are about to stream, do something if needed and optionally give buffers to play with
|
||||
success = ctx->cmd_cb(RAOP_SETUP);
|
||||
success = ctx->cmd_cb(RAOP_SETUP, &buffer, &size);
|
||||
|
||||
if ((p = strcasestr(buf, "timing_port")) != NULL) sscanf(p, "%*[^=]=%hu", &tport);
|
||||
if ((p = strcasestr(buf, "control_port")) != NULL) sscanf(p, "%*[^=]=%hu", &cport);
|
||||
@@ -672,9 +674,8 @@ 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);
|
||||
#else
|
||||
#else
|
||||
// need to make sure no search is on-going and reclaim task memory
|
||||
// need to make sure no search is on-going and reclaim task memory
|
||||
ctx->active_remote.running = false;
|
||||
xSemaphoreTake(ctx->active_remote.destroy_mutex, portMAX_DELAY);
|
||||
|
||||
@@ -93,6 +93,7 @@ typedef struct audio_buffer_entry { // decoded audio packets
|
||||
u32_t rtptime, last_resend;
|
||||
s16_t *data;
|
||||
int len;
|
||||
bool allocated;
|
||||
} abuf_t;
|
||||
|
||||
typedef struct rtp_s {
|
||||
@@ -152,7 +153,7 @@ typedef struct rtp_s {
|
||||
|
||||
|
||||
#define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES)
|
||||
|
||||
static void buffer_alloc(abuf_t *audio_buffer, int size, uint8_t *buf, size_t buf_size);
|
||||
static void buffer_release(abuf_t *audio_buffer);
|
||||
static void buffer_reset(abuf_t *audio_buffer);
|
||||
static void buffer_push_packet(rtp_t *ctx);
|
||||
@@ -208,6 +209,7 @@ static struct alac_codec_s* alac_init(int fmtp[32]) {
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rtp_resp_t rtp_init(struct in_addr host, int latency, char *aeskey, char *aesiv, char *fmtpstr,
|
||||
short unsigned pCtrlPort, short unsigned pTimingPort,
|
||||
uint8_t *buffer, size_t size,
|
||||
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -260,7 +262,7 @@ rtp_resp_t rtp_init(struct in_addr host, int latency, char *aeskey, char *aesiv,
|
||||
ctx->alac_codec = alac_init(fmtp);
|
||||
rc &= ctx->alac_codec != NULL;
|
||||
|
||||
rc &= ctx->alac_codec != NULL;
|
||||
buffer_alloc(ctx->audio_buffer, ctx->frame_size*4, buffer, size);
|
||||
|
||||
// create rtp ports
|
||||
for (i = 0; i < 3; i++) {
|
||||
@@ -311,7 +313,7 @@ void rtp_end(rtp_t *ctx)
|
||||
#else
|
||||
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
|
||||
vTaskDelete(ctx->thread);
|
||||
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
|
||||
SAFE_TCB_FREE(ctx->xTaskBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -369,10 +371,18 @@ void rtp_record(rtp_t *ctx, unsigned short seqno, unsigned rtptime) {
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static void buffer_alloc(abuf_t *audio_buffer, int size, uint8_t *buf, size_t buf_size) {
|
||||
int i;
|
||||
for (i = 0; i < BUFFER_FRAMES; i++) {
|
||||
if (buf && buf_size >= size) {
|
||||
audio_buffer[i].data = (s16_t*) buf;
|
||||
audio_buffer[i].allocated = false;
|
||||
buf += size;
|
||||
buf_size -= size;
|
||||
} else {
|
||||
audio_buffer[i].allocated = true;
|
||||
audio_buffer[i].data = malloc(size);
|
||||
}
|
||||
audio_buffer[i].ready = 0;
|
||||
}
|
||||
}
|
||||
@@ -381,7 +391,7 @@ static void buffer_alloc(abuf_t *audio_buffer, int size) {
|
||||
static void buffer_release(abuf_t *audio_buffer) {
|
||||
int i;
|
||||
for (i = 0; i < BUFFER_FRAMES; i++) {
|
||||
int i;
|
||||
if (audio_buffer[i].allocated) free(audio_buffer[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef struct {
|
||||
rtp_resp_t rtp_init(struct in_addr host, int latency,
|
||||
char *aeskey, char *aesiv, char *fmtpstr,
|
||||
short unsigned pCtrlPort, short unsigned pTimingPort,
|
||||
uint8_t *buffer, size_t size,
|
||||
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
|
||||
void rtp_end(struct rtp_s *ctx);
|
||||
bool rtp_flush(struct rtp_s *ctx, unsigned short seqno, unsigned rtptime, bool exit_locked);
|
||||
|
||||
@@ -48,6 +48,16 @@ void winsock_init(void);
|
||||
void winsock_init(void);
|
||||
void winsock_close(void);
|
||||
|
||||
#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); \
|
||||
vTaskPrioritySet(NULL, priority); \
|
||||
heap_caps_free(T); \
|
||||
} while (0)
|
||||
#endif
|
||||
@@ -67,5 +77,6 @@ char* kd_dump(key_data_t *kd);
|
||||
char* http_send(int sock, char *method, key_data_t *rkd);
|
||||
|
||||
char* kd_lookup(key_data_t *kd, char *key);
|
||||
bool kd_add(key_data_t *kd, char *key, char *value);
|
||||
char* kd_dump(key_data_t *kd);
|
||||
void kd_free(key_data_t *kd);
|
||||
|
||||
@@ -73,13 +73,11 @@ void _buf_flush(struct buffer *buf) {
|
||||
|
||||
// adjust buffer to multiple of mod bytes so reading in multiple always wraps on frame boundary
|
||||
void buf_adjust(struct buffer *buf, size_t mod) {
|
||||
size_t size;
|
||||
mutex_lock(buf->mutex);
|
||||
size = ((unsigned)(buf->base_size / mod)) * mod;
|
||||
buf->readp = buf->buf;
|
||||
buf->writep = buf->buf;
|
||||
buf->wrap = buf->buf + size;
|
||||
buf->size = size;
|
||||
buf->base_size = ((size_t)(buf->size / mod)) * mod;
|
||||
buf->readp = buf->writep = buf->buf;
|
||||
buf->wrap = buf->buf + buf->base_size;
|
||||
buf->size = buf->base_size;
|
||||
mutex_unlock(buf->mutex);
|
||||
}
|
||||
|
||||
@@ -91,15 +89,22 @@ void _buf_resize(struct buffer *buf, size_t size) {
|
||||
if (!buf->buf) {
|
||||
size = buf->size;
|
||||
buf->buf = malloc(size);
|
||||
if (!buf->buf) {
|
||||
size = 0;
|
||||
if (!buf->buf) size = 0;
|
||||
}
|
||||
}
|
||||
buf->readp = buf->buf;
|
||||
buf->writep = buf->buf;
|
||||
buf->writep = buf->readp = buf->buf;
|
||||
buf->wrap = buf->buf + size;
|
||||
buf->size = size;
|
||||
buf->base_size = size;
|
||||
buf->true_size = buf->base_size = buf->size = size;
|
||||
}
|
||||
|
||||
size_t _buf_limit(struct buffer *buf, size_t limit) {
|
||||
if (limit) {
|
||||
buf->size = limit;
|
||||
buf->readp = buf->writep = buf->buf;
|
||||
} else {
|
||||
buf->size = buf->base_size;
|
||||
}
|
||||
buf->wrap = buf->buf + buf->size;
|
||||
return buf->base_size - buf->size;
|
||||
}
|
||||
|
||||
void _buf_unwrap(struct buffer *buf, size_t cont) {
|
||||
@@ -130,7 +135,9 @@ void _buf_unwrap(struct buffer *buf, size_t cont) {
|
||||
if (len > by) {
|
||||
memmove(buf->buf, buf->buf + by, len - by);
|
||||
buf->writep -= by;
|
||||
} else buf->writep += buf->size - by;
|
||||
} else {
|
||||
buf->writep += buf->size - by;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,8 +164,7 @@ void buf_init(struct buffer *buf, size_t size) {
|
||||
buf->readp = buf->buf;
|
||||
buf->writep = buf->buf;
|
||||
buf->wrap = buf->buf + size;
|
||||
buf->size = size;
|
||||
buf->base_size = size;
|
||||
buf->true_size = buf->base_size = buf->size = size;
|
||||
mutex_create_p(buf->mutex);
|
||||
}
|
||||
|
||||
@@ -166,8 +172,7 @@ void buf_destroy(struct buffer *buf) {
|
||||
if (buf->buf) {
|
||||
free(buf->buf);
|
||||
buf->buf = NULL;
|
||||
buf->size = 0;
|
||||
buf->base_size = 0;
|
||||
buf->size = buf->base_size = buf->true_size = 0;
|
||||
mutex_destroy(buf->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ static bool bt_sink_cmd_handler(bt_sink_cmd_t cmd, va_list args)
|
||||
switch(cmd) {
|
||||
case BT_SINK_AUDIO_STARTED:
|
||||
_buf_flush(outputbuf);
|
||||
_buf_limit(outputbuf, 0);
|
||||
output.next_sample_rate = output.current_sample_rate = va_arg(args, u32_t);
|
||||
output.external = DECODE_BT;
|
||||
output.state = OUTPUT_STOPPED;
|
||||
@@ -251,15 +252,21 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
|
||||
|
||||
break;
|
||||
}
|
||||
case RAOP_SETUP:
|
||||
// we need a fair bit of space for RTP process
|
||||
_buf_resize(outputbuf, RAOP_OUTPUT_SIZE);
|
||||
case RAOP_SETUP: {
|
||||
uint8_t **buffer = va_arg(args, uint8_t**);
|
||||
size_t *size = va_arg(args, size_t*);
|
||||
|
||||
// steal buffer tail from outputbuf but do not reallocate
|
||||
*size = _buf_limit(outputbuf, RAOP_OUTPUT_SIZE);
|
||||
*buffer = outputbuf->writep + RAOP_OUTPUT_SIZE;
|
||||
|
||||
output.frames_played = 0;
|
||||
output.external = DECODE_RAOP;
|
||||
output.state = OUTPUT_STOPPED;
|
||||
if (decode.state != DECODE_STOPPED) decode.state = DECODE_ERROR;
|
||||
LOG_INFO("resizing buffer %u", outputbuf->size);
|
||||
break;
|
||||
}
|
||||
case RAOP_STREAM:
|
||||
LOG_INFO("Stream", NULL);
|
||||
raop_state = event;
|
||||
@@ -271,10 +278,9 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
|
||||
break;
|
||||
case RAOP_STOP:
|
||||
case RAOP_FLUSH:
|
||||
if (event == RAOP_FLUSH) { LOG_INFO("Flush", NULL); }
|
||||
else { LOG_INFO("Stop", NULL); }
|
||||
raop_state = event;
|
||||
LOG_INFO("%s", event == RAOP_FLUSH ? "Flush" : "Stop");
|
||||
_buf_flush(outputbuf);
|
||||
raop_state = event;
|
||||
if (output.state > OUTPUT_STOPPED) output.state = OUTPUT_STOPPED;
|
||||
abort_sink = true;
|
||||
output.frames_played = 0;
|
||||
|
||||
@@ -354,7 +354,6 @@ void output_init_common(log_level level, const char *device, unsigned output_buf
|
||||
loglevel = level;
|
||||
|
||||
output_buf_size = output_buf_size - (output_buf_size % BYTES_PER_FRAME);
|
||||
output.init_size = output_buf_size;
|
||||
LOG_DEBUG("outputbuf size: %u", output_buf_size);
|
||||
|
||||
buf_init(outputbuf, output_buf_size);
|
||||
|
||||
@@ -391,7 +391,7 @@ static void process_strm(u8_t *pkt, int len) {
|
||||
#if EMBEDDED
|
||||
if (output.external) decode_restore(output.external);
|
||||
output.external = 0;
|
||||
_buf_resize(outputbuf, output.init_size);
|
||||
_buf_limit(outputbuf, 0);
|
||||
#endif
|
||||
output.threshold = strm->output_threshold;
|
||||
output.next_replay_gain = unpackN(&strm->replay_gain);
|
||||
|
||||
@@ -532,6 +532,7 @@ struct buffer {
|
||||
u8_t *wrap;
|
||||
size_t size;
|
||||
size_t base_size;
|
||||
size_t true_size;
|
||||
mutex_type mutex;
|
||||
};
|
||||
|
||||
@@ -547,6 +548,7 @@ void _buf_flush(struct buffer *buf);
|
||||
void _buf_unwrap(struct buffer *buf, size_t cont);
|
||||
void buf_adjust(struct buffer *buf, size_t mod);
|
||||
void _buf_resize(struct buffer *buf, size_t size);
|
||||
size_t _buf_limit(struct buffer *buf, size_t limit);
|
||||
void buf_init(struct buffer *buf, size_t size);
|
||||
void buf_destroy(struct buffer *buf);
|
||||
|
||||
@@ -665,7 +667,6 @@ struct outputstate {
|
||||
u8_t channels;
|
||||
const char *device;
|
||||
int external;
|
||||
u32_t init_size;
|
||||
#if ALSA
|
||||
unsigned buffer;
|
||||
unsigned period;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS operator.cpp utf8.c
|
||||
idf_component_register(SRCS operator.cpp tools.c
|
||||
REQUIRES esp_common pthread
|
||||
INCLUDE_DIRS .
|
||||
)
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
/*
|
||||
* (c) Philippe G. 20201, philippe_44@outlook.com
|
||||
* see other copyrights below
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "tools.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
const static char TAG[] = "tools";
|
||||
|
||||
/****************************************************************************************
|
||||
* UTF-8 tools
|
||||
*/
|
||||
|
||||
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
// Copyright (c) 2017 ZephRay <zephray@outlook.com>
|
||||
//
|
||||
// utf8to1252 - almost equivalent to iconv -f utf-8 -t windows-1252, but better
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TAG "aa"
|
||||
|
||||
#define UTF8_ACCEPT 0
|
||||
#define UTF8_REJECT 1
|
||||
|
||||
@@ -91,3 +105,26 @@ void utf8_decode(char *src) {
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* URL tools
|
||||
*/
|
||||
|
||||
static inline char from_hex(char ch) {
|
||||
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
||||
}
|
||||
|
||||
void url_decode(char *url) {
|
||||
char *p, *src = strdup(url);
|
||||
for (p = src; *src; url++) {
|
||||
*url = *src++;
|
||||
if (*url == '%') {
|
||||
*url = from_hex(*src++) << 4;
|
||||
*url |= from_hex(*src++);
|
||||
} else if (*url == '+') {
|
||||
*url = ' ';
|
||||
}
|
||||
}
|
||||
*url = '\0';
|
||||
free(p);
|
||||
}
|
||||
@@ -10,4 +10,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void utf8_decode(char *src);
|
||||
void url_decode(char *url);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user