浏览代码

AirPlay: no realloc, safe TCB cleanup, tools convergence

Philippe G 3 年之前
父节点
当前提交
3b6299dc1a

+ 1 - 1
components/display/core/gds_image.c

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

+ 9 - 4
components/display/display.c

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

+ 7 - 6
components/raop/raop.c

@@ -255,7 +255,7 @@ void raop_delete(struct raop_ctx_s *ctx) {
 	vTaskDelay(100 / portTICK_PERIOD_MS);
 	ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
 	vTaskDelete(ctx->thread);
-	heap_caps_free(ctx->xTaskBuffer);
+	SAFE_TCB_FREE(ctx->xTaskBuffer);
 
 	// cleanup all session-created items
 	cleanup_rtsp(ctx, true);
@@ -525,15 +525,17 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
 		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
-		success = ctx->cmd_cb(RAOP_SETUP);
+		// we are about to stream, do something if needed and optionally give buffers to play with
+		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);
 
 		rtp = rtp_init(ctx->peer, ctx->latency,	ctx->rtsp.aeskey, ctx->rtsp.aesiv,
-					   ctx->rtsp.fmtp, cport, tport, ctx->cmd_cb, ctx->data_cb);
+					   ctx->rtsp.fmtp, cport, tport, buffer, size, ctx->cmd_cb, ctx->data_cb);
 						
 		ctx->rtp = rtp.ctx;
 		
@@ -672,9 +674,8 @@ void cleanup_rtsp(raop_ctx_t *ctx, bool abort) {
 		ctx->active_remote.running = false;
 		xSemaphoreTake(ctx->active_remote.destroy_mutex, portMAX_DELAY);
 		vTaskDelete(ctx->active_remote.thread);
+		SAFE_TCB_FREE(ctx->active_remote.xTaskBuffer);
 		vSemaphoreDelete(ctx->active_remote.thread);
-
-		heap_caps_free(ctx->active_remote.xTaskBuffer);
 #endif
 		memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
 		LOG_INFO("[%p]: Remote search thread aborted", ctx);

+ 18 - 8
components/raop/rtp.c

@@ -65,8 +65,8 @@
 #define MS2TS(ms, rate) ((((u64_t) (ms)) * (rate)) / 1000)
 #define TS2MS(ts, rate) NTP2MS(TS2NTP(ts,rate))
 
-
extern log_level 	raop_loglevel;
-
static log_level 	*loglevel = &raop_loglevel;
+extern log_level 	raop_loglevel;
+static log_level 	*loglevel = &raop_loglevel;
 
 //#define __RTP_STORE
 
@@ -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);
+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;
 
-	buffer_alloc(ctx->audio_buffer, ctx->frame_size*4);
+	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);
-		heap_caps_free(ctx->xTaskBuffer);
+		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) {
+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++) {
-		audio_buffer[i].data = malloc(size);
+		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++) {
-		free(audio_buffer[i].data);
+		if (audio_buffer[i].allocated) free(audio_buffer[i].data);
 	}
 }
 

+ 1 - 0
components/raop/rtp.h

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

+ 12 - 1
components/raop/util.h

@@ -48,6 +48,16 @@ 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
 char* 		strextract(char *s1, char *beg, char *end);
 in_addr_t 	get_localhost(char **name);
@@ -67,5 +77,6 @@ char* 		kd_dump(key_data_t *kd);
 void 		kd_free(key_data_t *kd);
 
 int 		_fprintf(FILE *file, ...);
-
#endif
+
+#endif
 

+ 24 - 19
components/squeezelite/buffer.c

@@ -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);
 }
 
@@ -90,16 +88,23 @@ void _buf_resize(struct buffer *buf, size_t size) {
 	buf->buf = malloc(size);
 	if (!buf->buf) {
 		size    = buf->size;
-		buf->buf= malloc(size);
-		if (!buf->buf) {
-			size = 0;
-		}
+		buf->buf = malloc(size);
+		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);
 	}
 }

+ 12 - 6
components/squeezelite/decode_external.c

@@ -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); }
+			LOG_INFO("%s", event == RAOP_FLUSH ? "Flush" : "Stop");
+			_buf_flush(outputbuf);
 			raop_state = event;
-			_buf_flush(outputbuf);		
 			if (output.state > OUTPUT_STOPPED) output.state = OUTPUT_STOPPED;
 			abort_sink = true;
 			output.frames_played = 0;

+ 0 - 1
components/squeezelite/output.c

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

+ 1 - 1
components/squeezelite/slimproto.c

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

+ 2 - 1
components/squeezelite/squeezelite.h

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

+ 2 - 2
components/tools/CMakeLists.txt

@@ -1,5 +1,5 @@
-idf_component_register(SRCS operator.cpp utf8.c  
-						REQUIRES esp_common  pthread 
+idf_component_register(SRCS operator.cpp tools.c
+						REQUIRES esp_common pthread 
                     	INCLUDE_DIRS .
                     	)
 

+ 45 - 8
components/tools/utf8.c → components/tools/tools.c

@@ -1,16 +1,30 @@
-// 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
-
+/* 
+ *  (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"
 
-#define TAG "aa"
+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
 
 #define UTF8_ACCEPT 0
 #define UTF8_REJECT 1
@@ -90,4 +104,27 @@ 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);
+}

+ 9 - 0
components/tools/tools.h

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