Simple ESP8266 Internet Radio Player/Streamer

My FM Radio Channel Selection is broken and the station that I am listening to has a low broadcast power, so there are a lot of interference, they have an internet stream but I do not have a device that can be powered 24/7 just only to stream.
I have a NodeMCU 1.0 devkit and it does not have any audio output, but the specifications says it can output I2S (I2S is not equal to I2C), I found some tutorials on how to connect an I2S Codec Device like the VS1053 or ES9053* but they cost a lot.
Luckily, I found the code of Sprite_tm on Github and it says that you can output a 5-bit PWM Signal from an ESP8266 but the problem is the lack of RAM. His post suggest using an SPI RAM but it cost a lot for me, so I just tried to compile and flash
the code.

$ git clone
$ cd ESP8266_MP3_DECODER/mp3

The makefile has some entries about xt-xcc which is not available for me but I have the xtensia binaries, compiled using the esp_open_sdk from pfalcon.
After editing the makefile, I just ran make then I flashed the firmware using the with the baudrate of 115200.

For the hardware, I used a BC548 NPN Transistor and a 1W 8 ohm speaker. You should use a 2N3904 NPN, since it can output maximum 1A and deliver about 2.3W to the speakers.
The BC548 can only output 100 mA, if you connect a 3W speaker the BC548 transistor will get hot and be destroyed. I also tried an N-channel MOSFET IRF3205 to power the speaker.

The connections are as follows:

BC548 Pin 1 (Collector) to Speaker Minus
BC548 Pin 2 (Base) to RX pin of NodeMCU
BC548 Pin 3 (Emitter) to GND of NodeMCU
Speaker Positive to Vin of NodeMCU (5V)

The stream gets interrupted because of the low RAM or heap memory of the ESP8266 or just my Slow Internet connection but I’ve
narrowed down that it is because of a buffer underflow, so I added a code to restart the ESP8266 if the system is stuck on
the buf uflow for a specified amount of seconds. I have also tried to add some other timer but the ESP8266 just resets with
Exception 28 or 29, and a watchdog external reset code 2, this could be the lack of heap memory or just a bug in my code.

If you want to see the demo and the schematic, you can watch my video on PeerTube or Youtube,
here are the links:

Except where otherwise noted, this work is licensed under Creative Commons Attribution-ShareAlike 4.0 International License (
I hope that this post is useful to you, if you liked this post you may support me via Patreon or liberapay. Thank you for your support.