Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio input gets muted after a while on android #86428

Open
Tracked by #76797
leoyanis opened this issue Dec 22, 2023 · 3 comments · May be fixed by #92969, #93154 or #93200
Open
Tracked by #76797

Audio input gets muted after a while on android #86428

leoyanis opened this issue Dec 22, 2023 · 3 comments · May be fixed by #92969, #93154 or #93200

Comments

@leoyanis
Copy link

Tested versions

4.1.1,4.2 (all devs and betas), 4.2, 4.2.1
mono and regular, tried them all

System information

MacOS, Sonoma 14, M1 pro -> Problem on Android (tested on 10 - 13)

Issue description

When recording audio with this minimal project, the audio input gets muted for no apparent reason.
This was a problem on many of my projects and i finally made a minimal project to troubleshoot and same issue.
This only happens on Android, but not on my mac.

Record_2023-12-22-11-41-42_8bd7053a4dd190e81637918be72deb46.mp4

In the video above i was talking and making noise, the bar at the top displays the volume.
You will see it drop to 0 permanently after a while, this was not from me stopping but from the app not detecting any audio input anymore.

The audio file is muted from that part on as you'd expect.

I have tried messing around with mix rate, stereo, other random settings, audio focus an threads but with no luck.

I believe there is some issue in the godot backend

Steps to reproduce

Install android build template on the minimal project.
Install on android.
Start recording.
Watch how it just mutes permanently after a while.
The muted thing resets after restarting the audio recorder.

Minimal reproduction project (MRP)

AudioRecord test.zip

@kus04e4ek
Copy link
Contributor

Did some debugging and it looks like the issue is in AudioStreamPlaybackMicrophone::_mix_internal, specifically in the value that is returned.

int AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) {
AudioDriver::get_singleton()->lock();
Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
#ifdef DEBUG_ENABLED
unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
#endif
int mixed_frames = p_frames;
if (playback_delay > input_size) {
for (int i = 0; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0.0f, 0.0f);
}
input_ofs = 0;
} else {
for (int i = 0; i < p_frames; i++) {
if (input_size > input_ofs && (int)input_ofs < buf.size()) {
float l = (buf[input_ofs++] >> 16) / 32768.f;
if ((int)input_ofs >= buf.size()) {
input_ofs = 0;
}
float r = (buf[input_ofs++] >> 16) / 32768.f;
if ((int)input_ofs >= buf.size()) {
input_ofs = 0;
}
p_buffer[i] = AudioFrame(l, r);
} else {
if (mixed_frames == p_frames) {
mixed_frames = i;
}
p_buffer[i] = AudioFrame(0.0f, 0.0f);
}
}
}
#ifdef DEBUG_ENABLED
if (input_ofs > input_position && (int)(input_ofs - input_position) < (p_frames * 2)) {
print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size));
}
#endif
AudioDriver::get_singleton()->unlock();
return mixed_frames;
}

Buffer underrun is happening, which results in not returning p_frames, which results in deleting AudioStreamPlaybackMicrophone instance.
if (mixed_frames != buffer_size) {
// We know we have at least the size of our lookahead buffer for fade-out purposes.
float fadeout_base = 0.94;
float fadeout_coefficient = 1;
static_assert(LOOKAHEAD_BUFFER_SIZE == 64, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE.");
// 0.94 ^ 64 = 0.01906. There might still be a pop but it'll be way better than if we didn't do this.
for (unsigned int idx = mixed_frames; idx < buffer_size; idx++) {
fadeout_coefficient *= fadeout_base;
buf[idx] *= fadeout_coefficient;
}
AudioStreamPlaybackListNode::PlaybackState new_state;
new_state = AudioStreamPlaybackListNode::AWAITING_DELETION;
playback->state.store(new_state);
} else {

Not really sure what the solution would be, but hope that it helps.

@ellenhp
Copy link
Contributor

ellenhp commented Mar 26, 2024

#73162 would almost certainly have fixed this, you can try it as a workaround if you're okay building the engine yourself. It should have no adverse effects, it's just a fix for an oversight on my part in #51296. Juan decided that we should fix this class of bug in the streams though so this will require a contributor to add underrun handling to the microphone audio stream.

@bestvcboy
Copy link

I also encountered the same problem under Android, which is particularly unstable when recording. After recording for a while, I found that:
var indx = AudioServer.GetBusIndex("Record");
float volumeDb1 = AudioServer.GetBusPeakVolumeLeftDb(indx, 0);
float volumeDb2 = AudioServer.GetBusPeakVolumeRightDb(indx, 0);
volumeDb1 = -200; volumeDb2 = -200, And then it won't be recorded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment