When we built our audio-only demo Party Line, we knew we wanted to offer multi-platform support from day one. Android support for audio applications has been notoriously limited, so we knew to brace ourselves for some fun new bugs learning opportunities along the way.
We found them fast! When we loaded our gist prototype in a WebView, everything worked on our physical devices, but in the emulator no audio came through. This was awkward for any audio-only app, and especially one that we wanted to work across multiple Android devices and versions.
This post walks through how we debugged this error, in case that could be helpful for troubleshooting similar but different errors. Of course, we’ll also go over our solution (scroll to the bottom if you want to skip ahead!).
Before we dive in, it’s worth noting that we only ran into this problem with Android API level 30; audio worked out of the box when we switched to < 29.
Find the root error
First, we wanted to rule out a mic permissions issue as a potential cause. A few lines in our gist stop local audio from playing to prevent an on-call echo. We commented them out to test if we could hear our own audio.
// don't play the local audio track (echo!)
// if (evt.participant.local) {
// return;
// }
We could hear our local audio with those lines removed, so we eliminated mic issues as the culprit.
Next, we loaded the webRTC troubleshooter in the emulator WebView.
We could join the meeting room, our local audio still worked, and the troubleshooter got stuck at the Udp test. This pointed us to a networking issue, and, since we could join the room, it also suggested a socket layer problem. We now knew what to look for in Logcat.
Logcat dumps a lot of information. We went through many rounds of quitting and relaunching to spot the error message we needed right after the popup for mic permissions:
2021-02-13 23:16:11.993 19189-19275/com.daily.audioonly E/chromium: [ERROR:address_tracker_linux.cc(245)] Could not send NETLINK request: Permission denied (13)
2021-02-13 23:16:11.987 19189-19189/com.daily.audioonly W/ThreadPoolForeg: type=1400 audit(0.0:457): avc: denied { nlmsg_readpriv } for scontext=u:r:untrusted_app:s0:c156,c256,c512,c768 tcontext=u:r:untrusted_app:s0:c156,c256,c512,c768 tclass=netlink_route_socket permissive=0 b/155595000 app=com.daily.audioonly
The Android docs helped us parse this error and determine that SELinux was preventing the emulator from communicating with the socket. It wasn’t granting those nlmsg_readpriv
so the emulator could listen to audio.
Run audit2allow
to grant read privileges
Continuing to read the docs, we found the audit2allow
command that converts denials into corresponding policy statements. All we had to do was run:
adb pull /sys/fs/selinux/policy
adb logcat -b all -d | audit2allow -p policy
And with that, we had audio in our emulator!
From there, we had a lot of fun building out the full Party Line codebase (we walk through the whole thing on our blog. Checkout the Android source code for both Java and Kotlin, and keep us posted on how it goes!
Top comments (0)