audio: SDL_ClearQueuedAudio() should free everything but two packets.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 06 Aug 2016 02:27:55 -0400
changeset 1026048c3f46395ae
parent 10259 457d9c7868ec
child 10261 e8facf18d5bd
audio: SDL_ClearQueuedAudio() should free everything but two packets.

Otherwise, if you had a massive, one-time queue buildup, the memory from that
remains allocated until you close the device. Also, if you are just using a
reasonable amount of space, this would previously cause you to reallocate it
over and over instead of keeping a little bit of memory around.
src/audio/SDL_audio.c
     1.1 --- a/src/audio/SDL_audio.c	Fri Aug 05 04:23:32 2016 -0400
     1.2 +++ b/src/audio/SDL_audio.c	Sat Aug 06 02:27:55 2016 -0400
     1.3 @@ -586,20 +586,44 @@
     1.4  SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
     1.5  {
     1.6      SDL_AudioDevice *device = get_audio_device(devid);
     1.7 -    SDL_AudioBufferQueue *buffer = NULL;
     1.8 +    SDL_AudioBufferQueue *packet;
     1.9 +
    1.10      if (!device) {
    1.11          return;  /* nothing to do. */
    1.12      }
    1.13  
    1.14      /* Blank out the device and release the mutex. Free it afterwards. */
    1.15      current_audio.impl.LockDevice(device);
    1.16 -    buffer = device->buffer_queue_head;
    1.17 +
    1.18 +    /* merge the available pool and the current queue into one list. */
    1.19 +    packet = device->buffer_queue_head;
    1.20 +    if (packet) {
    1.21 +        device->buffer_queue_tail->next = device->buffer_queue_pool;
    1.22 +    } else {
    1.23 +        packet = device->buffer_queue_pool;
    1.24 +    }
    1.25 +
    1.26 +    /* Remove the queued packets from the device. */
    1.27      device->buffer_queue_tail = NULL;
    1.28      device->buffer_queue_head = NULL;
    1.29      device->queued_bytes = 0;
    1.30 +    device->buffer_queue_pool = packet;
    1.31 +
    1.32 +    /* Keep up to two packets in the pool to reduce future malloc pressure. */
    1.33 +    if (packet) {
    1.34 +        if (!packet->next) {
    1.35 +            packet = NULL;  /* one packet (the only one) for the pool. */
    1.36 +        } else {
    1.37 +            SDL_AudioBufferQueue *next = packet->next->next;
    1.38 +            packet->next->next = NULL;  /* two packets for the pool. */
    1.39 +            packet = next;  /* rest will be freed. */
    1.40 +        }
    1.41 +    }
    1.42 +
    1.43      current_audio.impl.UnlockDevice(device);
    1.44  
    1.45 -    free_audio_queue(buffer);
    1.46 +    /* free any extra packets we didn't keep in the pool. */
    1.47 +    free_audio_queue(packet);
    1.48  }
    1.49  
    1.50