From 6600df863e319f1be1f79885bcc3e9006bcc6395 Mon Sep 17 00:00:00 2001 From: David Schramm Date: Sun, 27 Mar 2022 10:23:22 +0200 Subject: [PATCH 1/4] change CAM_STREAMER_MAX_CLIENTS & MIN_FRAME_TIME loc and improved debug --- app_httpd.cpp | 11 ++-- cam_streamer.c | 112 ++++++++++++++++++++++------------------ cam_streamer.h | 1 - esp32-cam-webserver.ino | 3 +- types.h | 11 ++++ 5 files changed, 80 insertions(+), 58 deletions(-) create mode 100644 types.h diff --git a/app_httpd.cpp b/app_httpd.cpp index 6265f1a..10fc218 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -27,10 +27,16 @@ #include "src/favicons.h" #include "src/logo.h" #include "storage.h" +#include "types.h" + +#ifndef MIN_FRAME_TIME + #define MIN_FRAME_TIME 500 +#endif extern "C"{ #include "cam_streamer.h" } + // Functions from the main .ino extern void flashLED(int flashtime); extern void setLamp(int newVal); @@ -793,10 +799,7 @@ void startCameraServer(int hPort, int sPort){ httpd_register_uri_handler(stream_httpd, &info_uri); httpd_register_uri_handler(stream_httpd, &streamviewer_uri); cam_streamer=(cam_streamer_t *) malloc(sizeof(cam_streamer_t)); -#ifndef CAM_STREAMER_DESIRED_FPS -#define CAM_STREAMER_DESIRED_FPS 2 -#endif - cam_streamer_init(cam_streamer, stream_httpd, CAM_STREAMER_DESIRED_FPS); + cam_streamer_init(cam_streamer, stream_httpd, MIN_FRAME_TIME); cam_streamer_start(cam_streamer); } httpd_register_uri_handler(stream_httpd, &favicon_16x16_uri); diff --git a/cam_streamer.c b/cam_streamer.c index 7dc8fe0..f9ea49c 100644 --- a/cam_streamer.c +++ b/cam_streamer.c @@ -7,9 +7,14 @@ #include #include #include +#include #include "cam_streamer.h" +#ifndef CAM_STREAMER_MAX_CLIENTS +#define CAM_STREAMER_MAX_CLIENTS 10 +#endif + #define PART_BOUNDARY "123456789000000000000987654321" #define _STREAM_HEADERS "HTTP/1.1 200 OK\r\n"\ @@ -18,46 +23,57 @@ "Keep-Alive: timeout=15\r\n"\ "Content-Type: multipart/x-mixed-replace;boundary=" PART_BOUNDARY "\r\n" +#define _TEXT_HEADERS "HTTP/1.1 200 OK\r\n"\ + "Access-Control-Allow-Origin: *\r\n"\ + "Connection: Close\r\n"\ + "Content-Type: text/plain\r\n\r\n" + +extern bool debugData; + static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; +static inline void print_debug(const char *fmt, ...) { + if(debugData) { + va_list l; + va_start(l, fmt); + vprintf(fmt, l); + va_end(l); + } +} + static uint8_t is_send_error(int r) { switch(r) { case HTTPD_SOCK_ERR_INVALID: -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] invalid argument occured!\n"); -#endif + print_debug("[cam_streamer] invalid argument occured!\n"); return 1; case HTTPD_SOCK_ERR_TIMEOUT: -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] timeout/interrupt occured!\n"); -#endif + print_debug("[cam_streamer] timeout/interrupt occured!\n"); return 1; case HTTPD_SOCK_ERR_FAIL: -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] unrecoverable error while send()!\n"); -#endif + print_debug("[cam_streamer] unrecoverable error while send()!\n"); return 1; case ESP_ERR_INVALID_ARG: -#ifdef DEBUG_DEFAULT_ON - printf("[text-streamer] session closed!\n"); -#endif + print_debug("[text-streamer] session closed!\n"); return 1; default: -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] sent %d bytes!\n", r); -#endif + print_debug("[cam_streamer] sent %d bytes!\n", r); return 0; } } -void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t fps) { +void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t frame_delay) { memset(s, 0, sizeof(cam_streamer_t)); - s->frame_delay=1000000/fps; + s->frame_delay=1000*frame_delay; s->clients=xQueueCreate(CAM_STREAMER_MAX_CLIENTS*2, sizeof(int)); s->server=server; } +// frame_delay must be in ms (not us) +void cam_streamer_set_frame_delays(cam_streamer_t *s, uint16_t frame_delay) { + s->frame_delay=1000*frame_delay; +} + static void cam_streamer_update_frame(cam_streamer_t *s) { uint8_t l=0; while(!__atomic_compare_exchange_n(&s->buf_lock, &l, 1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { @@ -73,17 +89,13 @@ static void cam_streamer_update_frame(cam_streamer_t *s) { s->last_updated=esp_timer_get_time(); s->part_len=snprintf(s->part_buf, 64, _STREAM_PART, s->buf->len); __atomic_store_n(&s->buf_lock, 0, __ATOMIC_RELAXED); -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] fetched new frame\n"); -#endif + print_debug("[cam_streamer] fetched new frame\n"); } static void cam_streamer_decrement_num_clients(cam_streamer_t *s) { size_t num_clients=s->num_clients; while(num_clients>0 && !__atomic_compare_exchange_n(&s->num_clients, &num_clients, num_clients-1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)); -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] num_clients decremented\n"); -#endif + print_debug("[cam_streamer] num_clients decremented\n"); } void cam_streamer_task(void *p) { @@ -105,16 +117,12 @@ void cam_streamer_task(void *p) { for(unsigned int i=0; iclients, &fd, 10/portTICK_PERIOD_MS)==pdFALSE) { -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] failed to dequeue fd!\n"); -#endif + print_debug("[cam_streamer] failed to dequeue fd!\n"); continue; } -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] dequeued fd %d\n", fd); - printf("[cam_streamer] sending part: \"%.*s\"\n", (int) s->part_len, s->part_buf); -#endif + print_debug("[cam_streamer] dequeued fd %d\n", fd); + print_debug("[cam_streamer] sending part: \"%.*s\"\n", (int) s->part_len, s->part_buf); if(is_send_error(httpd_socket_send(s->server, fd, s->part_buf, s->part_len, 0))) { cam_streamer_decrement_num_clients(s); @@ -132,9 +140,7 @@ void cam_streamer_task(void *p) { } xQueueSend(s->clients, (void *) &fd, 10/portTICK_PERIOD_MS); -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] fd %d requeued\n", fd); -#endif + print_debug("[cam_streamer] fd %d requeued\n", fd); } } } @@ -142,10 +148,8 @@ void cam_streamer_task(void *p) { void cam_streamer_start(cam_streamer_t *s) { BaseType_t r=xTaskCreate(cam_streamer_task, "cam_streamer", 10*1024, (void *) s, tskIDLE_PRIORITY+3, &s->task); -#ifdef DEBUG_DEFAULT_ON if(r!=pdPASS) - printf("[cam_streamer] failed to create task!\n"); -#endif + print_debug("[cam_streamer] failed to create task!\n"); } void cam_streamer_stop(cam_streamer_t *s) { @@ -162,35 +166,41 @@ void cam_streamer_dequeue_all_clients(cam_streamer_t *s) { } bool cam_streamer_enqueue_client(cam_streamer_t *s, int fd) { -#ifdef DEBUG_DEFAULT_ON - printf("sending stream headers:\n%s\nLength: %d\n", _STREAM_HEADERS, strlen(_STREAM_HEADERS)); -#endif + if(s->num_clients>=CAM_STREAMER_MAX_CLIENTS) { + if(httpd_socket_send(s->server, fd, _TEXT_HEADERS, strlen(_TEXT_HEADERS), 0)) { + print_debug("failed sending text headers!\n"); + return false; + } + +#define EMSG "too many clients" + if(httpd_socket_send(s->server, fd, EMSG, strlen(EMSG), 0)) { + print_debug("failed sending message\n"); + return false; + } +#undef EMSG + close(fd); + return false; + } + + print_debug("sending stream headers:\n%s\nLength: %d\n", _STREAM_HEADERS, strlen(_STREAM_HEADERS)); if(is_send_error(httpd_socket_send(s->server, fd, _STREAM_HEADERS, strlen(_STREAM_HEADERS), 0))) { -#ifdef DEBUG_DEFAULT_ON - printf("failed sending headers!\n"); -#endif + print_debug("failed sending headers!\n"); return false; } if(is_send_error(httpd_socket_send(s->server, fd, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY), 0))) { -#ifdef DEBUG_DEFAULT_ON - printf("failed sending boundary!\n"); -#endif + print_debug("failed sending boundary!\n"); return false; } const BaseType_t r=xQueueSend(s->clients, (void *) &fd, 10*portTICK_PERIOD_MS); if(r!=pdTRUE) { -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] failed to enqueue fd %d\n", fd); -#endif + print_debug("[cam_streamer] failed to enqueue fd %d\n", fd); #define EMSG "failed to enqueue" httpd_socket_send(s->server, fd, EMSG, strlen(EMSG), 0); #undef EMSG } else { -#ifdef DEBUG_DEFAULT_ON - printf("[cam_streamer] socket %d enqueued\n", fd); -#endif + print_debug("[cam_streamer] socket %d enqueued\n", fd); __atomic_fetch_add(&s->num_clients, 1, __ATOMIC_RELAXED); vTaskResume(s->task); } diff --git a/cam_streamer.h b/cam_streamer.h index a128926..2ff3e1b 100644 --- a/cam_streamer.h +++ b/cam_streamer.h @@ -11,7 +11,6 @@ #include #include -#define CAM_STREAMER_MAX_CLIENTS 10 typedef struct { QueueHandle_t clients; TaskHandle_t task; diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index a39c013..ef8cb9a 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -8,6 +8,7 @@ #include "src/parsebytes.h" #include "time.h" #include +#include "types.h" /* This sketch is a extension/expansion/reork of the 'official' ESP32 Camera example * sketch from Expressif: @@ -37,13 +38,11 @@ // Primary config, or defaults. #if __has_include("myconfig.h") - struct station { const char ssid[65]; const char password[65]; const bool dhcp;}; // do no edit #include "myconfig.h" #else #warning "Using Defaults: Copy myconfig.sample.h to myconfig.h and edit that to use your own settings" #define WIFI_AP_ENABLE #define CAMERA_MODEL_AI_THINKER - struct station { const char ssid[65]; const char password[65]; const bool dhcp;} stationList[] = {{"ESP32-CAM-CONNECT","InsecurePassword", true}}; #endif diff --git a/types.h b/types.h new file mode 100644 index 0000000..f17f021 --- /dev/null +++ b/types.h @@ -0,0 +1,11 @@ +#ifndef _INC_TYPES +#define _INC_TYPES + +#include +struct station { + const char ssid[65]; + const char password[65]; + const bool dhcp; +}; + +#endif From 7565740a4b8a3aa74aa354936d406fbd6161c1f5 Mon Sep 17 00:00:00 2001 From: David Schramm Date: Sun, 27 Mar 2022 13:47:29 +0200 Subject: [PATCH 2/4] add autolamp and more debug output --- app_httpd.cpp | 4 +--- cam_streamer.c => cam_streamer.cpp | 24 ++++++++++++++++-------- cam_streamer.h | 1 + 3 files changed, 18 insertions(+), 11 deletions(-) rename cam_streamer.c => cam_streamer.cpp (88%) diff --git a/app_httpd.cpp b/app_httpd.cpp index 10fc218..3bdce90 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -33,9 +33,7 @@ #define MIN_FRAME_TIME 500 #endif -extern "C"{ #include "cam_streamer.h" -} // Functions from the main .ino extern void flashLED(int flashtime); @@ -308,7 +306,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){ else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val); else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val); else if(!strcmp(variable, "rotate")) myRotation = val; - else if(!strcmp(variable, "min_frame_time")) minFrameTime = val; + else if(!strcmp(variable, "min_frame_time")) cam_streamer_set_frame_delay(cam_streamer, val); else if(!strcmp(variable, "autolamp") && (lampVal != -1)) { autoLamp = val; if (autoLamp) { diff --git a/cam_streamer.c b/cam_streamer.cpp similarity index 88% rename from cam_streamer.c rename to cam_streamer.cpp index f9ea49c..2c1c3f1 100644 --- a/cam_streamer.c +++ b/cam_streamer.cpp @@ -12,6 +12,7 @@ #include "cam_streamer.h" #ifndef CAM_STREAMER_MAX_CLIENTS +#warning "CAM_STREAMER_MAX_CLIENTS not defined, using default value of 10" #define CAM_STREAMER_MAX_CLIENTS 10 #endif @@ -29,6 +30,9 @@ "Content-Type: text/plain\r\n\r\n" extern bool debugData; +extern int lampVal; +extern bool autoLamp; +extern void setLamp(int); static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; @@ -70,7 +74,7 @@ void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t frame_ } // frame_delay must be in ms (not us) -void cam_streamer_set_frame_delays(cam_streamer_t *s, uint16_t frame_delay) { +void cam_streamer_set_frame_delay(cam_streamer_t *s, uint16_t frame_delay) { s->frame_delay=1000*frame_delay; } @@ -105,31 +109,35 @@ void cam_streamer_task(void *p) { int fd; unsigned int n_entries; for(;;) { - while(!(n_entries=uxQueueMessagesWaiting(s->clients))) + while(!(n_entries=uxQueueMessagesWaiting(s->clients))) { + if(autoLamp && lampVal!=-1) setLamp(0); vTaskSuspend(NULL); + if(autoLamp && lampVal!=-1) setLamp(lampVal); + } current_time=esp_timer_get_time(); if((current_time-last_time)frame_delay) vTaskDelay((s->frame_delay-(current_time-last_time))/(1000*portTICK_PERIOD_MS)); - last_time=current_time; cam_streamer_update_frame(s); + print_debug("[cam_streamer] frame_size: %luB %lums\n", s->buf->len, (current_time-last_time)/1000); + last_time=current_time; + for(unsigned int i=0; iclients, &fd, 10/portTICK_PERIOD_MS)==pdFALSE) { print_debug("[cam_streamer] failed to dequeue fd!\n"); continue; } - print_debug("[cam_streamer] dequeued fd %d\n", fd); - print_debug("[cam_streamer] sending part: \"%.*s\"\n", (int) s->part_len, s->part_buf); - - if(is_send_error(httpd_socket_send(s->server, fd, s->part_buf, s->part_len, 0))) { + print_debug("[cam_streamer] fd %d dequeued\n", fd); + + if(is_send_error(httpd_socket_send(s->server, fd, s->part_buf, s->part_len, 0))) { cam_streamer_decrement_num_clients(s); continue; } - if(is_send_error(httpd_socket_send(s->server, fd, s->buf->buf, s->buf->len, 0))) { + if(is_send_error(httpd_socket_send(s->server, fd, (const char *) s->buf->buf, s->buf->len, 0))) { cam_streamer_decrement_num_clients(s); continue; } diff --git a/cam_streamer.h b/cam_streamer.h index 2ff3e1b..52dd21f 100644 --- a/cam_streamer.h +++ b/cam_streamer.h @@ -25,6 +25,7 @@ typedef struct { } cam_streamer_t; void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t fps); +void cam_streamer_set_frame_delay(cam_streamer_t *s, uint16_t frame_delay); void cam_streamer_task(void *p); void cam_streamer_start(cam_streamer_t *s); void cam_streamer_stop(cam_streamer_t *s); From c209af1c38d06d0d3cef596f2c3d6fd8b958d02a Mon Sep 17 00:00:00 2001 From: David Schramm Date: Sun, 27 Mar 2022 13:56:08 +0200 Subject: [PATCH 3/4] remove types.h --- app_httpd.cpp | 2 +- esp32-cam-webserver.ino | 2 +- types.h | 11 ----------- 3 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 types.h diff --git a/app_httpd.cpp b/app_httpd.cpp index 3bdce90..62390c9 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -27,9 +27,9 @@ #include "src/favicons.h" #include "src/logo.h" #include "storage.h" -#include "types.h" #ifndef MIN_FRAME_TIME + #warning "MIN_FRAME_TIME undefined, setting to default value of 500" #define MIN_FRAME_TIME 500 #endif diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index ef8cb9a..a05f1c1 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -8,7 +8,6 @@ #include "src/parsebytes.h" #include "time.h" #include -#include "types.h" /* This sketch is a extension/expansion/reork of the 'official' ESP32 Camera example * sketch from Expressif: @@ -38,6 +37,7 @@ // Primary config, or defaults. #if __has_include("myconfig.h") + struct station { const char ssid[65]; const char password[65]; const bool dhcp;}; // do no edit #include "myconfig.h" #else #warning "Using Defaults: Copy myconfig.sample.h to myconfig.h and edit that to use your own settings" diff --git a/types.h b/types.h deleted file mode 100644 index f17f021..0000000 --- a/types.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _INC_TYPES -#define _INC_TYPES - -#include -struct station { - const char ssid[65]; - const char password[65]; - const bool dhcp; -}; - -#endif From 3bba1a5e98673bdeb9c12c73ecd117d51e49a718 Mon Sep 17 00:00:00 2001 From: David Schramm Date: Mon, 11 Apr 2022 11:05:25 +0200 Subject: [PATCH 4/4] import myconfig setting in cam_streamer --- app_httpd.cpp | 7 ++++++- cam_streamer.cpp | 15 ++++++++++++--- cam_streamer.h | 2 +- myconfig.sample.h | 5 ++++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app_httpd.cpp b/app_httpd.cpp index 62390c9..2eb4b53 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -28,8 +28,13 @@ #include "src/logo.h" #include "storage.h" +#if __has_include("myconfig.h") + struct station { const char ssid[65]; const char password[65]; const bool dhcp;}; + #include "myconfig.h" +#endif + #ifndef MIN_FRAME_TIME - #warning "MIN_FRAME_TIME undefined, setting to default value of 500" + #warning "MIN_FRAME_TIME undefined, using default value of 500" #define MIN_FRAME_TIME 500 #endif diff --git a/cam_streamer.cpp b/cam_streamer.cpp index 2c1c3f1..bce8b57 100644 --- a/cam_streamer.cpp +++ b/cam_streamer.cpp @@ -11,8 +11,17 @@ #include "cam_streamer.h" +#if __has_include("myconfig.h") +struct station { + const char ssid[65]; + const char password[65]; + const bool dhcp; +}; +#include "myconfig.h" +#endif + #ifndef CAM_STREAMER_MAX_CLIENTS -#warning "CAM_STREAMER_MAX_CLIENTS not defined, using default value of 10" +#warning "CAM_STREAMER_MAX_CLIENTS undefined, using default value of 10" #define CAM_STREAMER_MAX_CLIENTS 10 #endif @@ -131,8 +140,8 @@ void cam_streamer_task(void *p) { } print_debug("[cam_streamer] fd %d dequeued\n", fd); - - if(is_send_error(httpd_socket_send(s->server, fd, s->part_buf, s->part_len, 0))) { + + if(is_send_error(httpd_socket_send(s->server, fd, s->part_buf, s->part_len, 0))) { cam_streamer_decrement_num_clients(s); continue; } diff --git a/cam_streamer.h b/cam_streamer.h index 52dd21f..2a1500c 100644 --- a/cam_streamer.h +++ b/cam_streamer.h @@ -24,7 +24,7 @@ typedef struct { size_t num_clients; } cam_streamer_t; -void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t fps); +void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t frame_delay); void cam_streamer_set_frame_delay(cam_streamer_t *s, uint16_t frame_delay); void cam_streamer_task(void *p); void cam_streamer_start(cam_streamer_t *s); diff --git a/myconfig.sample.h b/myconfig.sample.h index 86efcaf..3ea701b 100644 --- a/myconfig.sample.h +++ b/myconfig.sample.h @@ -22,7 +22,7 @@ * just replace your ssid and password in the line below. */ -struct station stationList[] = {{"my_ssid","my_password", true}}; +const struct station stationList[] = {{"my_ssid","my_password", true}}; /* * You can extend the stationList[] above with additional SSID+Password pairs @@ -148,6 +148,9 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // max_fps = 1000/min_frame_time // #define MIN_FRAME_TIME 500 +// Maximum number of clients of the stream +// #define CAM_STREAMER_MAX_CLIENTS 10 + /* * Additional Features *