Skip to content

Commit

Permalink
coreaudio: Better handling of audio buffer queue management.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
icculus committed May 24, 2017
1 parent 126e5a1 commit fc4402e
Showing 1 changed file with 17 additions and 16 deletions.
33 changes: 17 additions & 16 deletions src/audio/coreaudio/SDL_coreaudio.m
Expand Up @@ -400,8 +400,12 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
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;
Expand Down Expand Up @@ -430,9 +434,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
}
}

if (!SDL_AtomicGet(&this->hidden->shutdown)) {
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
}
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);

inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
}
Expand All @@ -443,7 +445,13 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
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) {
Expand All @@ -466,9 +474,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
}
}

if (!SDL_AtomicGet(&this->hidden->shutdown)) {
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
}
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
}


Expand Down Expand Up @@ -514,7 +520,6 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
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?) */
Expand All @@ -533,19 +538,15 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
}

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);
}

if (this->hidden->ready_semaphore) {
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);
Expand Down Expand Up @@ -718,9 +719,9 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
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;
Expand Down

0 comments on commit fc4402e

Please sign in to comment.