Files
snapclient/components/websocket_if/websocket_if.c
Carlos 15b4baba28 - merge with original master from jorgen
- 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
2021-08-19 21:57:16 +02:00

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