What is the recommended way to send I2S microphone data to a remote HTTP endpoint using POST? #896
-
Hey @pschatzmann! Amazing library! I'm a embedded system newbie and I'm trying to make my ESP32 send and receive audio data over HTTP Currently I am saving the data to an SD card then reading it back when sending over HTTP I am having trouble making this work because I believe the ESP32's RAM is hitting it's limit when buffering and sending the data at once (recordings are WAV and they are about 300 - 450 KB) Not to mention reading from SD card then sending back is inefficient I wanted to ask if there is a recommended way to do this? I don't mind resorting to other protocols such as UDP. My sketch is as follows: #include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "AudioTools.h"
#define SD_CS GPIO_NUM_5
#define MicPIN_WS GPIO_NUM_21
#define MicPIN_SCK GPIO_NUM_12
#define MicPIN_SD GPIO_NUM_32
#define BUTTON_PIN GPIO_NUM_4
//#define SAMPLE_RATE 22050
#define SAMPLE_RATE 16000
String RECORDING_FILE_PATH = "/input.wav";
bool recording = false;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
static bool buttonPressed = false;
int buttonState = HIGH;
I2SStream i2s;
File audioFile;
EncodedAudioStream out(&audioFile, new WAVEncoder());
StreamCopy copier(out, i2s);
void setup(void);
void loop();
void buttonISR();
void toggleRecording();
void startRecording();
void stopRecording();
void setup(void) {
Serial.begin(115200);
if (!SD.begin(SD_CS)) {
Serial.println("Card Mount Failed");
while (1);
}
AudioLogger::instance().begin(Serial, AudioLogger::Info);
auto cfg = i2s.defaultConfig(RX_MODE);
cfg.channels = 2;
cfg.sample_rate = SAMPLE_RATE;
cfg.pin_ws = MicPIN_WS;
cfg.pin_bck = MicPIN_SCK;
cfg.pin_data = MicPIN_SD;
i2s.begin(cfg);
auto cfg_out = out.defaultConfig();
cfg_out.channels = 2;
cfg_out.sample_rate = SAMPLE_RATE;
out.begin(cfg_out);
copier.setCheckAvailableForWrite(false);
pinMode(BUTTON_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, CHANGE);
}
void loop() {
if (buttonPressed) {
toggleRecording();
delay(debounceDelay);
} else if (recording) {
copier.copy();
}
}
void buttonISR() {
int reading = digitalRead(BUTTON_PIN);
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
buttonPressed = !buttonPressed;
}
}
}
lastDebounceTime = millis();
}
void toggleRecording() {
if (!recording) {
startRecording();
} else {
stopRecording();
}
buttonPressed = false;
}
void startRecording() {
if (recording) return;
if (SD.remove(RECORDING_FILE_PATH)) {
Serial.println("File deleted");
}
audioFile.close();
audioFile = SD.open(RECORDING_FILE_PATH, FILE_WRITE);
out.end();
auto cfg_out = out.defaultConfig();
cfg_out.channels = 2;
cfg_out.sample_rate = 16000;
out.begin(cfg_out);
copier.begin(out, i2s);
Serial.println("RECORDING");
recording = true;
}
void stopRecording() {
copier.end();
audioFile.close();
Serial.println("FILE CLOSED");
recording = false;
} |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 9 replies
-
You don't need to store the data at all: just have a look at the examples-webserver. |
Beta Was this translation helpful? Give feedback.
-
@pschatzmann Thank you for your quick answer! I am currently looking at streams-i2s-webserver_wav.ino but I am assuming this webserver is server by ESP, which does not match my case since my server is a python server hosted remotely and my server only accepts HTTP connections Looking at communication-ip-send this one looks like the closest one to what I need, but I couldn't get this example to run properly, as I get errors when I run the sketch.. I did modify the sketch, the modifed version is below #include "AudioTools.h"
#include <WiFi.h>
#define SAMPLE_RATE 16000
#define MicPIN_WS GPIO_NUM_21
#define MicPIN_SCK GPIO_NUM_12
#define MicPIN_SD GPIO_NUM_32
AudioInfo info(16000, 1, 16);
I2SStream i2s;
WiFiClient client;
MeasuringStream clientTimed(client);
StreamCopy copier(clientTimed, i2s);
const char *ssid = "S20";
const char *password = "39891212";
const char *client_address = "192.168.1.35:8000/talk";
void connectWifi() {
auto cfg = i2s.defaultConfig(RX_MODE);
cfg.channels = 2;
cfg.sample_rate = SAMPLE_RATE;
cfg.pin_ws = MicPIN_WS;
cfg.pin_bck = MicPIN_SCK;
cfg.pin_data = MicPIN_SD;
i2s.begin(cfg);
// connect to WIFI
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(2000);
Serial.print(".");
}
Serial.println();
Serial.println(WiFi. localIP());
// Performance Hack
client.setNoDelay(true);
esp_wifi_set_ps(WIFI_PS_NONE);
}
void connectIP() {
if (!client.connected()) {
while (!client.connect(client_address)) {
Serial.println("trying to connect...");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
connectWifi();
Serial.println("started...");
}
void loop() {
connectIP(); // e.g if client is shut down we try to reconnect
copier.copy();
} And these are the errors:
I know the error is a result of me omitting the port variable, but if I leave it there my connection hangs infinitely which makes me think that the connection string is wrong. Thank you for your help |
Beta Was this translation helpful? Give feedback.
-
If you stick with this design it seems that you need to learn how to do Http Post. Just google the topic. |
Beta Was this translation helpful? Give feedback.
You don't need to store the data at all: just have a look at the examples-webserver.
If you are interested in communcation the examples are in examples-communication