Constantly growing audio delay (Android), or very loud noise, or no audio at all (Linux)
I'm trying to read the default device audio data and use that to render a audio wave on the screen.
On Android (13), the program reads the audio data but it the signal shown on the screen is delayed, and this delay constantly grows over time, for example, if I tap the mic with my finger, the wave sound corresponding to my tap appears 1 second later, when I try that again the corresponding wave appears 2 seconds later, and so on...
On Linux (Pop!_OS) the delay behavior is not present, but the wave shown for my connected mic is just floor noise, nothing stands out if I talk or tap it. If I unplug and use the computer mic, a very loud signal is shown, the floor noise just clips out, If I tap or talk the signal gets even more cliped.
static std::array<SDL_FPoint, 1024> lines;
static u32 nextSampleIndex = 0;
static void streamCallback(void* const /*userdata*/,
SDL_AudioStream* const stream,
const i32 additionalAmount,
const i32 /*totalAmount*/) {
const u32 numSamplesReceived = additionalAmount / sizeof(f32);
const u32 numSamplesToRead = SDL_min(numSamplesReceived, lines.size() - nextSampleIndex);
const f32 displayWidth = (f32)Display::width();
const f32 displayHeight = (f32)Display::height();
std::array<f32, lines.size()> buf{};
SDL_GetAudioStreamData(stream, buf.data(), (i32)(numSamplesToRead * sizeof(f32)));
for (u32 i = 0; i < numSamplesToRead; ++i, ++nextSampleIndex) {
lines[nextSampleIndex].y = displayHeight / 2.0F + 100.0F * buf[i];
lines[nextSampleIndex].x = displayWidth * ((f32)i / (f32)buf.size());
}
if (nextSampleIndex == lines.size()) {
nextSampleIndex = 0;
}
}
// after initing SDL:
bool App::run() {
const SDL_AudioSpec audioSpec = {.format = SDL_AudioFormat::SDL_AUDIO_F32, .channels = 1, .freq = 44100};
SDL_AudioStream* audioStream = SDL_OpenAudioDeviceStream(
SDL_AUDIO_DEVICE_DEFAULT_RECORDING, &audioSpec, streamCallback, nullptr);
if (audioStream == nullptr) {
logging::log(logging::LogLevel::ERROR, "SDL_OpenAudioDeviceStream failed ({})", SDL_GetError());
return false;
}
SDL_ResumeAudioStreamDevice(audioStream);
while (running) {
processEvents();
Display::setDrawColor();
Display::clear();
Display::setDrawColor({.r = 0XFF, .g = 0XFF, .b = 0XFF, .a = 0XFF});
Display::draw(lines);
Display::show();
}
SDL_DestroyAudioStream(audioStream);
return true;
}
// Display funcs
bool Display::clear() {
if (!SDL_RenderClear(renderer)) {
logging::log(logging::LogLevel::ERROR, "SDL_RenderClear failed ({})", SDL_GetError());
return false;
}
return true;
}
bool Display::show() {
if (!SDL_RenderPresent(renderer)) {
logging::log(logging::LogLevel::ERROR, "SDL_RenderPresent failed ({})", SDL_GetError());
return false;
}
return true;
}
bool Display::setDrawColor(const SDL_Color drawColor) {
const auto [r, g, b, a] = drawColor;
if (!SDL_SetRenderDrawColor(renderer, r, g, b, a)) {
logging::log(logging::LogLevel::ERROR, "SDL_SetRenderDrawColor failed ({})", SDL_GetError());
return false;
}
return true;
}
bool Display::draw(const std::span<const SDL_FPoint> lines) {
if (!SDL_RenderLines(renderer, lines.data(), (i32)lines.size())) {
logging::log(logging::LogLevel::ERROR, "SDL_RenderLines failed ({})", SDL_GetError());
return false;
}
return true;
}