coreaudio: Better handling of audio buffer queue management.
We don't fill buffers just to throw them away during shutdown now, we let the AudioQueue free its own buffers during disposal (which fixes possible warnings getting printed to stderr by CoreAudio), and we stop the queue after running any queued audio during shutdown, which prevents dropping the end of the audio playback if you opened the device with an enormous sample buffer. Fixes Bugzilla #3555.
parent
126e5a1dbf
commit
fc4402e5ff
|
@ -400,8 +400,12 @@ static void
|
|||
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
if (SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
return; /* don't do anything. */
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||
/* Supply silence if audio is enabled and not paused */
|
||||
/* Supply silence if audio is not enabled or paused */
|
||||
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
||||
} else {
|
||||
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
||||
|
@ -430,9 +434,7 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
|||
}
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
|
||||
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
|
||||
}
|
||||
|
@ -443,7 +445,13 @@ inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer
|
|||
const AudioStreamPacketDescription *inPacketDescs )
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) { /* ignore unless we're active. */
|
||||
|
||||
if (SDL_AtomicGet(&this->shutdown)) {
|
||||
return; /* don't do anything. */
|
||||
}
|
||||
|
||||
/* ignore unless we're active. */
|
||||
if (!SDL_AtomicGet(&this->paused) && SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) {
|
||||
const Uint8 *ptr = (const Uint8 *) inBuffer->mAudioData;
|
||||
UInt32 remaining = inBuffer->mAudioDataByteSize;
|
||||
while (remaining > 0) {
|
||||
|
@ -466,9 +474,7 @@ inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer
|
|||
}
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -514,7 +520,6 @@ static void
|
|||
COREAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
const SDL_bool iscapture = this->iscapture;
|
||||
int i;
|
||||
|
||||
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
||||
/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
|
||||
|
@ -533,12 +538,6 @@ COREAUDIO_CloseDevice(_THIS)
|
|||
}
|
||||
|
||||
if (this->hidden->audioQueue) {
|
||||
for (i = 0; i < this->hidden->numAudioBuffers; i++) {
|
||||
if (this->hidden->audioBuffer[i]) {
|
||||
AudioQueueFreeBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i]);
|
||||
}
|
||||
}
|
||||
SDL_free(this->hidden->audioBuffer);
|
||||
AudioQueueDispose(this->hidden->audioQueue, 1);
|
||||
}
|
||||
|
||||
|
@ -546,6 +545,8 @@ COREAUDIO_CloseDevice(_THIS)
|
|||
SDL_DestroySemaphore(this->hidden->ready_semaphore);
|
||||
}
|
||||
|
||||
/* AudioQueueDispose() frees the actual buffer objects. */
|
||||
SDL_free(this->hidden->audioBuffer);
|
||||
SDL_free(this->hidden->thread_error);
|
||||
SDL_free(this->hidden->buffer);
|
||||
SDL_free(this->hidden);
|
||||
|
@ -718,9 +719,9 @@ audioqueue_thread(void *arg)
|
|||
if (this->iscapture) { /* just stop immediately for capture devices. */
|
||||
AudioQueueStop(this->hidden->audioQueue, 1);
|
||||
} else { /* Drain off any pending playback. */
|
||||
AudioQueueStop(this->hidden->audioQueue, 0);
|
||||
const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0;
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
||||
AudioQueueStop(this->hidden->audioQueue, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue