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.  

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.

Screenshot of the webRTC troubleshooter screen in the Android emulator.
The WebRTC troubleshooter running in the Android emulator.

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. If you're interested in getting in on the fun, read our full demo writeup. Checkout the Android source code for both Java and Kotlin, and let us know what you think!