Skip to content

Commit 86ea17d

Browse files
authored
[OpenAL] Fix sourceSeek crash on stopped sources (#27426)
Fix a crash in `sourceSeek` when called on a stopped source by resetting `bufsProcessed = 0` before evaluating buffer durations. This replaces #26770. Unlike #26770, which added a top-level check on `src.bufQueue[0]`, this change handles zero/dummy buffers and empty queues safely anywhere in `bufQueue` via `for .. of` iteration and `audioBuf?.duration ?? 0.0`. It also adds assertions to `test_openal_error.c` to verify state correctness after seeking. See: #26770
1 parent 2768c9f commit 86ea17d

3 files changed

Lines changed: 45 additions & 9 deletions

File tree

src/lib/libopenal.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -721,15 +721,17 @@ var LibraryOpenAL = {
721721
AL.setSourceState(src, {{{ cDefs.AL_INITIAL }}});
722722
}
723723

724-
if (src.bufQueue[src.bufsProcessed].audioBuf !== null) {
725-
src.bufsProcessed = 0;
726-
while (offset > src.bufQueue[src.bufsProcessed].audioBuf.duration) {
727-
offset -= src.bufQueue[src.bufsProcessed].audioBuf.duration;
728-
src.bufsProcessed++;
724+
src.bufsProcessed = 0;
725+
for (var buf of src.bufQueue) {
726+
var duration = buf.audioBuf?.duration ?? 0.0;
727+
if (offset < duration) {
728+
break;
729729
}
730-
731-
src.bufOffset = offset;
730+
offset -= duration;
731+
src.bufsProcessed++;
732732
}
733+
// 'offset' is now the intra-buffer offset within the target buffer.
734+
src.bufOffset = offset;
733735

734736
if (playing) {
735737
AL.setSourceState(src, {{{ cDefs.AL_PLAYING }}});

test/codesize/test_codesize_hello_dylink_all.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"a.out.js": 267949,
2+
"a.out.js": 267933,
33
"a.out.nodebug.wasm": 588309,
4-
"total": 856258,
4+
"total": 856242,
55
"sent": [
66
"IMG_Init",
77
"IMG_Load",

test/openal/test_openal_error.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,39 @@ void test_offsets_with_zero_buffer(void) {
3838
alDeleteBuffers(1, &buf);
3939
}
4040

41+
void test_stopped_seek(void) {
42+
ALuint buf = 0;
43+
alGenBuffers(1, &buf);
44+
short dummy_data[2000] = {0};
45+
alBufferData(buf, AL_FORMAT_MONO16, dummy_data, sizeof(dummy_data), 44100);
46+
assert(alGetError() == AL_NO_ERROR);
47+
48+
ALuint src = 0;
49+
alGenSources(1, &src);
50+
assert(alGetError() == AL_NO_ERROR);
51+
52+
alSourcei(src, AL_BUFFER, buf);
53+
assert(alGetError() == AL_NO_ERROR);
54+
55+
alSourcePlay(src);
56+
assert(alGetError() == AL_NO_ERROR);
57+
58+
alSourceStop(src);
59+
assert(alGetError() == AL_NO_ERROR);
60+
61+
// See of 0.01 seconds while the stream in stopped.
62+
alSourcef(src, AL_SEC_OFFSET, 0.01f);
63+
assert(alGetError() == AL_NO_ERROR);
64+
65+
// Verify the the seek was successful
66+
float offset = 0.0f;
67+
alGetSourcef(src, AL_SEC_OFFSET, &offset);
68+
assert(offset == 0.01f);
69+
70+
alDeleteSources(1, &src);
71+
alDeleteBuffers(1, &buf);
72+
}
73+
4174
int main(int argc, char* argv[]) {
4275
ALCboolean ret;
4376

@@ -64,6 +97,7 @@ int main(int argc, char* argv[]) {
6497
assert(alGetError() == AL_NO_ERROR);
6598

6699
test_offsets_with_zero_buffer();
100+
test_stopped_seek();
67101

68102
ret = alcMakeContextCurrent(NULL);
69103
assert(ret == ALC_TRUE);

0 commit comments

Comments
 (0)