TL;DR - hoping for that rubber duck debug moment, I posted a minimalist example of the problem in action, if you just want to view it here. The problem file on that branch is here (...around line 270). Of course, there's a README in each sub directory to help get the full system running locally.
Objective
Upload an audio sample from a connected device. The upload is coming from an ESP32 device. Specifically, this example targets the Seeed Studio XIAO ESP32 S3 (Sense).
For all intents and purposes, I suppose this same solution could be applied to any type of file, not just audio (... I guess I should've just tried a
txtfile first).
The System
The overall system is comprised of the ESP32 device, a REST API built on NestJS and MongoDB as the datastore.
For testing and management purposes, I also built a web-based UI. Feel free to check the example repo if you want to run the whole, entire thing locally.
I have tested the system with audio files uploaded through the web UI. I have also tested the system with audio recorded through the web interface as well.
Both of those approaches work just fine -- I know there isn't a problem with those pieces of the solution.
FWIW - I'm using VS Code and the PlatformIO Extension.
The Problem Area
I have tried several different ways of writing the audio to an HttpClient stream.
If anyone cares to look, I created a branch for each variant of my attempts. The latest being
dev-8
I have gotten the device to make a POST request and see a record in the MongoDB collection, but ALL the audio data is missing from the file.
Here is my latest effort -- apologies for the long-winded code snippet -- can someone please help identify the problem?:
void uploadFile() {
try {
if (sessionId == 0) sessionId = millis();
Serial.print("Spewing chunks now, Session ID: ");
Serial.println(sessionId);
char head[128];
sprintf(head, "--%s\r\nContent-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\nContent-Type: audio/wav\r\n\r\n", AUDIO_FILE_BOUNDARY, WAV_FILE_NAME);
char tail[64];
sprintf(tail, "\r\n--%s--\r\n", AUDIO_FILE_BOUNDARY);
Serial.println("\t==> Begin Request.");
client.beginRequest();
client.post(API_ENDPOINT_MFILE);
client.sendHeader("Connection", "keep-alive");
client.sendHeader("Accept", "*/*");
client.sendHeader("Audio-Source", "streaming-from-device");
client.sendHeader("SessionID", sessionId);
// Using the device MAC address as its unique identifier.
String s(ESP.getEfuseMac());
client.sendHeader("Device-ID", s);
File file = SD.open("/" WAV_FILE_NAME, FILE_READ);
const size_t fLen = file.size();
client.sendHeader("Content-Length", String(fLen));
client.sendHeader("Content-Type", "multipart/form-data; boundary=" AUDIO_FILE_BOUNDARY);
char* fileBuffer = new char[fLen + 1];
Serial.printf("\t==> File Len: %d\n", fLen);
if (file.available()) {
file.readBytesUntil('\0', fileBuffer, fLen);
fileBuffer[fLen + 1] = '\0';
}
file.close();
client.beginBody();
client.println(head);
/**
* @brief Here is the problem
* I even used Github Copilot to help me write this code.
*/
try {
int offSet = 0;
while (offSet < fLen) {
int chunkSize = 1024;
Serial.printf("\t==> offSet: %d\n", offSet);
if (offSet + chunkSize > fLen) {
chunkSize = fLen - offSet;
}
client.write((uint8_t*)(fileBuffer + offSet), chunkSize);
offSet += chunkSize;
}
client.write('\0');
} catch (...) {
Serial.println("\n==== ERROR ===");
Serial.println("Could not write the file to the stream.\n");
}
client.println(tail);
client.flush();
client.endRequest();
Serial.println("\n============> DONE WRITING.\n");
while (!client.available())
;
readResponse();
} catch (...) {
Serial.println("\n\tThere was a problem transmitting audio.\n");
_resetSession();
}
}