OpenAL结合libsndfile播放长音频时出现开头失真、突然中断问题求助
Let's break down the potential issues in your code that could be causing the start-up distortion and sudden playback interruptions. I'll walk through the most likely culprits first:
1. Not Updating Buffers Frequently Enough (Top Cause of Sudden Interruptions)
Your updateBufferStream() function is responsible for refilling buffers once OpenAL has finished playing them. If you don't call this function regularly (like every frame in your main game/app loop), OpenAL will run out of queued audio data and stop playback abruptly.
How often you need to call it depends on your buffer size: for example, if b_samples is set to 4096 and your audio is 44100Hz, each buffer holds ~93ms of audio. Aim to call updateBufferStream() every 50ms or so to ensure you never run dry. If you're only calling it once every few seconds, that's definitely the issue.
2. Small Buffer Size Causing Start-Up Distortion
If b_samples is set to a tiny value (like 256 or 512), the initial buffer fill might be too small to smooth out the start of playback. Try increasing it to a larger power of two—4096 or 8192 are standard choices for streaming audio. This will give OpenAL more data to work with upfront, reducing crackling or distortion at the start.
Also, double-check that b_samples is actually initialized somewhere in your code (it's not defined in the snippets you shared). An uninitialized variable could lead to weird buffer sizes and unexpected behavior.
3. Missing Error Checks for OpenAL Initialization
You're doing a good job checking errors after most OpenAL calls, but you skipped checking right after creating sources and buffers. If these calls fail silently, it could lead to broken playback:
alGenSources(1, &se_source); if (alGetError() != AL_NO_ERROR) { throw("Failed to create OpenAL source"); } alGenBuffers(num_buffers, se_buffers); if (alGetError() != AL_NO_ERROR) { throw("Failed to create OpenAL buffers"); }
Adding these checks will help you rule out initialization issues.
4. Stale State Check in Underrun Handling
In updateBufferStream(), you check the source's playback state before refilling processed buffers. That means you're looking at a state that might not reflect the latest changes. Move the state check to after you've handled all processed buffers:
// After processing all queued buffers... alGetSourcei(se_source, AL_SOURCE_STATE, &state); if (state != AL_PLAYING && state != AL_PAUSED) { ALint queued; alGetSourcei(se_source, AL_BUFFERS_QUEUED, &queued); if (queued > 0) { alSourcePlay(se_source); if (alGetError() != AL_NO_ERROR) { throw("error restarting music playback"); } } }
This way, you're checking the state after ensuring any empty buffers are refilled, which reduces the chance of unnecessary playback stops.
5. Memory Leaks (Non-Critical but Worth Fixing)
You're using malloc() for se_membuf but there's no corresponding free() call. Over time, this will leak memory. Add a destructor to clean up all your resources properly:
musicBuffer::~musicBuffer() { if (se_sndfile) sf_close(se_sndfile); if (se_membuf) free(se_membuf); // Clean up OpenAL resources alSourceStop(se_source); alSourcei(se_source, AL_BUFFER, 0); alDeleteBuffers(num_buffers, se_buffers); alDeleteSources(1, &se_source); }
This ensures you don't leave dangling resources behind.
6. Edge Case for Looping (If Needed)
If you want your audio to loop, your current code will stop playback once it reaches the end of the file. To fix this, rewind the file when you hit the end:
slen = sf_readf_short(se_sndfile, se_membuf, b_samples); if (slen <= 0) { // Rewind to start for continuous looping sf_seek(se_sndfile, 0, SEEK_SET); slen = sf_readf_short(se_sndfile, se_membuf, b_samples); } if (slen > 0) { slen *= se_sfinfo.channels * (sf_count_t)sizeof(short); alBufferData(bufid, se_format, se_membuf, (ALsizei)slen, se_sfinfo.samplerate); alSourceQueueBuffers(se_source, 1, &bufid); }
If you don't want looping, this isn't your issue—but sudden stops at the end of the file are expected behavior.
Quick Tests to Diagnose
- First, make sure
updateBufferStream()is called every frame in your main loop. - Try increasing
b_samplesto 4096 and see if the start-up distortion goes away. - Add the missing error checks for
alGenSourcesandalGenBuffersto rule out initialization failures.
内容的提问来源于stack exchange,提问作者AsianMario

