Skip to content

Commit 095e221

Browse files
authored
Merge pull request #239 from daschr/fork/multi-stream
Fix autoLamp and FPS settings
2 parents 8e37e22 + 3bba1a5 commit 095e221

File tree

5 files changed

+101
-66
lines changed

5 files changed

+101
-66
lines changed

app_httpd.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,18 @@
2828
#include "src/logo.h"
2929
#include "storage.h"
3030

31-
extern "C"{
31+
#if __has_include("myconfig.h")
32+
struct station { const char ssid[65]; const char password[65]; const bool dhcp;};
33+
#include "myconfig.h"
34+
#endif
35+
36+
#ifndef MIN_FRAME_TIME
37+
#warning "MIN_FRAME_TIME undefined, using default value of 500"
38+
#define MIN_FRAME_TIME 500
39+
#endif
40+
3241
#include "cam_streamer.h"
33-
}
42+
3443
// Functions from the main .ino
3544
extern void flashLED(int flashtime);
3645
extern void setLamp(int newVal);
@@ -302,7 +311,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){
302311
else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val);
303312
else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val);
304313
else if(!strcmp(variable, "rotate")) myRotation = val;
305-
else if(!strcmp(variable, "min_frame_time")) minFrameTime = val;
314+
else if(!strcmp(variable, "min_frame_time")) cam_streamer_set_frame_delay(cam_streamer, val);
306315
else if(!strcmp(variable, "autolamp") && (lampVal != -1)) {
307316
autoLamp = val;
308317
if (autoLamp) {
@@ -793,10 +802,7 @@ void startCameraServer(int hPort, int sPort){
793802
httpd_register_uri_handler(stream_httpd, &info_uri);
794803
httpd_register_uri_handler(stream_httpd, &streamviewer_uri);
795804
cam_streamer=(cam_streamer_t *) malloc(sizeof(cam_streamer_t));
796-
#ifndef CAM_STREAMER_DESIRED_FPS
797-
#define CAM_STREAMER_DESIRED_FPS 2
798-
#endif
799-
cam_streamer_init(cam_streamer, stream_httpd, CAM_STREAMER_DESIRED_FPS);
805+
cam_streamer_init(cam_streamer, stream_httpd, MIN_FRAME_TIME);
800806
cam_streamer_start(cam_streamer);
801807
}
802808
httpd_register_uri_handler(stream_httpd, &favicon_16x16_uri);

cam_streamer.c renamed to cam_streamer.cpp

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,24 @@
77
#include <freertos/FreeRTOS.h>
88
#include <freertos/queue.h>
99
#include <freertos/task.h>
10+
#include <sys/socket.h>
1011

1112
#include "cam_streamer.h"
1213

14+
#if __has_include("myconfig.h")
15+
struct station {
16+
const char ssid[65];
17+
const char password[65];
18+
const bool dhcp;
19+
};
20+
#include "myconfig.h"
21+
#endif
22+
23+
#ifndef CAM_STREAMER_MAX_CLIENTS
24+
#warning "CAM_STREAMER_MAX_CLIENTS undefined, using default value of 10"
25+
#define CAM_STREAMER_MAX_CLIENTS 10
26+
#endif
27+
1328
#define PART_BOUNDARY "123456789000000000000987654321"
1429

1530
#define _STREAM_HEADERS "HTTP/1.1 200 OK\r\n"\
@@ -18,46 +33,60 @@
1833
"Keep-Alive: timeout=15\r\n"\
1934
"Content-Type: multipart/x-mixed-replace;boundary=" PART_BOUNDARY "\r\n"
2035

36+
#define _TEXT_HEADERS "HTTP/1.1 200 OK\r\n"\
37+
"Access-Control-Allow-Origin: *\r\n"\
38+
"Connection: Close\r\n"\
39+
"Content-Type: text/plain\r\n\r\n"
40+
41+
extern bool debugData;
42+
extern int lampVal;
43+
extern bool autoLamp;
44+
extern void setLamp(int);
45+
2146
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
2247
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
2348

49+
static inline void print_debug(const char *fmt, ...) {
50+
if(debugData) {
51+
va_list l;
52+
va_start(l, fmt);
53+
vprintf(fmt, l);
54+
va_end(l);
55+
}
56+
}
57+
2458
static uint8_t is_send_error(int r) {
2559
switch(r) {
2660
case HTTPD_SOCK_ERR_INVALID:
27-
#ifdef DEBUG_DEFAULT_ON
28-
printf("[cam_streamer] invalid argument occured!\n");
29-
#endif
61+
print_debug("[cam_streamer] invalid argument occured!\n");
3062
return 1;
3163
case HTTPD_SOCK_ERR_TIMEOUT:
32-
#ifdef DEBUG_DEFAULT_ON
33-
printf("[cam_streamer] timeout/interrupt occured!\n");
34-
#endif
64+
print_debug("[cam_streamer] timeout/interrupt occured!\n");
3565
return 1;
3666
case HTTPD_SOCK_ERR_FAIL:
37-
#ifdef DEBUG_DEFAULT_ON
38-
printf("[cam_streamer] unrecoverable error while send()!\n");
39-
#endif
67+
print_debug("[cam_streamer] unrecoverable error while send()!\n");
4068
return 1;
4169
case ESP_ERR_INVALID_ARG:
42-
#ifdef DEBUG_DEFAULT_ON
43-
printf("[text-streamer] session closed!\n");
44-
#endif
70+
print_debug("[text-streamer] session closed!\n");
4571
return 1;
4672
default:
47-
#ifdef DEBUG_DEFAULT_ON
48-
printf("[cam_streamer] sent %d bytes!\n", r);
49-
#endif
73+
print_debug("[cam_streamer] sent %d bytes!\n", r);
5074
return 0;
5175
}
5276
}
5377

54-
void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t fps) {
78+
void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t frame_delay) {
5579
memset(s, 0, sizeof(cam_streamer_t));
56-
s->frame_delay=1000000/fps;
80+
s->frame_delay=1000*frame_delay;
5781
s->clients=xQueueCreate(CAM_STREAMER_MAX_CLIENTS*2, sizeof(int));
5882
s->server=server;
5983
}
6084

85+
// frame_delay must be in ms (not us)
86+
void cam_streamer_set_frame_delay(cam_streamer_t *s, uint16_t frame_delay) {
87+
s->frame_delay=1000*frame_delay;
88+
}
89+
6190
static void cam_streamer_update_frame(cam_streamer_t *s) {
6291
uint8_t l=0;
6392
while(!__atomic_compare_exchange_n(&s->buf_lock, &l, 1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
@@ -73,17 +102,13 @@ static void cam_streamer_update_frame(cam_streamer_t *s) {
73102
s->last_updated=esp_timer_get_time();
74103
s->part_len=snprintf(s->part_buf, 64, _STREAM_PART, s->buf->len);
75104
__atomic_store_n(&s->buf_lock, 0, __ATOMIC_RELAXED);
76-
#ifdef DEBUG_DEFAULT_ON
77-
printf("[cam_streamer] fetched new frame\n");
78-
#endif
105+
print_debug("[cam_streamer] fetched new frame\n");
79106
}
80107

81108
static void cam_streamer_decrement_num_clients(cam_streamer_t *s) {
82109
size_t num_clients=s->num_clients;
83110
while(num_clients>0 && !__atomic_compare_exchange_n(&s->num_clients, &num_clients, num_clients-1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED));
84-
#ifdef DEBUG_DEFAULT_ON
85-
printf("[cam_streamer] num_clients decremented\n");
86-
#endif
111+
print_debug("[cam_streamer] num_clients decremented\n");
87112
}
88113

89114
void cam_streamer_task(void *p) {
@@ -93,35 +118,35 @@ void cam_streamer_task(void *p) {
93118
int fd;
94119
unsigned int n_entries;
95120
for(;;) {
96-
while(!(n_entries=uxQueueMessagesWaiting(s->clients)))
121+
while(!(n_entries=uxQueueMessagesWaiting(s->clients))) {
122+
if(autoLamp && lampVal!=-1) setLamp(0);
97123
vTaskSuspend(NULL);
124+
if(autoLamp && lampVal!=-1) setLamp(lampVal);
125+
}
98126

99127
current_time=esp_timer_get_time();
100128
if((current_time-last_time)<s->frame_delay)
101129
vTaskDelay((s->frame_delay-(current_time-last_time))/(1000*portTICK_PERIOD_MS));
102-
last_time=current_time;
103130

104131
cam_streamer_update_frame(s);
105132

133+
print_debug("[cam_streamer] frame_size: %luB %lums\n", s->buf->len, (current_time-last_time)/1000);
134+
last_time=current_time;
135+
106136
for(unsigned int i=0; i<n_entries; ++i) {
107137
if(xQueueReceive(s->clients, &fd, 10/portTICK_PERIOD_MS)==pdFALSE) {
108-
#ifdef DEBUG_DEFAULT_ON
109-
printf("[cam_streamer] failed to dequeue fd!\n");
110-
#endif
138+
print_debug("[cam_streamer] failed to dequeue fd!\n");
111139
continue;
112140
}
113141

114-
#ifdef DEBUG_DEFAULT_ON
115-
printf("[cam_streamer] dequeued fd %d\n", fd);
116-
printf("[cam_streamer] sending part: \"%.*s\"\n", (int) s->part_len, s->part_buf);
117-
#endif
142+
print_debug("[cam_streamer] fd %d dequeued\n", fd);
118143

119144
if(is_send_error(httpd_socket_send(s->server, fd, s->part_buf, s->part_len, 0))) {
120145
cam_streamer_decrement_num_clients(s);
121146
continue;
122147
}
123148

124-
if(is_send_error(httpd_socket_send(s->server, fd, s->buf->buf, s->buf->len, 0))) {
149+
if(is_send_error(httpd_socket_send(s->server, fd, (const char *) s->buf->buf, s->buf->len, 0))) {
125150
cam_streamer_decrement_num_clients(s);
126151
continue;
127152
}
@@ -132,20 +157,16 @@ void cam_streamer_task(void *p) {
132157
}
133158

134159
xQueueSend(s->clients, (void *) &fd, 10/portTICK_PERIOD_MS);
135-
#ifdef DEBUG_DEFAULT_ON
136-
printf("[cam_streamer] fd %d requeued\n", fd);
137-
#endif
160+
print_debug("[cam_streamer] fd %d requeued\n", fd);
138161
}
139162
}
140163
}
141164

142165
void cam_streamer_start(cam_streamer_t *s) {
143166
BaseType_t r=xTaskCreate(cam_streamer_task, "cam_streamer", 10*1024, (void *) s, tskIDLE_PRIORITY+3, &s->task);
144167

145-
#ifdef DEBUG_DEFAULT_ON
146168
if(r!=pdPASS)
147-
printf("[cam_streamer] failed to create task!\n");
148-
#endif
169+
print_debug("[cam_streamer] failed to create task!\n");
149170
}
150171

151172
void cam_streamer_stop(cam_streamer_t *s) {
@@ -162,35 +183,41 @@ void cam_streamer_dequeue_all_clients(cam_streamer_t *s) {
162183
}
163184

164185
bool cam_streamer_enqueue_client(cam_streamer_t *s, int fd) {
165-
#ifdef DEBUG_DEFAULT_ON
166-
printf("sending stream headers:\n%s\nLength: %d\n", _STREAM_HEADERS, strlen(_STREAM_HEADERS));
167-
#endif
186+
if(s->num_clients>=CAM_STREAMER_MAX_CLIENTS) {
187+
if(httpd_socket_send(s->server, fd, _TEXT_HEADERS, strlen(_TEXT_HEADERS), 0)) {
188+
print_debug("failed sending text headers!\n");
189+
return false;
190+
}
191+
192+
#define EMSG "too many clients"
193+
if(httpd_socket_send(s->server, fd, EMSG, strlen(EMSG), 0)) {
194+
print_debug("failed sending message\n");
195+
return false;
196+
}
197+
#undef EMSG
198+
close(fd);
199+
return false;
200+
}
201+
202+
print_debug("sending stream headers:\n%s\nLength: %d\n", _STREAM_HEADERS, strlen(_STREAM_HEADERS));
168203
if(is_send_error(httpd_socket_send(s->server, fd, _STREAM_HEADERS, strlen(_STREAM_HEADERS), 0))) {
169-
#ifdef DEBUG_DEFAULT_ON
170-
printf("failed sending headers!\n");
171-
#endif
204+
print_debug("failed sending headers!\n");
172205
return false;
173206
}
174207

175208
if(is_send_error(httpd_socket_send(s->server, fd, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY), 0))) {
176-
#ifdef DEBUG_DEFAULT_ON
177-
printf("failed sending boundary!\n");
178-
#endif
209+
print_debug("failed sending boundary!\n");
179210
return false;
180211
}
181212

182213
const BaseType_t r=xQueueSend(s->clients, (void *) &fd, 10*portTICK_PERIOD_MS);
183214
if(r!=pdTRUE) {
184-
#ifdef DEBUG_DEFAULT_ON
185-
printf("[cam_streamer] failed to enqueue fd %d\n", fd);
186-
#endif
215+
print_debug("[cam_streamer] failed to enqueue fd %d\n", fd);
187216
#define EMSG "failed to enqueue"
188217
httpd_socket_send(s->server, fd, EMSG, strlen(EMSG), 0);
189218
#undef EMSG
190219
} else {
191-
#ifdef DEBUG_DEFAULT_ON
192-
printf("[cam_streamer] socket %d enqueued\n", fd);
193-
#endif
220+
print_debug("[cam_streamer] socket %d enqueued\n", fd);
194221
__atomic_fetch_add(&s->num_clients, 1, __ATOMIC_RELAXED);
195222
vTaskResume(s->task);
196223
}

cam_streamer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <freertos/queue.h>
1212
#include <freertos/task.h>
1313

14-
#define CAM_STREAMER_MAX_CLIENTS 10
1514
typedef struct {
1615
QueueHandle_t clients;
1716
TaskHandle_t task;
@@ -25,7 +24,8 @@ typedef struct {
2524
size_t num_clients;
2625
} cam_streamer_t;
2726

28-
void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t fps);
27+
void cam_streamer_init(cam_streamer_t *s, httpd_handle_t server, uint16_t frame_delay);
28+
void cam_streamer_set_frame_delay(cam_streamer_t *s, uint16_t frame_delay);
2929
void cam_streamer_task(void *p);
3030
void cam_streamer_start(cam_streamer_t *s);
3131
void cam_streamer_stop(cam_streamer_t *s);

esp32-cam-webserver.ino

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,12 @@
3737

3838
// Primary config, or defaults.
3939
#if __has_include("myconfig.h")
40-
struct station { const char ssid[65]; const char password[65]; const bool dhcp;}; // do no edit
40+
struct station { const char ssid[65]; const char password[65]; const bool dhcp;}; // do no edit
4141
#include "myconfig.h"
4242
#else
4343
#warning "Using Defaults: Copy myconfig.sample.h to myconfig.h and edit that to use your own settings"
4444
#define WIFI_AP_ENABLE
4545
#define CAMERA_MODEL_AI_THINKER
46-
struct station { const char ssid[65]; const char password[65]; const bool dhcp;}
4746
stationList[] = {{"ESP32-CAM-CONNECT","InsecurePassword", true}};
4847
#endif
4948

myconfig.sample.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* just replace your ssid and password in the line below.
2323
*/
2424

25-
struct station stationList[] = {{"my_ssid","my_password", true}};
25+
const struct station stationList[] = {{"my_ssid","my_password", true}};
2626

2727
/*
2828
* You can extend the stationList[] above with additional SSID+Password pairs
@@ -148,6 +148,9 @@ struct station stationList[] = {{"ssid1", "pass1", true},
148148
// max_fps = 1000/min_frame_time
149149
// #define MIN_FRAME_TIME 500
150150

151+
// Maximum number of clients of the stream
152+
// #define CAM_STREAMER_MAX_CLIENTS 10
153+
151154
/*
152155
* Additional Features
153156
*

0 commit comments

Comments
 (0)