- minimize RAM usage of all components - use both IRAM and DRAM in player component so we can buffer up to 1s on modules without SPI RAM - support fragemented pcm chunks so we can use all available RAM if there isn't a big enough block available but still enough HEAP - reinclude all components from jorgen's master branch - add custom i2s driver to get a precise timing of initial sync - change wrong usage of esp_timer for latency measurement of snapcast protocol - add player component
167 lines
4.6 KiB
C
167 lines
4.6 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include "esp_log.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
|
|
#include "websocket_server.h"
|
|
#include "websocket.h"
|
|
#include "websocket_if.h"
|
|
|
|
#include "protocol.h"
|
|
|
|
static QueueHandle_t client_queue;
|
|
const static int client_queue_size = 10;
|
|
|
|
int websocket_if_start(void)
|
|
{ int ws_res = ws_server_start();
|
|
if (ws_res == 0)
|
|
{ printf("Websocket error\n");
|
|
}
|
|
xTaskCreate(&server_task,"server_task",8*1024,NULL,6,NULL);
|
|
xTaskCreate(&server_handle_task,"server_handle_task",8*1024,NULL,9,NULL);
|
|
return 1;
|
|
}
|
|
|
|
int websocket_if_stop(void)
|
|
{ return 1;
|
|
|
|
}
|
|
|
|
// Handles websocket events - Pass on to protocol handler using queue
|
|
void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) {
|
|
const static char* TAG = "websocket_callback";
|
|
int value;
|
|
|
|
switch(type) {
|
|
case WEBSOCKET_CONNECT:
|
|
ESP_LOGI(TAG,"client %i connected!",num);
|
|
break;
|
|
case WEBSOCKET_DISCONNECT_EXTERNAL:
|
|
ESP_LOGI(TAG,"client %i sent a disconnect message",num);
|
|
break;
|
|
case WEBSOCKET_DISCONNECT_INTERNAL:
|
|
ESP_LOGI(TAG,"client %i was disconnected",num);
|
|
break;
|
|
case WEBSOCKET_DISCONNECT_ERROR:
|
|
ESP_LOGI(TAG,"client %i was disconnected due to an error",num);
|
|
break;
|
|
case WEBSOCKET_TEXT:
|
|
if(len) { // if the message length was greater than zero
|
|
switch(msg[0]) {
|
|
case 'L':
|
|
if(sscanf(msg,"L%i",&value)) {
|
|
ESP_LOGI(TAG,"LED value: %i",value);
|
|
ws_server_send_text_all_from_callback(msg,len); // broadcast it!
|
|
}
|
|
break;
|
|
case 'M':
|
|
ESP_LOGI(TAG, "got message length %i: %s", (int)len-1, &(msg[1]));
|
|
break;
|
|
default:
|
|
ESP_LOGI(TAG, "got an unknown message with length %i", (int)len);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WEBSOCKET_BIN:
|
|
{
|
|
//ESP_LOGI(TAG,"client %i sent binary message of size %i:\n",num,(uint32_t)len);
|
|
uint8_t (*protmsg)[] = malloc(len);
|
|
memcpy(protmsg,msg,len);
|
|
xQueueSendToBack(prot_queue,&protmsg,portMAX_DELAY);
|
|
break;
|
|
}
|
|
case WEBSOCKET_PING:
|
|
ESP_LOGI(TAG,"client %i pinged us with message of size %i:\n%s",num,(uint32_t)len,msg);
|
|
break;
|
|
case WEBSOCKET_PONG:
|
|
ESP_LOGI(TAG,"client %i responded to the ping",num);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// serves any clients
|
|
void http_serve(struct netconn *conn) {
|
|
const static char* TAG = "http_server";
|
|
struct netbuf* inbuf;
|
|
static char* buf;
|
|
static uint16_t buflen;
|
|
static err_t err;
|
|
|
|
netconn_set_recvtimeout(conn,2000); // allow a connection timeout of 1 second
|
|
ESP_LOGI(TAG,"reading from client...");
|
|
err = netconn_recv(conn, &inbuf);
|
|
ESP_LOGI(TAG,"read from client");
|
|
if(err==ERR_OK) {
|
|
netbuf_data(inbuf, (void**)&buf, &buflen);
|
|
if(buf) {
|
|
if(strstr(buf,"GET / ")
|
|
&& strstr(buf,"Upgrade: websocket")) {
|
|
ESP_LOGI(TAG,"Requesting websocket on /");
|
|
ws_server_add_client(conn,buf,buflen,"/",websocket_callback);
|
|
netbuf_delete(inbuf);
|
|
}
|
|
|
|
else {
|
|
ESP_LOGI(TAG,"Unknown request");
|
|
netconn_close(conn);
|
|
netconn_delete(conn);
|
|
netbuf_delete(inbuf);
|
|
}
|
|
}
|
|
else {
|
|
ESP_LOGI(TAG,"Unknown request (empty?...)");
|
|
netconn_close(conn);
|
|
netconn_delete(conn);
|
|
netbuf_delete(inbuf);
|
|
}
|
|
}
|
|
else { // if err==ERR_OK
|
|
ESP_LOGI(TAG,"error on read, closing connection");
|
|
netconn_close(conn);
|
|
netconn_delete(conn);
|
|
netbuf_delete(inbuf);
|
|
}
|
|
}
|
|
|
|
// handles clients when they first connect. passes to a queue
|
|
void server_task(void* pvParameters) {
|
|
const static char* TAG = "server_task";
|
|
struct netconn *conn, *newconn;
|
|
static err_t err;
|
|
client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*));
|
|
|
|
conn = netconn_new(NETCONN_TCP);
|
|
netconn_bind(conn,NULL,8088);
|
|
netconn_listen(conn);
|
|
ESP_LOGI(TAG,"server listening");
|
|
do {
|
|
err = netconn_accept(conn, &newconn);
|
|
ESP_LOGI(TAG,"new client");
|
|
if(err == ERR_OK) {
|
|
xQueueSendToBack(client_queue,&newconn,portMAX_DELAY);
|
|
//http_serve(newconn);
|
|
}
|
|
} while(err == ERR_OK);
|
|
netconn_close(conn);
|
|
netconn_delete(conn);
|
|
ESP_LOGE(TAG,"task ending, rebooting board");
|
|
esp_restart();
|
|
}
|
|
|
|
// receives clients from queue, handles them
|
|
void server_handle_task(void* pvParameters) {
|
|
const static char* TAG = "server_handle_task";
|
|
struct netconn* conn;
|
|
ESP_LOGI(TAG,"task starting");
|
|
for(;;) {
|
|
xQueueReceive(client_queue,&conn,portMAX_DELAY);
|
|
if(!conn) continue;
|
|
http_serve(conn);
|
|
}
|
|
vTaskDelete(NULL);
|
|
}
|