Quest 2 – Microphone.IsRecording == true but Microphone.GetPosition stays 0
Device: Meta Quest 2
OS: 81.0.0.1083.403
Unity: 6000.0.43f (Android, IL2CPP)
API: UnityEngine.Microphone
Use-case: Starting the microphone & checking if there is some data coming out of it
Hi everyone,
I have experienced a very weird bug on my Quest 2 app recently. I basically have a screen that checks that the mic is on when a user starts my application, as my app needs a microphone, it's to prevent users from starting it while their mic is muted and they can't go through the app. And recently I have had reports from users telling me that their mic is not muted & the app has the correct permissions but they still see that screen.
The fix for now that I have made is that I added that when the app is paused with `OnApplicationPause`, that I stop the microphone & then when the app is unpaused, I restart it. And this works.
Interestingly, restarting the app when they see that screen, without puting the headset to sleep & waking up again (just with a short tap on the quest power button) is NOT fixing the issue, it needs to be put to sleep. And that is where I start getting quite confusing and I am asking for some help of people who know more than I do.
And the very very annoying thing about this bug is that it is super inconsistent, sometimes I have it 5 times in a row. And sometimes I don't have it when starting my app 30 times in a row. I have the feeling that it happens more often when I have just switched on the headset and start the app right after, but this might just have been a coincidence. I don't have a stable way to reproduce that error, it's just happening sometimes.
This is what I have checked:
- Microphone.Start(device, true, ..., 16000) returns a non-null AudioClip.
- Microphone.IsRecording(device) returns true.
- But Microphone.GetPosition(device) stays at 0 forever – I poll it every frame for >5 seconds.
- No exceptions. The clip exists, but no samples are ever written; my loudness stays at 0.
Does anybody have any hint about where I can look at? I am pretty stuck right now.
This are my logs from my quest
12:19:10.123 Unity I <b><color=purple>RECOGNISSIMO Start Mic Starting</color></b>
12:19:10.123 Unity I InitMic: recording=True pos=0 device=''12:19:10.123 AAudio I AAudioStreamBuilder_openStream() called ----------------------------
12:19:10.123 AAudio I AudioStreamBuilder: rate = 16000, channels = 1, format = 5, dir = INPUT
12:19:10.123 AAudio D AudioStreamBuilder: build() enable (auto) aaudio input mmap via gk
12:19:10.123 AAudio D AudioStreamBuilder: build() package com.wondder.GivingFeedback denied mmap12:19:10.146 Unity I InitMic: recording=True pos=0 device=''
12:19:10.159 Unity I InitMic: recording=True pos=0 device=''
12:19:10.267 Unity I InitMic: recording=True pos=0 device=''12:19:10.268 EffectHAL W Effect ... SET_CONFIG returned status: Invalid argument
12:19:10.273 EffectHAL W Effect ... SET_CONFIG returned status: Invalid argument
12:19:10.296 AudioFlinger W createRecordTrack_l(): mismatch between requested flags (...) and input flags (...)
12:19:10.324 audio_hw_primary D adev_close_input_stream: ...
12:19:10.324 audio_hw_primary D io_streams_map_remove: Removed stream with handle ...
12:19:10.324 audio_hw_primary D in_standby: usecase(30: low-latency-record)
This is my code simplified
using UnityEngine;
using System.Collections;
public class MicInitTest : MonoBehaviour
{
public string DeviceName = null;
public int SampleRate = 16000;
public float TimeSensitivity = 0.25f;
AudioClip _clip;
bool _micInitializing;
bool _microphoneInitialized;
IEnumerator Start()
{
yield return InitializeMicrophone();
}
IEnumerator InitializeMicrophone()
{
if (_micInitializing || _microphoneInitialized)
yield break;
_micInitializing = true;
// 1) Stop any previous recording
if (Microphone.IsRecording(DeviceName))
{
Debug.Log("MIC was already recording, calling End()");
Microphone.End(DeviceName);
float endStart = Time.realtimeSinceStartup;
const float endTimeout = 3f;
while (Microphone.IsRecording(DeviceName) &&
Time.realtimeSinceStartup - endStart < endTimeout)
{
Debug.Log("Waiting for mic to end recording…");
yield return null;
}
}
// 2) Start recording
int maxRecordingTime = Mathf.Max(2, (int)(TimeSensitivity + 1f));
_clip = Microphone.Start(DeviceName, true, maxRecordingTime, SampleRate);
Debug.Log("<b><color=purple>RECOGNISSIMO Start Mic Starting</color></b>");
if (_clip == null)
{
Debug.LogError("Microphone.Start returned null clip");
_micInitializing = false;
yield break;
}
// 3) Wait until GetPosition > 0 (or timeout). On good runs this happens
// after a few frames, on bad runs it never happens.
float startTime = Time.realtimeSinceStartup;
const float timeoutSeconds = 5f;
int nbOfTry = 0;
const int maxNbOfTry = 1;
while (true)
{
int pos = Microphone.GetPosition(DeviceName);
bool recording = Microphone.IsRecording(DeviceName);
Debug.Log($"InitMic: recording={recording} pos={pos} device='{DeviceName}'");
if (pos > 0)
break;
if (!recording && Time.realtimeSinceStartup - startTime > timeoutSeconds)
{
Debug.LogError("Microphone is not recording, aborting init");
_micInitializing = false;
yield break;
}
if (Time.realtimeSinceStartup - startTime > timeoutSeconds)
{
if (nbOfTry >= maxNbOfTry)
{
Debug.LogError("Timeout waiting for mic position > 0");
_micInitializing = false;
yield break;
}
nbOfTry++;
yield return HardResetAudio();
// Retry once
_clip = Microphone.Start(DeviceName, true, maxRecordingTime, SampleRate);
startTime = Time.realtimeSinceStartup;
}
yield return null;
}
_microphoneInitialized = true;
_micInitializing = false;
Debug.Log("<b><color=green>Microphone initialized successfully.</color></b>");
}
IEnumerator HardResetAudio()
{
Debug.Log("Hard reset audio and mic (StopAudioOutput/StartAudioOutput)");
AudioSettings.Mobile.StopAudioOutput();
yield return new WaitForEndOfFrame();
AudioSettings.Mobile.StartAudioOutput();
yield return new WaitForEndOfFrame();
}
}