Let's make a Bluetooth microphone I said to myself, how hard can it be?
We've already made a bluetooth speaker so making a Bluetooth microphone should be easy.
So, What are we doing in this video?
First off we'll discuss why this seemingly trivial thing is not trivial
spoiler alert, you can't simply create an A2DP Bluetooth source and expect it to work as a microphone.
We'll work around this limitation by using the Bluetooth Hands-Free Profile
another spoiler alert - this is very cool, but honestly it's not great.
Finally we'll actually make a working wireless microphone
And then, at the end of the video there a nice little bonus feature that I think you'll like.
We'll get started after this quick word about the channel sponsor PCBWay.
PCBWay have been supporting the channel for a while, they offer PCB Production, CNC and 3D Printing,
PCB Assembly and much much more.
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.
So, what's the issue with the A2DP Bluetooth profile?
We used this to create our Bluetooth speaker in a previous video.
And it was trivially easy and required just a few lines of code with some helper libraries.
What's more you can also output audio using the A2DP Bluetooth profile,
this also just requires a few lines of code.
The problem is, my PC and most probably your PC is not a Bluetooth speaker - so it's not
going to pick up our A2DP source as a potential input it can use.
It's simply not the way the standards have been defined and implemented.
This leads me to my nice trouble shooting diagram for future projects.
Am I using bluetooth?
If the answer is no - it's going to be great
If the answer is yes - you're in for a world of consfusion
Now, I can hear you all right now saying, what's wrong with this guy - you can definitely have
Bluetooth microphones - I've got a bluetooth headset and it works with my phone and my laptop.
Enter the Bluetooth Hands-Free Profile or HFP. This is used by hands-free kits to
communicate with mobile phones and now that we spend all day on Zoom calls, computers.
The Hands-Free Profile defines two roles,
an Audio Gateway known as AG and a Hands-Free unit known as HF. We're going to turn our ESP32
into a hands free unit so that it can connect to our computer which will quite happily act
as an audio gateway. This will then let us send audio data from the microphone to the computer.
There are several issues with this.
The first is a fundamental issue with the codecs used.
These are limited to 8KHz or 16KHz sampling rates.
As we know from our previous videos on audio input on the ESP32 8KHz is just about good
enough for speach, but it's not great. Unfortunately in my experiments with the
ESP32 and my computer I've not managed to get them to agree to the 16KHz sampling rate. So I'm
stuck with 8KHz. My phone will however connect at 16KHz so will get slightly better quality.
The second issue is just getting this to work. I tried running the examples in the ESP-IDF
and hit a number of problems. The main one being that it was unable to stay connected
for more than a few seconds. The code is also pretty hard to understand.
I have however managed to find an alternative bluetooth stack that seems to be stable
and has sample code that I was able to understand.
The sample code was missing the parts required to get the microphone working,
but I've managed to hack together enough code to get it to work.
This is very much alpha code and support for this
kind of thing seems to be pretty rough - hopefully it will improve over time.
I've run the code up on my ESP32 and we are now able to connect the ESP32
with my computer and it shows up as an audio input and output device.
It's pretty cool - the volume controls work
and send messages to the ESP32 and we can see it sending data in the logs.
And, as the computer recognises it as an audio input we can record directly from it.
I've recorded a few seconds of me speaking and some music. Let's have a listen.
It's definitely understandable - but it's not great. We can see
if we prot a spectrum of the audio it's cut off at 4KHz so it sounds pretty muffled.
This seems to be a limitation of my computer as it does the same
thing with my expensive noise cancelling headpohones which also cut off at 4KHz.
So my computer won't do the 16kHz sampling rate.
So, for me this is not really usable as a wireless mike.
Having said that we can do some fun things. I've got it paired with my phone
and we can make phone calls and play DTMF tones.
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.
We've managed to make a hands free speakerphone - I'm not sure
I'd actually want to use it for anything serious.
And it's not really what I set out to do.
I really want a wireless microphone.
Let's have a look at alternatives. If we look at proper wireless microphones that connect to PCs,
we see they normally transmit the audio data over UHF and use a USB
dongle to act as USB microphone to get the data into the computer.
We're not going to do that, but we do have an ESP32 which has WiFi.
Why not use WiFi to send our audio.
We did something similar to this with the Walky-Talky project where
we used UDP packets to stream our audio data.
Let's try it out using TCP sockets. I've set up some very simple code that runs a TCP server on
port 9090. It then listens for new connections and streams audio data out to anyone who is listening.
I've also got a very simple Python script that will connect to our sever
and playback the audio data as it is coming through.
I've also set up a virtual audio device using some free software called Blackhole. This acts as a
virtual audio device that will route audio from an output device to an input device. This means that
we can play audio data to the Blackhole output device and then other software can record the audio
from the Blackhole input device. There is a similar piece of software for windows called VB-Cable.
Let's give it a quick go.
I've got the software up and running on my ESP32 waiting for connections.
And I've started up the python script to receive audio and play it to the Blackhole input device.
I can now just record the audio in Audacity from the Blackhole device.
It works pretty well!
Let's have a listen to what we recorded.
Quality is significantly better and if we look at the spectrum
we now get the full audio bandwidth of around 20KHz.
We've had to jump through a few hoops, but we have a working wireless microphone.
I promised you a little bonus - so here it is.
I thought it might be good to do this without needing a python program,
so I've embedded a simple HTML audio player that let's you use your browser to play the audio.
This can be served directly from the ESP32 - just don't forget to follow
the instructions to upload the SPIFFS file system.
This will receive audio directly from the ESP32 over a websocket
and play it back over the default output device.
There is a slight limitation with selecting audio devices when you are not serving files over HTTPS or localhost
There's a couple of things you can do to work around this. I use a handy plugin for VSCode
called Live Server. This lets you serve HTML files from localhost which gets around this restriction.
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.
Or, you can add an exception to chrome for the URL we are getting from the ESP32 that
will make it treat it as a secure site even though it's not coming over HTTPS.
Just go to chrome://flags and enter an exception for "Insecure origins treated as secure".
With that done we can now route the audio to the
virtual audio device and record the audio that is coming from the ESP32.
That works pretty well and we can do a similar thing to before where we record the audio using Audacity.
We've also got a nice little audio visualiser.
All in all, quite a nice successful project. Thanks for watching and I'll see you next time!