Hey everyone,
I’m running into an issue with a Unity project and could really use some advice.
We’re developing an Android app where kids can chat with an AI using voice input. The problem is, if another app is using the microphone in the background, our app can’t pick up any audio, so users think the chat feature is broken.
On iOS, we can easily check if the microphone is in use with Microphone.IsRecording and Microphone.devices. But on Android, we can’t seem to get it working the same way. We even tried writing a native .aar plugin but no luck there.
Ideally, we want to show a notification if another app is using the mic so users know what’s going on. Has anyone managed to detect if the mic is occupied by another app on Android? Any tips or suggestions would be super helpful!
Thanks in advance!
I’m sorry to hear about that!
I feel like using a .aar might have given you that info when requesting audio focus, by returning AUDIOFOCUS_REQUEST_FAILED or else. (AudioFocusRequest | Android Developers)
Otherwise, you could make a script testing the microphone by capturing something like one second of sound, and if that is completely empty or if Microphone.IsRecording(...) returns false, then display a warning to the user?
Or maybe I’m not understanding clearly what’s going on… let me know!
We’ve tried both of your proposals. First trying to capture a momentarily microphone resulted with fail in our tests, since some mobile devices did not capture any sound if we simply did not speak and misled our app. So we’ve decided not to go with that solution.
When it comes to .aar here I would like to share you my module. This module did not help also. It always returned that mic was available. Here I will be sharing our module. Maybe you can help us with another proposal or an idea.
package com.ayasis.miccheck;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.util.Log;
public class MicrophoneHelper {
private static final String TAG = "MicrophoneHelper";
private AudioFocusRequest audioFocusRequest;
private AudioManager audioManager;
public MicrophoneHelper(Context context) {
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
public boolean isMicrophoneAvailable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build();
audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.setAudioAttributes(audioAttributes)
.setOnAudioFocusChangeListener(focusChange -> {})
.build();
int result = audioManager.requestAudioFocus(audioFocusRequest);
if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.d(TAG, "Microphone is in use by another app.");
return false;
}
} else {
// For devices below Android 8.0, fallback to the legacy method
int result = audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.d(TAG, "Microphone is in use by another app (legacy check).");
return false;
}
}
return true;
}
public void releaseAudioFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && audioFocusRequest != null) {
audioManager.abandonAudioFocusRequest(audioFocusRequest);
} else {
audioManager.abandonAudioFocus(null);
}
}
}
Ok, I understand why the first idea is not a great fit in your case.
Then the native plugin code you shared is exactly what I was going for. The only nitpick I’d point out in it is the line 32 result == AudioManager.AUDIOFOCUS_REQUEST_FAILED that I would have replaced by result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED, like it is actually written in the else clause, but I doubt that it would fix it…
For further troubleshooting I would recommend:
- Try to get a sense of how frequent this issue is across android versions and phone models. I’m painfully aware how tedious this process is, but if you have a few phones at hand, I would test with all of them at least to confirm the scope of the issue
- Validating permissions in the android manifest, and maybe make a runtime check for that through a native plugin. I believe an audio device can show up as “focused” even if capture is not allowed.
- Implementing a focus change callback might allow you to track better what’s currently grabbing the microphone (AudioManager.OnAudioFocusChangeListener | Android Developers)
- I know we already discarded recording a small sample of audio, but maybe doing a native recording would be better. I can’t tell if there is any filtering or noise gate applied on the signal received at that level, but I figure that even if users don’t speak, the microphone should detect non zero values. (AudioRecord | Android Developers)
Thank you for your answer, nowadays I am on a different task, will definitely let you know in a few work days about our trials.