View All Posts
Want to keep up to date with the latest posts and videos? Subscribe to the newsletter
HELP SUPPORT MY WORK: If you're feeling flush then please stop by Patreon Or you can make a one off donation via ko-fi

Learn how to create a wireless microphone using ESP32 and Bluetooth Hands-Free Profile (HFP). Although the audio quality isn't perfect, the project pushes the ESP32's capabilities to their limits, resulting in an effective wireless speakerphone.

Related Content

[0:00] Let’s make a Bluetooth microphone I said to myself, how hard can it be?
[0:03] We’ve already made a bluetooth speaker so making a Bluetooth microphone should be easy.
[0:08] So, What are we doing in this video?
[0:09] First off we’ll discuss why this seemingly trivial thing is not trivial
[0:14] spoiler alert, you can’t simply create an A2DP Bluetooth source and expect it to work as a microphone.
[0:20] We’ll work around this limitation by using the Bluetooth Hands-Free Profile
[0:23] another spoiler alert - this is very cool, but honestly it’s not great.
[0:28] Finally we’ll actually make a working wireless microphone
[0:31] And then, at the end of the video there a nice little bonus feature that I think you’ll like.
[0:35] We’ll get started after this quick word about the channel sponsor PCBWay.
[0:39] PCBWay have been supporting the channel for a while, they offer PCB Production, CNC and 3D Printing,

[0:46] PCB Assembly and much much more.
[0:48] I’ve made quite a few boards with them and they are great to work with. You can find a link to their details in the description.
[0:53] So, what’s the issue with the A2DP Bluetooth profile?
[0:57] We used this to create our Bluetooth speaker in a previous video.

[1:00] And it was trivially easy and required just a few lines of code with some helper libraries.
[1:05] What’s more you can also output audio using the A2DP Bluetooth profile,

[1:09] this also just requires a few lines of code.
[1:11] The problem is, my PC and most probably your PC is not a Bluetooth speaker - so it’s not

[1:17] going to pick up our A2DP source as a potential input it can use.

[1:21] It’s simply not the way the standards have been defined and implemented.
[1:24] This leads me to my nice trouble shooting diagram for future projects.
[1:28] Am I using bluetooth?
[1:29] If the answer is no - it’s going to be great
[1:31] If the answer is yes - you’re in for a world of consfusion
[1:34] Now, I can hear you all right now saying, what’s wrong with this guy - you can definitely have

[1:38] Bluetooth microphones - I’ve got a bluetooth headset and it works with my phone and my laptop.
[1:44] Enter the Bluetooth Hands-Free Profile or HFP. This is used by hands-free kits to

[1:49] communicate with mobile phones and now that we spend all day on Zoom calls, computers.
[1:53] The Hands-Free Profile defines two roles,

[1:56] an Audio Gateway known as AG and a Hands-Free unit known as HF. We’re going to turn our ESP32

[2:03] into a hands free unit so that it can connect to our computer which will quite happily act

[2:07] as an audio gateway. This will then let us send audio data from the microphone to the computer.
[2:12] There are several issues with this.
[2:15] The first is a fundamental issue with the codecs used.

[2:18] These are limited to 8KHz or 16KHz sampling rates.
[2:23] As we know from our previous videos on audio input on the ESP32 8KHz is just about good

[2:29] enough for speach, but it’s not great. Unfortunately in my experiments with the

[2:33] ESP32 and my computer I’ve not managed to get them to agree to the 16KHz sampling rate. So I’m

[2:40] stuck with 8KHz. My phone will however connect at 16KHz so will get slightly better quality.
[2:46] The second issue is just getting this to work. I tried running the examples in the ESP-IDF

[2:51] and hit a number of problems. The main one being that it was unable to stay connected

[2:56] for more than a few seconds. The code is also pretty hard to understand.
[2:59] I have however managed to find an alternative bluetooth stack that seems to be stable

[3:04] and has sample code that I was able to understand.
[3:06] The sample code was missing the parts required to get the microphone working,

[3:10] but I’ve managed to hack together enough code to get it to work.
[3:13] This is very much alpha code and support for this

[3:15] kind of thing seems to be pretty rough - hopefully it will improve over time.
[3:20] I’ve run the code up on my ESP32 and we are now able to connect the ESP32

[3:24] with my computer and it shows up as an audio input and output device.
[3:28] It’s pretty cool - the volume controls work

[3:30] and send messages to the ESP32 and we can see it sending data in the logs.
[3:35] And, as the computer recognises it as an audio input we can record directly from it.
[3:40] I’ve recorded a few seconds of me speaking and some music. Let’s have a listen.
[4:03] It’s definitely understandable - but it’s not great. We can see

[4:07] if we prot a spectrum of the audio it’s cut off at 4KHz so it sounds pretty muffled.

[4:12] This seems to be a limitation of my computer as it does the same

[4:15] thing with my expensive noise cancelling headpohones which also cut off at 4KHz.
[4:20] So my computer won’t do the 16kHz sampling rate.
[4:23] So, for me this is not really usable as a wireless mike.
[4:26] Having said that we can do some fun things. I’ve got it paired with my phone

[4:31] and we can make phone calls and play DTMF tones.
[4:34] We can also call this test number and get it to record the audio and play it back to us. So we can see what the quality is like.
[5:31] We’ve managed to make a hands free speakerphone - I’m not sure

[5:34] I’d actually want to use it for anything serious.
[5:35] And it’s not really what I set out to do.
[5:38] I really want a wireless microphone.
[5:41] Let’s have a look at alternatives. If we look at proper wireless microphones that connect to PCs,

[5:46] we see they normally transmit the audio data over UHF and use a USB

[5:50] dongle to act as USB microphone to get the data into the computer.
[5:54] We’re not going to do that, but we do have an ESP32 which has WiFi.

[5:58] Why not use WiFi to send our audio.
[6:00] We did something similar to this with the Walky-Talky project where

[6:03] we used UDP packets to stream our audio data.
[6:06] Let’s try it out using TCP sockets. I’ve set up some very simple code that runs a TCP server on

[6:12] port 9090. It then listens for new connections and streams audio data out to anyone who is listening.
[6:18] I’ve also got a very simple Python script that will connect to our sever

[6:22] and playback the audio data as it is coming through.
[6:25] I’ve also set up a virtual audio device using some free software called Blackhole. This acts as a

[6:30] virtual audio device that will route audio from an output device to an input device. This means that

[6:36] we can play audio data to the Blackhole output device and then other software can record the audio

[6:42] from the Blackhole input device. There is a similar piece of software for windows called VB-Cable.
[6:47] Let’s give it a quick go.
[6:48] I’ve got the software up and running on my ESP32 waiting for connections.
[6:52] And I’ve started up the python script to receive audio and play it to the Blackhole input device.
[6:58] I can now just record the audio in Audacity from the Blackhole device.
[7:30] It works pretty well!
[7:31] Let’s have a listen to what we recorded.
[7:56] Quality is significantly better and if we look at the spectrum

[7:59] we now get the full audio bandwidth of around 20KHz.
[8:02] We’ve had to jump through a few hoops, but we have a working wireless microphone.
[8:07] I promised you a little bonus - so here it is.
[8:09] I thought it might be good to do this without needing a python program,

[8:13] so I’ve embedded a simple HTML audio player that let’s you use your browser to play the audio.
[8:18] This can be served directly from the ESP32 - just don’t forget to follow

[8:22] the instructions to upload the SPIFFS file system.
[8:24] This will receive audio directly from the ESP32 over a websocket

[8:28] and play it back over the default output device.
[8:31] There is a slight limitation with selecting audio devices when you are not serving files over HTTPS or localhost
[8:37] There’s a couple of things you can do to work around this. I use a handy plugin for VSCode

[8:42] called Live Server. This lets you serve HTML files from localhost which gets around this restriction.
[8:47] And you can now pick the audio output device you want to use. This great if you don’t want to use the standard output device and get massive feedback.
[8:55] Or, you can add an exception to chrome for the URL we are getting from the ESP32 that

[8:58] will make it treat it as a secure site even though it’s not coming over HTTPS.
[9:03] Just go to chrome://flags and enter an exception for “Insecure origins treated as secure”.
[9:10] With that done we can now route the audio to the

[9:12] virtual audio device and record the audio that is coming from the ESP32.
[9:16] That works pretty well and we can do a similar thing to before where we record the audio using Audacity.
[9:21] We’ve also got a nice little audio visualiser.
[9:24] All in all, quite a nice successful project. Thanks for watching and I’ll see you next time!

HELP SUPPORT MY WORK: If you're feeling flush then please stop by Patreon Or you can make a one off donation via ko-fi
Want to keep up to date with the latest posts and videos? Subscribe to the newsletter
Blog Logo

Chris Greening

> Image


A collection of slightly mad projects, instructive/educational videos, and generally interesting stuff. Building projects around the Arduino and ESP32 platforms - we'll be exploring AI, Computer Vision, Audio, 3D Printing - it may get a bit eclectic...

View All Posts