I'm using ESPAsyncWebServer to serve an ESP32CAM image to a web page (a pointer to the image buffer has been stored in a FreeRTOS queue by a different task):
void handleImageRequest(AsyncWebServerRequest *request) {
camera_fb_t *photoBuffer;
BaseType_t result = xQueueReceive(imageQueue, &photoBuffer, 0);
if (result == pdPASS) {
request->send_P(200, "image/jpeg", photoBuffer->buf, photoBuffer->len);
} else {
request->send(200, "text/plain", "No Photo Available");
}
}
Now I want to delete the buffer and free the memory with:
esp_camera_fb_return(photoBuffer);
But I can't do it right after the call to send_P() because that function returns almost immediately while the buffer is still being served in the background.
So, does ESPAsyncWebServer provide a callback or other method to inform my code that the entire buffer has been served and may now be deleted?
Thanks.
I'm not sure it's really an "issue" with the library rather than lack of knowledge on my part. However I'll do that in a few days if nobody here has an answer.
Having not yet received a response to the GitHub issue that I posted, I dug into the ESPAsyncWebServer source code. I came up with one solution by hooking a callback function into the Client disconnect sequence. Don't know if this is optimal, but it seem to work. FWIW, here's the code (I also removed the FreeRTOS queue to simplify the example):
void handleImageRequest(AsyncWebServerRequest *request) {
camera_fb_t *photoBuffer;
photoBuffer = esp_camera_fb_get();
if (photoBuffer != nullptr) {
Serial.printf("Got Photo, Width = %d, Height = %d\n", photoBuffer->width, photoBuffer->height);
AsyncClient *currentClient = request->client();
currentClient->onDisconnect(handleClientDisconnect, photoBuffer);
request->send_P(200, "image/jpeg", photoBuffer->buf, photoBuffer->len);
} else {
request->send(200, "text/plain", "No Photo Available");
}
}
void handleClientDisconnect(void *ptr, AsyncClient *client) {
camera_fb_t *photoBuffer = reinterpret_cast<camera_fb_t *>(ptr);
esp_camera_fb_return(photoBuffer);
}
Because the callback is so simple, it's arguably cleaner to use a lambda:
void handleImageRequest(AsyncWebServerRequest *request) {
camera_fb_t *photoBuffer;
photoBuffer = esp_camera_fb_get();
if (photoBuffer != nullptr) {
Serial.printf("Got Photo, Width = %d, Height = %d\n", photoBuffer->width, photoBuffer->height);
AsyncClient *currentClient = request->client();
auto returnPhotoBuffer = [photoBuffer] (void *ptr, AsyncClient *client) {
esp_camera_fb_return(photoBuffer);
};
currentClient->onDisconnect(returnPhotoBuffer, nullptr);
request->send_P(200, "image/jpeg", photoBuffer->buf, photoBuffer->len);
} else {
request->send(200, "text/plain", "No Photo Available");
}
}