@@ -446,18 +446,34 @@ pull_used_buffers() {
446
446
int err = alGetError ();
447
447
if (err == AL_NO_ERROR) {
448
448
if (_stream_queued[0 ]._buffer != buffer) {
449
- audio_error (" corruption in stream queue" );
450
- cleanup ();
451
- return ;
452
- }
453
- _stream_queued.pop_front ();
454
- if (_stream_queued.size ()) {
455
- double al = _stream_queued[0 ]._time_offset + _stream_queued[0 ]._loop_index * _length;
456
- double rtc = TrueClock::get_global_ptr ()->get_short_time ();
457
- correct_calibrated_clock (rtc, al);
458
- }
459
- if (buffer != _sd->_sample ) {
460
- alDeleteBuffers (1 ,&buffer);
449
+ // This is certainly atypical: most implementations of OpenAL unqueue
450
+ // buffers in FIFO order. However, some (e.g. Apple's) can unqueue
451
+ // buffers out-of-order if playback is interrupted. So, we don't freak
452
+ // out unless `buffer` isn't in _stream_queued at all.
453
+ bool found_culprit = false ;
454
+ for (auto it = _stream_queued.begin (); it != _stream_queued.end (); ++it) {
455
+ if (it->_buffer == buffer) {
456
+ // Phew. Found it. Just remove that.
457
+ _stream_queued.erase (it);
458
+ found_culprit = true ;
459
+ break ;
460
+ }
461
+ }
462
+ if (!found_culprit) {
463
+ audio_error (" corruption in stream queue" );
464
+ cleanup ();
465
+ return ;
466
+ }
467
+ } else {
468
+ _stream_queued.pop_front ();
469
+ if (_stream_queued.size ()) {
470
+ double al = _stream_queued[0 ]._time_offset + _stream_queued[0 ]._loop_index * _length;
471
+ double rtc = TrueClock::get_global_ptr ()->get_short_time ();
472
+ correct_calibrated_clock (rtc, al);
473
+ }
474
+ if (buffer != _sd->_sample ) {
475
+ alDeleteBuffers (1 ,&buffer);
476
+ }
461
477
}
462
478
} else {
463
479
break ;
0 commit comments