AirPlay: no realloc, safe TCB cleanup, tools convergence

This commit is contained in:
Philippe G
2021-12-17 10:54:25 -08:00
parent a266c07114
commit 3b6299dc1a
14 changed files with 144 additions and 59 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 .
)

View File

@@ -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);
}

View File

@@ -10,4 +10,13 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void utf8_decode(char *src);
void url_decode(char *url);
#ifdef __cplusplus
}
#endif