WiFiClient.cpp:395] write(): fail on fd 60, errno: 11, "No more processes"

mchahn
Posts: 17
Joined: Fri Sep 18, 2020 6:31 am

WiFiClient.cpp:395] write(): fail on fd 60, errno: 11, "No more processes"

Postby mchahn » Fri Aug 27, 2021 1:57 am

I have an esp32 aurdino app that is serving a video stream (see code below). I'm constantly getting the error message: WiFiClient.cpp:395] write(): fail on fd 60, errno: 11, 'No more processes'. It is clogging up my logs. Strangely enough I don't see any symptoms in my app, but I really want to fix this.

I searched for "No more processes" in the entire esp32 arduino repo and got no hits. So it must be coming from the idf level. When I searched the esp32 idf repo I got

Code: Untitled.cpp Select all

#define pdFREERTOS_ERRNO_EAGAIN           11  /* No more processes */
But I couldn't find any code with that string or any code referencing pdFREERTOS_ERRNO_EAGAIN.

I'm not even sure what a "process" is. Is that a task? I googled "esp32 processes" and got nothing interesting.

As you can tell I am lost. Can someone help me understand what is going on?

Code: Untitled.cpp Select all


// https://RandomNerdTutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/

#include "Arduino.h"
#include "main.h"

// #include "esp_camera.h"
// #include "esp_timer.h"
// #include "img_converters.h"
// #include "fb_gfx.h"
// #include "soc/soc.h" //disable brownout problems
// #include "soc/rtc_cntl_reg.h" //disable brownout problems
// #include "esp_http_server.h"

#include "OV2640.h"
#include <WiFi.h>
#include <WebServer.h>
#include <WiFiClient.h>
#include <esp_bt.h>
#include <esp_wifi.h>
#include <esp_sleep.h>
#include <driver/rtc_io.h>

#include "output.h"
#include "http.h"
#include "camera.h"

#define APP_CPU 1
#define PRO_CPU 0 = 0;

u32_t fps = 0;
u32_t fpsCounter = 0;

OV2640 cam;
WebServer multiServer(8080);

// ===== rtos task handles =========================
// Streaming is implemented with 3 tasks:
TaskHandle_t tMjpeg; // handles client connections to the webserver
TaskHandle_t tCam; // handles getting picture frames from the camera and storing them locally
TaskHandle_t tStream; // actually streaming frames to all connected clients

// frameSync semaphore is used to prevent streaming buffer as it is replaced with the next frame
SemaphoreHandle_t frameSync = NULL;

// Queue stores currently connected clients to whom we are streaming
QueueHandle_t streamingClients;

// We will try to achieve this frame rate
#define FPS 14

// We will handle web client requests every 50 ms (20 Hz)
const int WSINTERVAL = 100;

void camCB(void* pvParameters);
void streamCB(void * pvParameters);
void streamCB(void * pvParameters);
void handleJPGSstream(void);
void handleJPG(void);
char* allocateMemory(char* aPtr, size_t aSize);
// void handleNotFound();

// ======== Server Connection Handler Task ==========================
void mjpegCB(void* pvParameters) {
TickType_t lastWakeTime;
const TickType_t frequency = pdMS_TO_TICKS(WSINTERVAL);

// Creating frame synchronization semaphore and initializing it
frameSync = xSemaphoreCreateBinary();
xSemaphoreGive( frameSync );

// Creating a queue to track all connected clients
streamingClients = xQueueCreate( 5, sizeof(WiFiClient*) );

//=== setup section ==================

// Creating RTOS task for grabbing frames from the camera
xTaskCreatePinnedToCore(
camCB, // callback
"cam", // name
4096, // stacj size
NULL, // parameters
2, // priority
&tCam, // RTOS task handle
APP_CPU); // core

// Creating task to push the stream to all connected clients
xTaskCreatePinnedToCore(
streamCB,
"strmCB",
4 * 1024,
NULL, //(void*) handler,
2,
&tStream,
APP_CPU);

// Registering webserver handling routines
multiServer.on("/stream", HTTP_GET, handleJPGSstream);
// multiServer.onNotFound(handleNotFound);

// Starting webserver
multiServer.begin();

//=== loop() section ===================
lastWakeTime = xTaskGetTickCount();
for (;;) {
multiServer.handleClient();

// After every server client handling request, we let other tasks run and then pause
taskYIELD();
vTaskDelayUntil(&lastWakeTime, frequency);
}
}

// Commonly used variables:
volatile size_t camSize; // size of the current frame, byte
volatile char* camBuf; // pointer to the current frame


// ==== RTOS task to grab frames from the camera =========================
void camCB(void* pvParameters) {

TickType_t lastWakeTime;

// A running interval associated with currently desired frame rate
const TickType_t frequency = pdMS_TO_TICKS(1000 / FPS);

// Mutex for the critical section of switching the active frames around
portMUX_TYPE xSemaphore = portMUX_INITIALIZER_UNLOCKED;

// Pointers to the 2 frames, their respective sizes and index of the current frame
char* fbs[2] = { NULL, NULL };
size_t fSize[2] = { 0, 0 };
int ifb = 0;

//=== loop() section ===================
lastWakeTime = xTaskGetTickCount();

while (true) {
fpsCounter++;

// Grab a frame from the camera and query its size
cam.run();
size_t s = cam.getSize();

// If frame size is more that we have previously allocated - request 125% of the current frame space
if (s > fSize[ifb]) {
fSize[ifb] = s * 4 / 3;
fbs[ifb] = allocateMemory(fbs[ifb], fSize[ifb]);
}

// Copy current frame into local buffer
char* b = (char*) cam.getfb();
memcpy(fbs[ifb], b, s);

// Let other tasks run and wait until the end of the current frame rate interval (if any time left)
taskYIELD();
vTaskDelayUntil(&lastWakeTime, frequency);

// Only switch frames around if no frame is currently being streamed to a client
// Wait on a semaphore until client operation completes
xSemaphoreTake( frameSync, portMAX_DELAY );

// Do not allow interrupts while switching the current frame
portENTER_CRITICAL(&xSemaphore);
camBuf = fbs[ifb];
camSize = s;
ifb++;
ifb &= 1; // this should produce 1, 0, 1, 0, 1 ... sequence
portEXIT_CRITICAL(&xSemaphore);

// Let anyone waiting for a frame know that the frame is ready
xSemaphoreGive( frameSync );

// Technically only needed once: let the streaming task know that we have at least one frame
// and it could start sending frames to the clients, if any
xTaskNotifyGive( tStream );

// Immediately let other (streaming) tasks run
taskYIELD();

// If streaming task has suspended itself (no active clients to stream to)
// there is no need to grab frames from the camera. We can save some juice
// by suspedning the tasks
if ( eTaskGetState( tStream ) == eSuspended ) {
vTaskSuspend(NULL); // passing NULL means "suspend yourself"
}
}
}


// ==== Memory allocator that takes advantage of PSRAM if present =======================
char* allocateMemory(char* aPtr, size_t aSize) {

// Since current buffer is too smal, free it
if (aPtr != NULL) free(aPtr);


size_t freeHeap = ESP.getFreeHeap();
char* ptr = NULL;

// If memory requested is more than 2/3 of the currently free heap, try PSRAM immediately
if ( aSize > freeHeap * 2 / 3 ) {
if ( psramFound() && ESP.getFreePsram() > aSize ) {
ptr = (char*) ps_malloc(aSize);
}
}
else {
// Enough free heap - let's try allocating fast RAM as a buffer
ptr = (char*) malloc(aSize);

// If allocation on the heap failed, let's give PSRAM one more chance:
if ( ptr == NULL && psramFound() && ESP.getFreePsram() > aSize) {
ptr = (char*) ps_malloc(aSize);
}
}

// Finally, if the memory pointer is NULL, we were not able to allocate any memory, and that is a terminal condition.
if (ptr == NULL) {
ESP.restart();
}
return ptr;
}


// ==== STREAMING ======================================================
const char HEADER[] = "HTTP/1.1 200 OK\r\n" \
"Access-Control-Allow-Origin: *\r\n" \
"Content-Type: multipart/x-mixed-replace; boundary=123456789000000000000987654321\r\n";
const char BOUNDARY[] = "\r\n--123456789000000000000987654321\r\n";
const char CTNTTYPE[] = "Content-Type: image/jpeg\r\nContent-Length: ";
const int hdrLen = strlen(HEADER);
const int bdrLen = strlen(BOUNDARY);
const int cntLen = strlen(CTNTTYPE);


// ==== Handle connection request from clients ===============================
void handleJPGSstream(void)
{
// Can only acommodate 5 clients. The limit is a default for WiFi connections
if ( !uxQueueSpacesAvailable(streamingClients) ) return;

// Create a new WiFi Client object to keep track of this one
WiFiClient* client = new WiFiClient();
*client = multiServer.client();

// Immediately send this client a header
client->write(HEADER, hdrLen);
client->write(BOUNDARY, bdrLen);

// Push the client to the streaming queue
xQueueSend(streamingClients, (void *) &client, 0);

// Wake up streaming tasks, if they were previously suspended:
if ( eTaskGetState( tCam ) == eSuspended ) vTaskResume( tCam );
if ( eTaskGetState( tStream ) == eSuspended ) vTaskResume( tStream );
}


// ==== Actually stream content to all connected clients ========================
void streamCB(void * pvParameters) {
char buf[16];
TickType_t lastWakeTime;
TickType_t frequency;

// Wait until the first frame is captured and there is something to send
// to clients
ulTaskNotifyTake( pdTRUE, /* Clear the notification value before exiting. */
portMAX_DELAY ); /* Block indefinitely. */

lastWakeTime = xTaskGetTickCount();
while (true) {
// Default assumption we are running according to the FPS
frequency = pdMS_TO_TICKS(1000 / FPS);

// Only bother to send anything if there is someone watching
UBaseType_t activeClients = uxQueueMessagesWaiting(streamingClients);
if ( activeClients ) {
// Adjust the period to the number of connected clients
frequency /= activeClients;

// Since we are sending the same frame to everyone,
// pop a client from the the front of the queue
WiFiClient *client;
xQueueReceive (streamingClients, (void*) &client, 0);

// Check if this client is still connected.

if (!client->connected()) {
// delete this client reference if s/he has disconnected
// and don't put it back on the queue anymore. Bye!
delete client;
}
else {

// Ok. This is an actively connected client.
// Let's grab a semaphore to prevent frame changes while we
// are serving this frame
xSemaphoreTake( frameSync, portMAX_DELAY );

client->write(CTNTTYPE, cntLen);
sprintf(buf, "%d\r\n\r\n", camSize);
client->write(buf, strlen(buf));
client->write((char*) camBuf, (size_t)camSize);
client->write(BOUNDARY, bdrLen);

// Since this client is still connected, push it to the end
// of the queue for further processing
xQueueSend(streamingClients, (void *) &client, 0);

// The frame has been served. Release the semaphore and let other tasks run.
// If there is a frame switch ready, it will happen now in between frames
xSemaphoreGive( frameSync );
taskYIELD();
}
}
else {
// Since there are no connected clients, there is no reason to waste battery running
vTaskSuspend(NULL);
}
// Let other tasks run after serving every client
taskYIELD();
vTaskDelayUntil(&lastWakeTime, frequency);
}
}

// ==== Handle invalid URL requests ============================================
// void handleNotFound()
// {
// String message = "Server is running!\n\n";
// message += "URI: ";
// message += multiServer.uri();
// message += "\nMethod: ";
// message += (multiServer.method() == HTTP_GET) ? "GET" : "POST";
// message += "\nArguments: ";
// message += multiServer.args();
// message += "\n";
// multiServer.send(200, "text / plain", message);
// }

// for thinkertoy esp32-cam
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27

#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22

// ==== SETUP method ==================================================================
void initCamera() {
// Configure the camera
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;

// Frame parameters: pick one
// config.frame_size = FRAMESIZE_UXGA;
// config.frame_size = FRAMESIZE_SVGA;
// config.frame_size = FRAMESIZE_QVGA;
config.frame_size = FRAMESIZE_VGA; // 640x480
config.jpeg_quality = 12;
config.fb_count = 2;

if (cam.init(config) != ESP_OK) {
prtl("Error initializing the camera");
delay(10000);
ESP.restart();
}

// Start mainstreaming RTOS task
xTaskCreatePinnedToCore(
mjpegCB,
"mjpeg",
4 * 1024,
NULL,
2,
&tMjpeg,
APP_CPU);
}

u32_t lastFpsCalc = 0;

void cameraLoop() {
if((millis() - lastFpsCalc) > 4000) {
fps = fpsCounter / 4;
fpsCounter = 0;
lastFpsCalc = millis();
}
}

Who is online

Users browsing this forum: Bing [Bot], ChatGPT-User, Google [Bot], meta-externalagent, PetalBot and 4 guests