Skip to content

Commit 6ca0a68

Browse files
committed
openal: Retry deleting a buffer until success
The rationale for this change is Apple's OpenAL implementation, which needs a little time after the `alSourcei(source, AL_BUFFER, 0);` call before any buffers used by that source are free for deletion. The defaults in the config variables are such that the OpenAL manager will attempt to delete a buffer up to 6 times (that is, the original attempt plus 5 reattempts), with delays of 1ms, 2ms, 4ms, 8ms, and 16ms before each reattempt - which means it'll wait a grand total of 31ms for a buffer to be free before assuming that some even greater problem must be happening and giving up.
1 parent 1862100 commit 6ca0a68

File tree

5 files changed

+63
-4
lines changed

5 files changed

+63
-4
lines changed

panda/src/audiotraits/config_openalAudio.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ ConfigVariableString openal_device
3030
PRC_DESC("Specify the OpenAL device string for audio playback (no quotes). If this "
3131
"is not specified, the OpenAL default device is used."));
3232

33+
ConfigVariableInt openal_buffer_delete_reattempts
34+
("openal-buffer-delete-reattempts", 5,
35+
PRC_DESC("If deleting a buffer fails due to still being in use, the OpenAL "
36+
"sound plugin will wait a moment and reattempt deletion, with an "
37+
"exponentially-increasing delay for each attempt. This number "
38+
"specifies how many repeat attempts (not counting the initial attempt) "
39+
"should be made before giving up and raising an error."));
40+
41+
ConfigVariableDouble openal_buffer_delete_delay
42+
("openal-buffer-delete-delay", 0.001,
43+
PRC_DESC("If deleting a buffer fails due to still being in use, the OpenAL "
44+
"sound plugin will wait a moment and reattempt deletion, with an "
45+
"exponentially-increasing delay for each attempt. This number "
46+
"specifies how long, in seconds, the OpenAL plugin will wait after "
47+
"its first failed attempt. The second attempt will be double this "
48+
"delay, the third quadruple, and so on."));
49+
3350

3451
/**
3552
* Initializes the library. This must be called at least once before any of

panda/src/audiotraits/config_openalAudio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@ extern "C" EXPCL_OPENAL_AUDIO void init_libOpenALAudio();
2626
extern "C" EXPCL_OPENAL_AUDIO Create_AudioManager_proc *get_audio_manager_func_openal_audio();
2727

2828
extern ConfigVariableString openal_device;
29+
extern ConfigVariableInt openal_buffer_delete_reattempts;
30+
extern ConfigVariableDouble openal_buffer_delete_delay;
2931

3032
#endif // CONFIG_OPENALAUDIO_H

panda/src/audiotraits/openalAudioManager.cxx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ OpenALAudioManager::SoundData::
10521052
if (_sample != 0) {
10531053
if (_manager->_is_valid) {
10541054
_manager->make_current();
1055-
alDeleteBuffers(1,&_sample);
1055+
_manager->delete_buffer(_sample);
10561056
}
10571057
_sample = 0;
10581058
}
@@ -1128,3 +1128,42 @@ discard_excess_cache(int sample_limit) {
11281128
delete sd;
11291129
}
11301130
}
1131+
1132+
/**
1133+
* Deletes an OpenAL buffer. This is a special function because some
1134+
* implementations of OpenAL (e.g. Apple's) don't unlock the buffers
1135+
* immediately, due to needing to coordinate with another thread. If this is
1136+
* the case, the alDeleteBuffers call will error back with AL_INVALID_OPERATION
1137+
* as if trying to delete an actively-used buffer, which will tell us to wait a
1138+
* bit and try again.
1139+
*/
1140+
void OpenALAudioManager::
1141+
delete_buffer(ALuint buffer) {
1142+
ReMutexHolder holder(_lock);
1143+
int attempt = 0;
1144+
ALuint error;
1145+
1146+
// Keep trying until we succeed (or give up).
1147+
while (true) {
1148+
alDeleteBuffers(1, &buffer);
1149+
error = alGetError();
1150+
1151+
if (error == AL_NO_ERROR) {
1152+
// Success! This will happen right away 99% of the time.
1153+
return;
1154+
} else if (error != AL_INVALID_OPERATION) {
1155+
// We weren't expecting that. This should be reported.
1156+
break;
1157+
} else if (attempt >= openal_buffer_delete_reattempts.get_value()) {
1158+
// We ran out of reattempts. Give up.
1159+
break;
1160+
} else {
1161+
// Make another attempt after (delay * 2^n) seconds.
1162+
Thread::sleep(openal_buffer_delete_delay.get_value() * (1 << attempt));
1163+
attempt++;
1164+
}
1165+
}
1166+
1167+
// If we got here, one of the breaks above happened, indicating an error.
1168+
audio_error("failed to delete a buffer: " << alGetString(error) );
1169+
}

panda/src/audiotraits/openalAudioManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ class EXPCL_OPENAL_AUDIO OpenALAudioManager : public AudioManager {
129129
void decrement_client_count(SoundData *sd);
130130
void discard_excess_cache(int limit);
131131

132+
void delete_buffer(ALuint buffer);
133+
132134
void starting_sound(OpenALAudioSound* audio);
133135
void stopping_sound(OpenALAudioSound* audio);
134136

panda/src/audiotraits/openalAudioSound.cxx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,7 @@ stop() {
208208
for (int i=0; i<((int)(_stream_queued.size())); i++) {
209209
ALuint buffer = _stream_queued[i]._buffer;
210210
if (buffer != _sd->_sample) {
211-
alDeleteBuffers(1, &buffer);
212-
al_audio_errcheck("deleting a buffer");
211+
_manager->delete_buffer(buffer);
213212
}
214213
}
215214
_stream_queued.resize(0);
@@ -472,7 +471,7 @@ pull_used_buffers() {
472471
correct_calibrated_clock(rtc, al);
473472
}
474473
if (buffer != _sd->_sample) {
475-
alDeleteBuffers(1,&buffer);
474+
_manager->delete_buffer(buffer);
476475
}
477476
}
478477
} else {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy