Merge branch 'master' into httpd

Conflicts:
	components/wifi-manager/http_server.c
	components/wifi-manager/wifi_manager.c
	main/config.c
	main/config.h
This commit is contained in:
Sebastien
2020-01-22 15:13:18 -05:00
122 changed files with 9091 additions and 588 deletions

View File

@@ -43,7 +43,8 @@
#include "dmap_parser.h"
#include "log_util.h"
#define RTSP_STACK_SIZE (8*1024)
#define RTSP_STACK_SIZE (8*1024)
#define SEARCH_STACK_SIZE (2*1048)
typedef struct raop_ctx_s {
#ifdef WIN32
@@ -60,7 +61,7 @@ typedef struct raop_ctx_s {
#else
TaskHandle_t thread, search_thread, joiner;
StaticTask_t *xTaskBuffer;
StackType_t *xStack;
StackType_t xStack[RTSP_STACK_SIZE] __attribute__ ((aligned (4)));
#endif
unsigned char mac[6];
int latency;
@@ -71,14 +72,19 @@ typedef struct raop_ctx_s {
struct rtp_s *rtp;
raop_cmd_cb_t cmd_cb;
raop_data_cb_t data_cb;
/*
struct {
char DACPid[32], id[32];
struct in_addr host;
u16_t port;
#ifdef WIN32
struct mDNShandle_s *handle;
#else
bool running;
TaskHandle_t thread, joiner;
StaticTask_t *xTaskBuffer;
StackType_t xStack[SEARCH_STACK_SIZE] __attribute__ ((aligned (4)));;
#endif
} active_remote;
*/
void *owner;
} raop_ctx_t;
@@ -98,7 +104,7 @@ static void* search_remote(void *args);
extern char private_key[];
enum { RSA_MODE_KEY, RSA_MODE_AUTH };
static void on_dmap_string(void *ctx, const char *code, const char *name, const char *buf, size_t len);
/*----------------------------------------------------------------------------*/
@@ -186,26 +192,23 @@ struct raop_ctx_s *raop_create(struct in_addr host, char *name,
id[63] = '\0';
ctx->svc = mdnsd_register_svc(ctx->svr, id, "_raop._tcp.local", ctx->port, NULL, (const char**) txt);
pthread_create(&ctx->thread, NULL, &rtsp_thread, ctx);
pthread_create(&ctx->thread, NULL, &rtsp_thread, ctx);
#else
LOG_INFO("starting mDNS with %s", id);
ESP_ERROR_CHECK( mdns_service_add(id, "_raop", "_tcp", ctx->port, txt, sizeof(txt) / sizeof(mdns_txt_item_t)) );
ctx->xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ctx->xStack = (StackType_t*) malloc(RTSP_STACK_SIZE);
ctx->thread = xTaskCreateStatic( (TaskFunction_t) rtsp_thread, "RTSP_thread", RTSP_STACK_SIZE, ctx, ESP_TASK_PRIO_MIN + 1, ctx->xStack, ctx->xTaskBuffer);
#endif
return ctx;
}
/*----------------------------------------------------------------------------*/
void raop_delete(struct raop_ctx_s *ctx) {
int sock;
/*----------------------------------------------------------------------------*/
void raop_delete(struct raop_ctx_s *ctx) {
#ifdef WIN32
int sock;
struct sockaddr addr;
socklen_t nlen = sizeof(struct sockaddr);
#endif
@@ -214,66 +217,99 @@ void raop_delete(struct raop_ctx_s *ctx) {
#ifdef WIN32
ctx->running = false;
// wake-up thread by connecting socket, needed for freeBSD
sock = socket(AF_INET, SOCK_STREAM, 0);
getsockname(ctx->sock, (struct sockaddr *) &addr, &nlen);
connect(sock, (struct sockaddr*) &addr, sizeof(addr));
closesocket(sock);
#ifdef WIN32
sock = socket(AF_INET, SOCK_STREAM, 0);
getsockname(ctx->sock, (struct sockaddr *) &addr, &nlen);
connect(sock, (struct sockaddr*) &addr, sizeof(addr));
vTaskDelete(ctx->thread);
closesocket(sock);
heap_caps_free(ctx->xTaskBuffer);
#endif
pthread_join(ctx->thread, NULL);
#ifdef WIN32
rtp_end(ctx->rtp);
shutdown(ctx->sock, SD_BOTH);
closesocket(ctx->sock);
// terminate search, but do not reclaim memory of pthread if never launched
if (ctx->active_remote.handle) {
close_mDNS(ctx->active_remote.handle);
pthread_join(ctx->search_thread, NULL);
}
// stop broadcasting devices
mdns_service_remove(ctx->svr, ctx->svc);
mdnsd_stop(ctx->svr);
#else
// first stop the search task if any
if (ctx->active_remote.running) {
ctx->active_remote.joiner = xTaskGetCurrentTaskHandle();
ctx->active_remote.running = false;
vTaskResume(ctx->active_remote.thread);
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
vTaskDelete(ctx->active_remote.thread);
heap_caps_free(ctx->active_remote.xTaskBuffer);
}
// then the RTSP task
ctx->joiner = xTaskGetCurrentTaskHandle();
ctx->running = false;
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
vTaskDelete(ctx->thread);
heap_caps_free(ctx->xTaskBuffer);
rtp_end(ctx->rtp);
shutdown(ctx->sock, SHUT_RDWR);
closesocket(ctx->sock);
pthread_join(ctx->search_thread, NULL);
}
*/
NFREE(ctx->rtsp.aeskey);
NFREE(ctx->rtsp.aesiv);
NFREE(ctx->rtsp.fmtp);
mdns_service_remove("_raop", "_tcp");
#endif
NFREE(ctx->rtsp.aeskey);
#else
NFREE(ctx->rtsp.aesiv);
#endif
NFREE(ctx->rtsp.fmtp);
free(ctx);
}
/*----------------------------------------------------------------------------*/
void raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
struct sockaddr_in addr;
int sock;
char *command = NULL;
// first notify the remote controller (if any)
switch(event) {
case RAOP_REW:
command = strdup("beginrew");
break;
case RAOP_FWD:
command = strdup("beginff");
break;
case RAOP_PREV:
command = strdup("previtem");
break;
case RAOP_NEXT:
command = strdup("nextitem");
break;
case RAOP_TOGGLE:
command = strdup("playpause");
break;
case RAOP_PAUSE:
command = strdup("pause");
break;
case RAOP_PLAY:
command = strdup("play");
break;
case RAOP_RESUME:
command = strdup("playresume");
break;
case RAOP_STOP:
command = strdup("stop");
break;
case RAOP_VOLUME_UP:
command = strdup("volumeup");
break;
@@ -286,9 +322,9 @@ void raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
asprintf(&command,"setproperty?dmcp.device-volume=%0.4lf", Volume);
break;
}
}
default:
break;
default:
break;
}
// no command to send to remote or no remote found yet
if (!command || !ctx->active_remote.port) {
@@ -317,11 +353,7 @@ void raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
if (len > 0) resp[len-1] = '\0';
LOG_INFO("[%p]: sending airplay remote\n%s<== received ==>\n%s", ctx, buf, resp);
len = recv(sock, resp, 512, 0);
NFREE(method);
LOG_INFO("[%p]: sending airplay remote\n%s<== received ==>\n%s", ctx, buf, resp);
NFREE(method);
NFREE(buf);
kd_free(headers);
}
@@ -366,7 +398,7 @@ static void *rtsp_thread(void *arg) {
closesocket(sock);
LOG_INFO("RTSP close %u", sock);
sock = -1;
if (n < 0 || !res) {
}
}
if (sock != -1) closesocket(sock);
@@ -429,12 +461,27 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
kd_add(resp, "Public", "ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
} else if (!strcmp(method, "ANNOUNCE")) {
char *padded, *p;
NFREE(ctx->rtsp.aeskey);
NFREE(ctx->rtsp.aesiv);
NFREE(ctx->rtsp.fmtp);
// LMS might has taken over the player, leaving us with a running RTP session (should not happen)
if (ctx->rtp) {
LOG_WARN("[%p]: closing unfinished RTP session", ctx);
rtp_end(ctx->rtp);
}
// same, should not happen unless we have missed a teardown ...
if (ctx->active_remote.running) {
ctx->active_remote.joiner = xTaskGetCurrentTaskHandle();
ctx->active_remote.running = false;
vTaskResume(ctx->active_remote.thread);
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
vTaskDelete(ctx->active_remote.thread);
heap_caps_free(ctx->active_remote.xTaskBuffer);
memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
@@ -467,13 +514,17 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
}
if ((p = strcasestr(body, "fmtp")) != NULL) {
NFREE(padded);
p = strextract(p, ":", "\r\n");
ctx->rtsp.fmtp = strdup(p);
NFREE(p);
}
// on announce, search remote
NFREE(p);
if ((buf = kd_lookup(headers, "DACP-ID")) != NULL) strcpy(ctx->active_remote.DACPid, buf);
if ((buf = kd_lookup(headers, "Active-Remote")) != NULL) strcpy(ctx->active_remote.id, buf);
#ifdef WIN32
ctx->active_remote.handle = init_mDNS(false, ctx->host);
pthread_create(&ctx->search_thread, NULL, &search_remote, ctx);
#else
ctx->active_remote.running = true;
@@ -481,7 +532,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
ctx->active_remote.thread = xTaskCreateStatic( (TaskFunction_t) search_remote, "search_remote", SEARCH_STACK_SIZE, ctx, ESP_TASK_PRIO_MIN + 1, ctx->active_remote.xStack, ctx->active_remote.xTaskBuffer);
#endif
ctx->active_remote.handle = init_mDNS(false, ctx->host);
} else if (!strcmp(method, "SETUP") && ((buf = kd_lookup(headers, "Transport")) != NULL)) {
char *p;
rtp_resp_t rtp = { 0 };
short unsigned tport = 0, cport = 0;
@@ -520,7 +571,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
kd_add(resp, "Audio-Latency", latency);
}
snprintf(latency, 6, "%u", ctx->latency);
buf = kd_lookup(headers, "RTP-Info");
if (buf && (p = strcasestr(buf, "seq")) != NULL) sscanf(p, "%*[^=]=%hu", &seqno);
if (buf && (p = strcasestr(buf, "rtptime")) != NULL) sscanf(p, "%*[^=]=%u", &rtptime);
@@ -533,7 +584,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
unsigned rtptime = 0;
char *p;
unsigned short seqno = 0;
buf = kd_lookup(headers, "RTP-Info");
if ((p = strcasestr(buf, "seq")) != NULL) sscanf(p, "%*[^=]=%hu", &seqno);
if ((p = strcasestr(buf, "rtptime")) != NULL) sscanf(p, "%*[^=]=%u", &rtptime);
@@ -541,20 +592,32 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
if (ctx->rtp && rtp_flush(ctx->rtp, seqno, rtptime))
success = ctx->cmd_cb(RAOP_FLUSH, NULL);
// only send FLUSH if useful (discards frames above buffer head and top)
} else if (!strcmp(method, "TEARDOWN")) {
rtp_end(ctx->rtp);
} else if (!strcmp(method, "TEARDOWN")) {
ctx->rtp = NULL;
// need to make sure no search is on-going and reclaim pthread memory
#ifdef WIN32
if (ctx->active_remote.handle) close_mDNS(ctx->active_remote.handle);
pthread_join(ctx->search_thread, NULL);
#else
ctx->active_remote.joiner = xTaskGetCurrentTaskHandle();
ctx->active_remote.running = false;
// task might not need to be resumed anyway
vTaskResume(ctx->active_remote.thread);
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
vTaskDelete(ctx->active_remote.thread);
heap_caps_free(ctx->active_remote.xTaskBuffer);
LOG_INFO("[%p]: mDNS search task terminated", ctx);
#endif
// need to make sure no search is on-going and reclaim pthread memory
memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
pthread_join(ctx->search_thread, NULL);
NFREE(ctx->rtsp.aeskey);
NFREE(ctx->rtsp.aesiv);
NFREE(ctx->rtsp.fmtp);
@@ -563,7 +626,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
} else if (!strcmp(method, "SET_PARAMETER")) {
char *p;
if (body && (p = strcasestr(body, "volume")) != NULL) {
float volume;
sscanf(p, "%*[^:]:%f", &volume);
@@ -585,7 +648,6 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
LOG_INFO("[%p]: received metadata\n\tartist: %s\n\talbum: %s\n\ttitle: %s",
ctx, metadata.artist, metadata.album, metadata.title);
free_metadata(&metadata);
if (!dmap_parse(&settings, body, len)) {
}
}
*/
@@ -605,7 +667,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
NFREE(body);
NFREE(buf);
kd_free(resp);
kd_free(headers);
return true;
}
@@ -625,11 +687,9 @@ bool search_remote_cb(mDNSservice_t *slist, void *cookie, bool *stop) {
inet_ntoa(ctx->active_remote.host), ctx->active_remote.port);
*stop = true;
break;
LOG_INFO("[%p]: found ActiveRemote for %s at %s:%u", ctx, ctx->active_remote.DACPid,
}
}
}
// let caller clear list
return false;
}
@@ -637,7 +697,57 @@ static void* search_remote(void *args) {
/*----------------------------------------------------------------------------*/
static void* search_remote(void *args) {
raop_ctx_t *ctx = (raop_ctx_t*) args;
query_mDNS(ctx->active_remote.handle, "_dacp._tcp.local", 0, 0, &search_remote_cb, (void*) ctx);
return NULL;
}
#else
/*----------------------------------------------------------------------------*/
static void* search_remote(void *args) {
raop_ctx_t *ctx = (raop_ctx_t*) args;
bool found = false;
LOG_INFO("starting remote search");
while (ctx->active_remote.running && !found) {
mdns_result_t *results = NULL;
mdns_result_t *r;
mdns_ip_addr_t *a;
if (mdns_query_ptr("_dacp", "_tcp", 3000, 32, &results)) {
LOG_ERROR("mDNS active remote query Failed");
continue;
}
for (r = results; r && !strcasestr(r->instance_name, ctx->active_remote.DACPid); r = r->next);
if (r) {
for (a = r->addr; a && a->addr.type != IPADDR_TYPE_V4; a = a->next);
if (a) {
found = true;
ctx->active_remote.host.s_addr = a->addr.u_addr.ip4.addr;
ctx->active_remote.port = r->port;
LOG_INFO("found remote %s %s:%hu", r->instance_name, inet_ntoa(ctx->active_remote.host), ctx->active_remote.port);
}
}
mdns_query_results_free(results);
}
/*
for some reason which is beyond me, if that tasks gives the semaphore
before the RTSP tasks waits for it, then freeRTOS crashes in queue
management caused by LWIP stack once the RTSP socket is closed. I have
no clue why, but so we'll suspend the tasks as soon as we're done with
search and wait for the resume then give the semaphore
*/
// PS: I know this is not fully race-condition free
if (ctx->active_remote.running) vTaskSuspend(NULL);
xTaskNotifyGive(ctx->active_remote.joiner);
// now our context will be deleted
vTaskSuspend(NULL);

View File

@@ -24,7 +24,7 @@
#include "platform.h"
#include "raop_sink.h"
struct raop_ctx_s* raop_create(struct in_addr host, char *name, unsigned char mac[6], int latency,
struct raop_ctx_s* raop_create(struct in_addr host, char *name, unsigned char mac[6], int latency,
raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
void raop_delete(struct raop_ctx_s *ctx);
void raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param);

View File

@@ -11,8 +11,9 @@
#include "esp_pthread.h"
#include "esp_system.h"
#include "freertos/timers.h"
#include "nvs_utilities.h"
#include "config.h"
#include "raop.h"
#include "audio_controls.h"
#include "log_util.h"
@@ -22,14 +23,68 @@
#define CONFIG_AIRPLAY_NAME "ESP32-AirPlay"
#endif
static const char * TAG = "platform";
log_level raop_loglevel = lINFO;
log_level util_loglevel;
static log_level *loglevel = &raop_loglevel;
static struct raop_ctx_s *raop;
static void raop_volume_up(void) {
raop_cmd(raop, RAOP_VOLUME_UP, NULL);
LOG_INFO("AirPlay volume up");
}
static void raop_volume_down(void) {
raop_cmd(raop, RAOP_VOLUME_DOWN, NULL);
LOG_INFO("AirPlay volume down");
}
static void raop_toggle(void) {
raop_cmd(raop, RAOP_TOGGLE, NULL);
LOG_INFO("AirPlay play/pause");
}
static void raop_pause(void) {
raop_cmd(raop, RAOP_PAUSE, NULL);
LOG_INFO("AirPlay pause");
}
static void raop_play(void) {
raop_cmd(raop, RAOP_PLAY, NULL);
LOG_INFO("AirPlay play");
}
static void raop_stop(void) {
raop_cmd(raop, RAOP_STOP, NULL);
LOG_INFO("AirPlay stop");
}
static void raop_prev(void) {
raop_cmd(raop, RAOP_PREV, NULL);
LOG_INFO("AirPlay previous");
}
static void raop_next(void) {
raop_cmd(raop, RAOP_NEXT, NULL);
LOG_INFO("AirPlay next");
}
const static actrls_t controls = {
raop_volume_up, raop_volume_down, // volume up, volume down
raop_toggle, raop_play, // toggle, play
raop_pause, raop_stop, // pause, stop
NULL, NULL, // rew, fwd
raop_prev, raop_next, // prev, next
};
/****************************************************************************************
* Airplay taking/giving audio system's control
*/
void raop_master(bool on) {
if (on) actrls_set(controls, NULL);
else actrls_unset();
}
/****************************************************************************************
* Airplay sink de-initialization
*/
@@ -56,14 +111,14 @@ void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
ESP_ERROR_CHECK( mdns_init() );
ESP_ERROR_CHECK( mdns_hostname_set(hostname) );
char * sink_name_buffer= (char *)config_alloc_get(NVS_TYPE_STR, "airplay_name");
char * sink_name_buffer= (char *)config_alloc_get(NVS_TYPE_STR,"airplay_name");
if(sink_name_buffer != NULL){
memset(sink_name, 0x00, sizeof(sink_name));
strncpy(sink_name,sink_name_buffer,sizeof(sink_name)-1 );
free(sink_name_buffer);
}
ESP_LOGI(TAG, "mdns hostname set to: [%s] with servicename %s", hostname, sink_name);
LOG_INFO( "mdns hostname set to: [%s] with servicename %s", hostname, sink_name);
// create RAOP instance, latency is set by controller
uint8_t mac[6];
@@ -72,8 +127,10 @@ void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb) {
}
/****************************************************************************************
* Airplay local command (stop, start, volume ...)
* Airplay forced disconnection
*/
void raop_sink_cmd(raop_event_t event, void *param) {
raop_cmd(raop, event, param);
void raop_disconnect(void) {
LOG_INFO("forced disconnection");
raop_cmd(raop, RAOP_STOP, NULL);
actrls_unset();
}

View File

@@ -13,27 +13,31 @@
#define RAOP_SAMPLE_RATE 44100
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_PAUSE, RAOP_STOP, RAOP_VOLUME, RAOP_TIMING } raop_event_t ;
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_PAUSE, RAOP_STOP,
RAOP_VOLUME, RAOP_TIMING, RAOP_PREV, RAOP_NEXT, RAOP_REW, RAOP_FWD,
RAOP_VOLUME_UP, RAOP_VOLUME_DOWN, RAOP_RESUME, RAOP_TOGGLE } raop_event_t ;
typedef void (*raop_cmd_cb_t)(raop_event_t event, void *param);
typedef bool (*raop_cmd_cb_t)(raop_event_t event, void *param);
typedef void (*raop_data_cb_t)(const u8_t *data, size_t len, u32_t playtime);
/**
* @brief init sink mode (need to be provided)
*/
void raop_sink_init(raop_cmd_cb_t cmd_cb, raop_data_cb_t data_cb);
/**
* @brief deinit sink mode (need to be provided)
*/
void raop_sink_deinit(void);
/**
* @brief init sink mode (need to be provided)
* @brief do what's necessary when becoming in charge
*/
void raop_master(bool on);
void raop_sink_cmd(raop_event_t event, void *param);
/**
* @brief force disconnection
*/
void raop_disconnect(void);
#endif /* RAOP_SINK_H*/

View File

@@ -139,7 +139,7 @@ typedef struct rtp_s {
#ifdef WIN32
pthread_t thread;
#else
TaskHandle_t thread, joiner;
TaskHandle_t thread, joiner;
StaticTask_t *xTaskBuffer;
StackType_t xStack[RTP_STACK_SIZE] __attribute__ ((aligned (4)));
#endif
@@ -275,11 +275,11 @@ rtp_resp_t rtp_init(struct in_addr host, int latency, char *aeskey, char *aesiv,
#ifdef WIN32
pthread_create(&ctx->thread, NULL, rtp_thread_func, (void *) ctx);
#else
// xTaskCreate((TaskFunction_t) rtp_thread_func, "RTP_thread", RTP_TASK_SIZE, ctx, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1 , &ctx->thread);
// xTaskCreate((TaskFunction_t) rtp_thread_func, "RTP_thread", RTP_TASK_SIZE, ctx, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1 , &ctx->thread);
ctx->xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ctx->thread = xTaskCreateStatic( (TaskFunction_t) rtp_thread_func, "RTP_thread", RTP_STACK_SIZE, ctx,
CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, ctx->xStack, ctx->xTaskBuffer );
#endif
} else {
LOG_ERROR("[%p]: cannot start RTP", ctx);
rtp_end(ctx);
@@ -304,9 +304,8 @@ void rtp_end(rtp_t *ctx)
#endif
ctx->running = false;
#ifdef WIN32
pthread_join(ctx->thread, NULL);
pthread_join(ctx->thread, NULL);
#else
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
vTaskDelete(ctx->thread);
heap_caps_free(ctx->xTaskBuffer);
@@ -715,7 +714,7 @@ static void *rtp_thread_func(void *arg) {
}
free(packet);
LOG_INFO("[%p]: terminating", ctx);
LOG_INFO("[%p]: terminating", ctx);
#ifndef WIN32
xTaskNotifyGive(ctx->joiner);