ESP32 Voice Streamer

Use the ESP32 and the Adafruit Electret Microphone Amplifier Board to stream your voice over WiFi to your Raspberry Pi.

Story

There are many things that do audio streaming nowadays. Smart assistants like Alexa and Google Home are great examples. This got me thinking about trying something with tone too. I decided to build an electret microphone and an amplifier using an operational amplifier. I connected it to an ESP8266 developer board. While the program worked, it sometimes had pauses while playing the audio in real-time. I tried using interrupts, but they didnā€™t solve the issue. Additionally, the signal was very noisy. So, I upgraded to an ESP32 board and Adafruitā€™s Electret Microphone Amplifier Board. Making some adjustments to the code, it started working!

Step 1: Building the Circuit

Regrettably, the analog input range on our device is limited to 0-1V. Since our microphone outputs a voltage between 0 and 2.25V, we require a voltage divider to bring it within the acceptable range. The diagram below illustrates the voltage divider setup. Connect the yellow cable directly to the ADC of your ESP32 board. Donā€™t forget to also connect the ground and 5V (Vin) lines to your ESP32. When working with 5V levels and 3.3V logic, take necessary precautions to avoid any potential issues.

When you donā€™t have the resistors you can also use a 10kĪ© potentiometer and set it to 5.6k and 4.4k.

Step 2: Set up the code

Open the Arduino software on your computer. Paste the Arduino code from the CODE section below in the editor. (Donā€™t forget to remove the standard code before!) Now change your WiFi credentials in the following path of the code:

const char* ssid     = "YOUR SSID";
const char* password = "YOUR PASSWORD";

Furthermore, you have to set the IP Address of your Raspberry Pi.

const char* host     = "YOUR SERVER IP ADDRESS"; 

Now you can upload the code to your ESP32 board. To Tools-> Board and select your ESP32 board. Now select the Port at Tools-> Port. Now you click ā€œuploadā€ to upload your Sectch.

Step 3: Get streaming

Configure your Raspberry Pi by connecting to it and verifying that the correct audio output is selected. Access the terminal and enter the command ā€œsudo raspi-configā€. A graphical interface will appear. Navigate to ā€œAdvanced Optionsā€ and select it by pressing enter. Within the submenu, select ā€œAudioā€ and press enter once more. To ensure proper functionality, choose ā€œForce 3.5mm (ā€˜headphoneā€™) jackā€ and confirm. Review the main menu, then select ā€œFinishā€ to complete the setup process.

Now just type in the following command and hit enter:

nc -l 4444 | aplay -r 8000 -f U8

Now plug in your ESP32 module. (Donā€™t forget to connect a speaker or headphones to your Raspberry.) And listen to your stream.

IMPORTANT: first run the command and then connect the ESP32 to power.

Schematics

Code

/* Audio streamer with ESP32 and Adafruit elected microphone board. 
 * Created by Julian Schroeter.
*/
#include <Arduino.h>
#include <WiFi.h>
#include <driver/adc.h>

#define AUDIO_BUFFER_MAX 800

uint8_t audioBuffer[AUDIO_BUFFER_MAX];
uint8_t transmitBuffer[AUDIO_BUFFER_MAX];
uint32_t bufferPointer = 0;

const char* ssid     = "YOUR SSID";
const char* password = "YOUR PASSWORD";
const char* host     = "YOUR SERVER IP ADDRESS";

bool transmitNow = false;

WiFiClient client;

hw_timer_t * timer = NULL; // our timer
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 

void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux); // says that we want to run critical code and don't want to be interrupted
  int adcVal = adc1_get_voltage(ADC1_CHANNEL_0); // reads the ADC
  uint8_t value = map(adcVal, 0 , 4096, 0, 255);  // converts the value to 0..255 (8bit)
  audioBuffer[bufferPointer] = value; // stores the value
  bufferPointer++;
 
  if (bufferPointer == AUDIO_BUFFER_MAX) { // when the buffer is full
    bufferPointer = 0;
    memcpy(transmitBuffer, audioBuffer, AUDIO_BUFFER_MAX); // copy buffer into a second buffer
    transmitNow = true; // sets the value true so we know that we can transmit now
  }
  portEXIT_CRITICAL_ISR(&timerMux); // says that we have run our critical code
}


void setup() {
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("MY IP address: ");
  Serial.println(WiFi.localIP());
  
  adc1_config_width(ADC_WIDTH_12Bit); // configure the analogue to digital converter
  adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db); // connects the ADC 1 with channel 0 (GPIO 36)

  const int port = 4444;
  while (!client.connect(host, port)) {
    Serial.println("connection failed");
    delay(1000);
  }

  Serial.println("connected to server");

  timer = timerBegin(0, 80, true); // 80 Prescaler
  timerAttachInterrupt(timer, &onTimer, true); // binds the handling function to our timer 
  timerAlarmWrite(timer, 125, true);
  timerAlarmEnable(timer);

}

void loop() {
  if (transmitNow) { // checks if the buffer is full
    transmitNow = false;
    client.write((const uint8_t *)audioBuffer, sizeof(audioBuffer)); // sending the buffer to our server
  }
}

Source: ESP32 Voice Streamer


About The Author

Muhammad Bilal

I am highly skilled and motivated individual with a Master's degree in Computer Science. I have extensive experience in technical writing and a deep understanding of SEO practices.

Leave a Comment

Your email address will not be published. Required fields are marked *