BirdFeeder turns cheap, locked, or other e-waste Android phones (FRP-locked, carrier-locked, bootloader-locked — the ones nobody wants) into single-purpose headless audio appliances that stream to an RTSP server, particularly for consumption by BirdNET-Go for ML bird call identification.
I built this with the intent of deploying Pi Zero W nodes across my property, but I was never able to reduce the noise floor and get audio quality I was happy with, no matter what ADC/USB sound card/shielding combination I tried. I reworked the project to deploy on legacy Android phones instead — and the result has genuinely impressed me, both in audio quality and reliability, so I figured it was worth sharing.
NOTE: This project is fully functional in my environment across multiple devices, and the documentation is admittedly not great. I am working on expanding this repo doc and experimenting with a setup script to run on your host mahcine to eliminate a lot of manual work in the future.
What does it do?
- Automatically launches as a service at boot via Termux:Boot, no manual interaction required.
- Runs fully headless via Termux.
- Captures audio via PulseAudio's module-sles-source and publishes it live to an RTSP server using ffmpeg
- Automatically recovers from crashes, network drops, rtsp server reboots, etc.
- Waits for connectivity to RTSP server before initializing stream.
- Configurable options for stream quality, gain, bitrate (if using a lossy codec), RTSP destination, etc.
For a deep dive on the audio processing pipeline (capture → PulseAudio → ffmpeg → codec → RTSP) and the known constraints of running non-root on locked/cheap hardware, see the Technical Details wiki page.
This tool is designed around the cheapest phones you can find on eBay — FRP-locked, carrier-locked, bootloader-locked, cracked, whatever. If it boots and has a working WiFi radio and microphone, it's a candidate. See the Successfully Deployed Devices section for hardware I've successfully deployed with -- but I've found that the process is pretty similar across devices, with a few nuances for MDM and FRP locks (details provided where I can).
- Successfully Deployed Devices
- Debloating Tools In Progress, likely moving to Wiki.
- MDM/FRP Locks In Progress, likely moving to Wiki.
- Device Preparation
- BirdFeeder Setup Process
- Kiosk Mode (Optional) In Testing, documentation to follow.
- Acknowledgements
Android 12:
- Pixel 3 XL with default Google Fi ROM. (mdm lock bypassed)
- Moto G Stylus 2022 (Non-5G) with default Cricket ROM.
- Pixel 2 with default Google Fi ROM. (mdm lock bypassed)
Android 15 Currently Inop:
- Pixel 2 with LineageOS 22.2 ROM. (FRP lock bypassed)
**Issues: **
- OPEN Audio stream is dead silent unless you open the LineageOS Recorder application, and start/stop a recording. RTSP audio spring to life when you do this, and remains functional until a reboot. I am not sure of the mechanism causing this quite yet, Android 15 seems to be locked down a little tighter.
- OPEN Sysinfo is further locked down, cannot pull MAC address so health page is missing this field.
- Resolved Termux:Boot was able to start the streaming script, but SSH was never listening unless you brought Termux to the foreground. I modified the start-birdfeeder.sh with one line so that the background processes (specifically, sshd) would run, else it required first bringing Termux into the foreground. That line was "$PREFIX/bin/runsvdir $PREFIX/var/service > /dev/null 2>&1 &". This is in the default repo file now, should not have negative impact on older devices.
Other:
- Raspberry Pi Zero 2 W (deprecated, script in repo for reference)
- Evaluate condition & functionality of phone. Note MDM or FRP locks.
- Perform factory reset and debloat as needed. Currently using Universal Android Debloater Next Gen for this.
- Bypass FRP / Remove MDM as needed. (see MDM/FRP Locks)
- Complete OOBE, skipping all setup including cellular, network, PIN, etc.
The verbiage varies a bit from device to device, but these are my baseline configurations that I configure on the phone by hand.
Settings -> About Phone ->
- Device Name: Configure as you'd like.
- Build number: Tap until developer mode is enabled.
Settings -> Network and Internet
- About phone
- Private DNS Mode: Off
- Internet: Connect to your SSID, set to treat as unmetered, choose to use device MAC (not randomized), enable "send device name".
- Internet: Network Preferences: Turn on Wi-Fi Automatically enabled, Notify for public networks disabled.
- Airplane Mode: On
- Wi-Fi: On
Settings -> System -> Developer Options
- USB debugging: On
- Mobile data always active: Off
Then, connect to the phone via ADB (USB or network) and run the following (this is assuming you have downloaded these APKs already:
adb install com.termux_1022.apk
adb install com.termux.api_1002.apk
adb install com.termux.boot_1000.apk
adb shell pm grant com.termux android.permission.RECORD_AUDIO
adb shell pm grant com.termux.api android.permission.ACCESS_FINE_LOCATION
adb shell pm grant com.termux.api android.permission.ACCESS_COARSE_LOCATION
adb shell "/system/bin/device_config set_sync_disabled_for_tests persistent"
adb shell "/system/bin/device_config put activity_manager max_phantom_processes 2147483647"
adb shell "settings put global settings_enable_monitor_phantom_procs false"
Manually, on the device again:
- Open each Termux app, grant any permissions requested, click the buttons for disabling battery optimization and granting display over other apps in Termux:Boot.
- Settings -> Apps -> Termux:API -> Modify System Settings -> Allowed
- Run the following to start our termux service and setup SSH:
pkg update && pkg upgrade
pkg install termux-services openssh
sv-enable sshd
passwd
- The "passwd" command is to set your SSH login password. You'll need to exit and restart Termux afterward. From there, we can connect to the device over SSH on port 8022 (binds to 8022 instead of 22 since we're not running with root priv on the phones).
ssh 1.2.3.4 -p 8022
pkg install ffmpeg pulseaudio lighttpd iproute2 termux-api
Next, we'll make the startup and streaming script files, I just copy paste the contents from this repo into new files - SCP works too if you prefer:
mkdir ~/.termux/boot/
nano ~/.termux/boot/start-birdfeeder.sh
chmod +x ~/.termux/boot/start-birdfeeder.sh
nano ~/birdfeeder.sh
chmod +x ~/birdfeeder.sh
Open the lighttpd configuration file:
nano $PREFIX/etc/lighttpd/lighttpd.conf
Add these three lines to the bottom of it and save:
server.document-root = "/data/data/com.termux/files/home/www"
server.port = 8080
index-file.names = ( "index.html" )
My better half often moves these phones around to different physical feeder areas, and the current solution does not provide a simple way for her to check the device's status. The solution I decided on was to sideload WebViewKiosk_v0.26.18.apk, set the homepage to http://localhost:8080, set WebViewKiosk as the phone's launcher, and enable lock. Pressing the power button will now display a live copy of the health webpage. More later..
- BirdNET-Go — the whole reason this project exists
- Termux / Termux:Boot / Termux:API
- MediaMTX — RTSP server used in my environment
- LineageOS — used wherever bootlocker unlocking permits
- FFmpeg / PulseAudio / lighttpd