Oculus Quest Microphone with Vivox

I’ve been searching for a good VOIP solution for the Oculus Quest. I wanted something that would work cross-platform and that could scale well. UE4 had a Vivox implementation built-in so I decided to check it out.

My initial impression of the Vivox implementation was soured a bit by the outdated UE4 documentation (which I fixed). But I pressed on until I had the implementation working in windows. When I went to test on the Oculus, voice didn’t work and this suspicious error message showed up in the logs:

vxa_capture_device_open failed: status=3

The Solution

Despite this being my fault, I would like to advise that “3” is an incredibly poor status indicator. This indicator can only be decoded by the few people who have access to the source code of the precompiled library. Better would be any description or self-documenting ENUM name like E_NO_PERMISSION.

Oculus Quest as of September 2019 is on Android API 25. In API 23, Google made a critical change to the way that permissions work. It used to be that listing all the permissions you needed in DefaultEngine.ini (or the Android manifest) was enough. Not Anymore!

It is now possible for a user to revoke permissions at any time, so a more robust solution is now required:

  1. Add all permissions that you will ever need into DefaultEngine.ini
  2. Explicitly request the permission(s) before trying to use them


Add the Permission

Let’s say you want to use the microphone. First, add the permission to DefaultEngine.ini:


Add The Module

UE4 has a helper plugin called AndroidPermission that can be used to request permissions. For Blueprint projects, see this reference for the 2 blueprint calls you’ll need. C++ folks will need to make the following change to their build file.

In your project’s *.Build.cs file, add AndroidPermission to PublicDependencyModuleNames:

   new string[] {

Request the Permission

Finally, request permission(s). In the example below, the Login function will utilize the microphone.

#include "AndroidPermissionFunctionLibrary.h"
#include "AndroidPermissionCallbackProxy.h"
void SomeFuncWhereYouNeedPermissions()
// If we don't have the permission
if (!UAndroidPermissionFunctionLibrary::CheckPermission(TEXT("android.permission.RECORD_AUDIO")))
// Build an array of permissions to request
TArray<FString> Perms;
if (UAndroidPermissionCallbackProxy* Callback = UAndroidPermissionFunctionLibrary::AcquirePermissions(Perms))
// Bind to the callback so we know when permissions have been granted
Callback->OnPermissionsGrantedDelegate.BindLambda([this](const TArray<FString>& Permissions, const TArray<bool>& GrantResults)
// If you requested more than 1 permission, then you should check the Permissions array to see if
// your specific permission got granted. In this case, we only requested a single permission.
if (GrantResults.Num() > 0)
if (GrantResults[0])
// We got RECORD_AUDIO permission, now we can use the mic
// We already had permissions so continue using the mic
UE_LOG(LogTemp, Warning, TEXT("Already had RECORD_AUDIO permissions"));
#else // Not Android
view raw example.cpp hosted with ❤ by GitHub


Leave a Reply