gilmaimon / ArduinoWebsockets

A library for writing modern websockets applications with Arduino (ESP8266 and ESP32)
GNU General Public License v3.0
448 stars 95 forks source link

Sending large messages crashes ESP32 #89

Open BenBergman opened 3 years ago

BenBergman commented 3 years ago

Describe the bug I am attempting to send high resolution JPEG images captured from an OV2640 camera over websockets. I am able to send VGA (640x480) images no problem, but if I try to scale up to UXGA (1600x1200) the ESP32 spits out a backtrace and reboots.

I think what might be happening is a copy of the data is being made in memory instead of streaming from the existing location. I have been able to take UXGA images and send them via AsyncWebServer (though in that case I had saved them to SPIFFS).

To Reproduce Library version: 0.4.18 Board: ESP32-CAM Send a UXGA frame buffer as a binary websocket message and you will see the app crashes and the ESP32 reboots.

Expected behavior The full frame buffer should be transmitted without crashing the application.

Code My project is based on https://github.com/0015/IdeasNProjects/tree/master/ESP32_CAM_LocalServer/CameraWeb Changing line 55 form FRAMESIZE_VGA to FRAMESIZE_UXGA should cause the application to crash, but leaving it as VGA will transmit the full message just fine.

Additional context One other variation is my setup is using the ESP as the websocket server instead of the client, but I don't think that should have any baring on this issue.

BenBergman commented 3 years ago

Even bumping from VGA to SVGA causes the crash. I did a quick test printing the length of the framebuffer prior to sending. The test VGA was 16744 and the test SVGA was 27581 bytes. I'm sure those values will fluctuate based on the JPEG compression of each image, but it should be the right ball park.

gilmaimon commented 3 years ago

So I looked at the flow, seems like 2 copies are being made. One is essential (as far as I know), because I want to send the whole message on a single WiFiClient.send (including header). When I sent header and body seperately some servers had trouble with it. The other copy is kinda wasteful and can be eliminated. The issue right here.

In order to save space:

  1. The full size should be allocated initially instead of added using the overloaded + operator
  2. Probably should be using std::vector with a suiting c'tor to allocate the whole block once without resizing it

I'm not actively working on the library, so this is open for anyone to help and contribute.

Also, I'm a bit surprised that copying 27K block crashes an esp32, could it be something else? Maybe the network stack itself can't handle that much data? You should consider sending the data as fragmented messages, splitting the big chunk to smaller ones.

Gil.