Refactored the audio queueing code to a generic SDL_DataQueue interface.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 06 Dec 2016 02:23:54 -0500
changeset 1068134b25c97b17f
parent 10680 fe759a74b018
child 10682 520611e8f69e
Refactored the audio queueing code to a generic SDL_DataQueue interface.

This is not a public API (at the moment), but we will be needing this for
other internal things soon.
VisualC/SDL/SDL.vcxproj
VisualC/SDL/SDL.vcxproj.filters
VisualC/SDL/SDL_VS2008.vcproj
src/SDL_dataqueue.c
src/SDL_dataqueue.h
src/audio/SDL_audio.c
src/audio/SDL_sysaudio.h
     1.1 --- a/VisualC/SDL/SDL.vcxproj	Tue Dec 06 02:20:58 2016 -0500
     1.2 +++ b/VisualC/SDL/SDL.vcxproj	Tue Dec 06 02:23:54 2016 -0500
     1.3 @@ -387,6 +387,7 @@
     1.4      <ClCompile Include="..\..\src\libm\s_sin.c" />
     1.5      <ClCompile Include="..\..\src\libm\s_tan.c" />
     1.6      <ClCompile Include="..\..\src\SDL.c" />
     1.7 +    <ClCompile Include="..\..\src\SDL_dataqueue.c" />
     1.8      <ClCompile Include="..\..\src\SDL_assert.c" />
     1.9      <ClCompile Include="..\..\src\atomic\SDL_atomic.c" />
    1.10      <ClCompile Include="..\..\src\audio\SDL_audio.c" />
     2.1 --- a/VisualC/SDL/SDL.vcxproj.filters	Tue Dec 06 02:20:58 2016 -0500
     2.2 +++ b/VisualC/SDL/SDL.vcxproj.filters	Tue Dec 06 02:23:54 2016 -0500
     2.3 @@ -253,6 +253,7 @@
     2.4      <ClInclude Include="..\..\src\dynapi\SDL_dynapi_overrides.h" />
     2.5      <ClInclude Include="..\..\src\dynapi\SDL_dynapi_procs.h" />
     2.6      <ClInclude Include="..\..\src\SDL_error_c.h" />
     2.7 +    <ClInclude Include="..\..\src\SDL_dataqueue.h" />
     2.8      <ClInclude Include="..\..\src\events\SDL_events_c.h" />
     2.9      <ClInclude Include="..\..\src\events\SDL_gesture_c.h" />
    2.10      <ClInclude Include="..\..\src\video\SDL_glesfuncs.h" />
    2.11 @@ -357,6 +358,7 @@
    2.12      <ClCompile Include="..\..\src\audio\dummy\SDL_dummyaudio.c" />
    2.13      <ClCompile Include="..\..\src\dynapi\SDL_dynapi.c" />
    2.14      <ClCompile Include="..\..\src\video\SDL_egl.c" />
    2.15 +    <ClCompile Include="..\..\src\SDL_dataqueue.c" />
    2.16      <ClCompile Include="..\..\src\SDL_error.c" />
    2.17      <ClCompile Include="..\..\src\events\SDL_events.c" />
    2.18      <ClCompile Include="..\..\src\video\SDL_fillrect.c" />
     3.1 --- a/VisualC/SDL/SDL_VS2008.vcproj	Tue Dec 06 02:20:58 2016 -0500
     3.2 +++ b/VisualC/SDL/SDL_VS2008.vcproj	Tue Dec 06 02:23:54 2016 -0500
     3.3 @@ -962,6 +962,14 @@
     3.4  			>
     3.5  		</File>
     3.6  		<File
     3.7 +			RelativePath="..\..\src\SDL_dataqueue.c"
     3.8 +			>
     3.9 +		</File>
    3.10 +		<File
    3.11 +			RelativePath="..\..\src\SDL_dataqueue.h"
    3.12 +			>
    3.13 +		</File>
    3.14 +		<File
    3.15  			RelativePath="..\..\src\SDL_error.c"
    3.16  			>
    3.17  		</File>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/SDL_dataqueue.c	Tue Dec 06 02:23:54 2016 -0500
     4.3 @@ -0,0 +1,260 @@
     4.4 +/*
     4.5 +  Simple DirectMedia Layer
     4.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4.7 +
     4.8 +  This software is provided 'as-is', without any express or implied
     4.9 +  warranty.  In no event will the authors be held liable for any damages
    4.10 +  arising from the use of this software.
    4.11 +
    4.12 +  Permission is granted to anyone to use this software for any purpose,
    4.13 +  including commercial applications, and to alter it and redistribute it
    4.14 +  freely, subject to the following restrictions:
    4.15 +
    4.16 +  1. The origin of this software must not be misrepresented; you must not
    4.17 +     claim that you wrote the original software. If you use this software
    4.18 +     in a product, an acknowledgment in the product documentation would be
    4.19 +     appreciated but is not required.
    4.20 +  2. Altered source versions must be plainly marked as such, and must not be
    4.21 +     misrepresented as being the original software.
    4.22 +  3. This notice may not be removed or altered from any source distribution.
    4.23 +*/
    4.24 +
    4.25 +#include "./SDL_internal.h"
    4.26 +#include "SDL.h"
    4.27 +#include "./SDL_dataqueue.h"
    4.28 +#include "SDL_assert.h"
    4.29 +
    4.30 +typedef struct SDL_DataQueuePacket
    4.31 +{
    4.32 +    size_t datalen;  /* bytes currently in use in this packet. */
    4.33 +    size_t startpos;  /* bytes currently consumed in this packet. */
    4.34 +    struct SDL_DataQueuePacket *next;  /* next item in linked list. */
    4.35 +    Uint8 data[SDL_VARIABLE_LENGTH_ARRAY];  /* packet data */
    4.36 +} SDL_DataQueuePacket;
    4.37 +
    4.38 +struct SDL_DataQueue
    4.39 +{
    4.40 +    SDL_DataQueuePacket *head; /* device fed from here. */
    4.41 +    SDL_DataQueuePacket *tail; /* queue fills to here. */
    4.42 +    SDL_DataQueuePacket *pool; /* these are unused packets. */
    4.43 +    size_t packet_size;   /* size of new packets */
    4.44 +    size_t queued_bytes;  /* number of bytes of data in the queue. */
    4.45 +};
    4.46 +
    4.47 +static void
    4.48 +SDL_FreeDataQueueList(SDL_DataQueuePacket *packet)
    4.49 +{
    4.50 +    while (packet) {
    4.51 +        SDL_DataQueuePacket *next = packet->next;
    4.52 +        SDL_free(packet);
    4.53 +        packet = next;
    4.54 +    }
    4.55 +}
    4.56 +
    4.57 +
    4.58 +/* this all expects that you managed thread safety elsewhere. */
    4.59 +
    4.60 +SDL_DataQueue *
    4.61 +SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
    4.62 +{
    4.63 +    SDL_DataQueue *queue = (SDL_DataQueue *) SDL_malloc(sizeof (SDL_DataQueue));
    4.64 +
    4.65 +    if (!queue) {
    4.66 +        SDL_OutOfMemory();
    4.67 +        return NULL;
    4.68 +    } else {
    4.69 +        const size_t packetlen = _packetlen ? _packetlen : 1024;
    4.70 +        const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen;
    4.71 +        size_t i;
    4.72 +
    4.73 +        SDL_zerop(queue);
    4.74 +        queue->packet_size = packetlen;
    4.75 +
    4.76 +        for (i = 0; i < wantpackets; i++) {
    4.77 +            SDL_DataQueuePacket *packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packetlen);
    4.78 +            if (packet) { /* don't care if this fails, we'll deal later. */
    4.79 +                packet->datalen = 0;
    4.80 +                packet->startpos = 0;
    4.81 +                packet->next = queue->pool;
    4.82 +                queue->pool = packet;
    4.83 +            }
    4.84 +        }
    4.85 +    }
    4.86 +
    4.87 +    return queue;
    4.88 +}
    4.89 +
    4.90 +void
    4.91 +SDL_FreeDataQueue(SDL_DataQueue *queue)
    4.92 +{
    4.93 +    if (queue) {
    4.94 +        SDL_FreeDataQueueList(queue->head);
    4.95 +        SDL_FreeDataQueueList(queue->pool);
    4.96 +        SDL_free(queue);
    4.97 +    }
    4.98 +}
    4.99 +
   4.100 +void
   4.101 +SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
   4.102 +{
   4.103 +    const size_t packet_size = queue ? queue->packet_size : 1;
   4.104 +    const size_t slackpackets = (slack + (packet_size-1)) / packet_size;
   4.105 +    SDL_DataQueuePacket *packet;
   4.106 +    SDL_DataQueuePacket *prev = NULL;
   4.107 +    size_t i;
   4.108 +
   4.109 +    if (!queue) {
   4.110 +        return;
   4.111 +    }
   4.112 +
   4.113 +    packet = queue->head;
   4.114 +
   4.115 +    /* merge the available pool and the current queue into one list. */
   4.116 +    if (packet) {
   4.117 +        queue->tail->next = queue->pool;
   4.118 +    } else {
   4.119 +        packet = queue->pool;
   4.120 +    }
   4.121 +
   4.122 +    /* Remove the queued packets from the device. */
   4.123 +    queue->tail = NULL;
   4.124 +    queue->head = NULL;
   4.125 +    queue->queued_bytes = 0;
   4.126 +    queue->pool = packet;
   4.127 +
   4.128 +    /* Optionally keep some slack in the pool to reduce malloc pressure. */
   4.129 +    for (i = 0; packet && (i < slackpackets); i++) {
   4.130 +        prev = packet;
   4.131 +        packet = packet->next;
   4.132 +    }
   4.133 +
   4.134 +    if (prev) {
   4.135 +        prev->next = NULL;
   4.136 +    } else {
   4.137 +        queue->pool = NULL;
   4.138 +    }
   4.139 +
   4.140 +    SDL_FreeDataQueueList(packet);  /* free extra packets */
   4.141 +}
   4.142 +
   4.143 +int
   4.144 +SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
   4.145 +{
   4.146 +    size_t len = _len;
   4.147 +    const Uint8 *data = (const Uint8 *) _data;
   4.148 +    const size_t packet_size = queue ? queue->packet_size : 0;
   4.149 +    SDL_DataQueuePacket *orighead;
   4.150 +    SDL_DataQueuePacket *origtail;
   4.151 +    size_t origlen;
   4.152 +    size_t datalen;
   4.153 +
   4.154 +    if (!queue) {
   4.155 +        return SDL_InvalidParamError("queue");
   4.156 +    }
   4.157 +
   4.158 +    orighead = queue->head;
   4.159 +    origtail = queue->tail;
   4.160 +    origlen = origtail ? origtail->datalen : 0;
   4.161 +
   4.162 +    while (len > 0) {
   4.163 +        SDL_DataQueuePacket *packet = queue->tail;
   4.164 +        SDL_assert(!packet || (packet->datalen <= packet_size));
   4.165 +        if (!packet || (packet->datalen >= packet_size)) {
   4.166 +            /* tail packet missing or completely full; we need a new packet. */
   4.167 +            packet = queue->pool;
   4.168 +            if (packet != NULL) {
   4.169 +                /* we have one available in the pool. */
   4.170 +                queue->pool = packet->next;
   4.171 +            } else {
   4.172 +                /* Have to allocate a new one! */
   4.173 +                packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packet_size);
   4.174 +                if (packet == NULL) {
   4.175 +                    /* uhoh, reset so we've queued nothing new, free what we can. */
   4.176 +                    if (!origtail) {
   4.177 +                        packet = queue->head;  /* whole queue. */
   4.178 +                    } else {
   4.179 +                        packet = origtail->next;  /* what we added to existing queue. */
   4.180 +                        origtail->next = NULL;
   4.181 +                        origtail->datalen = origlen;
   4.182 +                    }
   4.183 +                    queue->head = orighead;
   4.184 +                    queue->tail = origtail;
   4.185 +                    queue->pool = NULL;
   4.186 +
   4.187 +                    SDL_FreeDataQueueList(packet);  /* give back what we can. */
   4.188 +
   4.189 +                    return SDL_OutOfMemory();
   4.190 +                }
   4.191 +            }
   4.192 +            packet->datalen = 0;
   4.193 +            packet->startpos = 0;
   4.194 +            packet->next = NULL;
   4.195 +                
   4.196 +            SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
   4.197 +            if (queue->tail == NULL) {
   4.198 +                queue->head = packet;
   4.199 +            } else {
   4.200 +                queue->tail->next = packet;
   4.201 +            }
   4.202 +            queue->tail = packet;
   4.203 +        }
   4.204 +
   4.205 +        datalen = SDL_min(len, packet_size - packet->datalen);
   4.206 +        SDL_memcpy(packet->data + packet->datalen, data, datalen);
   4.207 +        data += datalen;
   4.208 +        len -= datalen;
   4.209 +        packet->datalen += datalen;
   4.210 +        queue->queued_bytes += datalen;
   4.211 +    }
   4.212 +
   4.213 +    return 0;
   4.214 +}
   4.215 +
   4.216 +size_t
   4.217 +SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
   4.218 +{
   4.219 +    size_t len = _len;
   4.220 +    Uint8 *buf = (Uint8 *) _buf;
   4.221 +    Uint8 *ptr = buf;
   4.222 +    SDL_DataQueuePacket *packet;
   4.223 +
   4.224 +    if (!queue) {
   4.225 +        return 0;
   4.226 +    }
   4.227 +
   4.228 +    while ((len > 0) && ((packet = queue->head) != NULL)) {
   4.229 +        const size_t avail = packet->datalen - packet->startpos;
   4.230 +        const size_t cpy = SDL_min(len, avail);
   4.231 +        SDL_assert(queue->queued_bytes >= avail);
   4.232 +
   4.233 +        SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
   4.234 +        packet->startpos += cpy;
   4.235 +        ptr += cpy;
   4.236 +        queue->queued_bytes -= cpy;
   4.237 +        len -= cpy;
   4.238 +
   4.239 +        if (packet->startpos == packet->datalen) {  /* packet is done, put it in the pool. */
   4.240 +            queue->head = packet->next;
   4.241 +            SDL_assert((packet->next != NULL) || (packet == queue->tail));
   4.242 +            packet->next = queue->pool;
   4.243 +            queue->pool = packet;
   4.244 +        }
   4.245 +    }
   4.246 +
   4.247 +    SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
   4.248 +
   4.249 +    if (queue->head == NULL) {
   4.250 +        queue->tail = NULL;  /* in case we drained the queue entirely. */
   4.251 +    }
   4.252 +
   4.253 +    return (size_t) (ptr - buf);
   4.254 +}
   4.255 +
   4.256 +size_t
   4.257 +SDL_CountDataQueue(SDL_DataQueue *queue)
   4.258 +{
   4.259 +    return queue ? queue->queued_bytes : 0;
   4.260 +}
   4.261 +
   4.262 +/* vi: set ts=4 sw=4 expandtab: */
   4.263 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/SDL_dataqueue.h	Tue Dec 06 02:23:54 2016 -0500
     5.3 @@ -0,0 +1,39 @@
     5.4 +/*
     5.5 +  Simple DirectMedia Layer
     5.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     5.7 +
     5.8 +  This software is provided 'as-is', without any express or implied
     5.9 +  warranty.  In no event will the authors be held liable for any damages
    5.10 +  arising from the use of this software.
    5.11 +
    5.12 +  Permission is granted to anyone to use this software for any purpose,
    5.13 +  including commercial applications, and to alter it and redistribute it
    5.14 +  freely, subject to the following restrictions:
    5.15 +
    5.16 +  1. The origin of this software must not be misrepresented; you must not
    5.17 +     claim that you wrote the original software. If you use this software
    5.18 +     in a product, an acknowledgment in the product documentation would be
    5.19 +     appreciated but is not required.
    5.20 +  2. Altered source versions must be plainly marked as such, and must not be
    5.21 +     misrepresented as being the original software.
    5.22 +  3. This notice may not be removed or altered from any source distribution.
    5.23 +*/
    5.24 +#ifndef SDL_dataqueue_h_
    5.25 +#define SDL_dataqueue_h_
    5.26 +
    5.27 +/* this is not (currently) a public API. But maybe it should be! */
    5.28 +
    5.29 +struct SDL_DataQueue;
    5.30 +typedef struct SDL_DataQueue SDL_DataQueue;
    5.31 +
    5.32 +SDL_DataQueue *SDL_NewDataQueue(const size_t packetlen, const size_t initialslack);
    5.33 +void SDL_FreeDataQueue(SDL_DataQueue *queue);
    5.34 +void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack);
    5.35 +int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *data, const size_t len);
    5.36 +size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
    5.37 +size_t SDL_CountDataQueue(SDL_DataQueue *queue);
    5.38 +
    5.39 +#endif /* SDL_dataqueue_h_ */
    5.40 +
    5.41 +/* vi: set ts=4 sw=4 expandtab: */
    5.42 +
     6.1 --- a/src/audio/SDL_audio.c	Tue Dec 06 02:20:58 2016 -0500
     6.2 +++ b/src/audio/SDL_audio.c	Tue Dec 06 02:23:54 2016 -0500
     6.3 @@ -418,136 +418,23 @@
     6.4  
     6.5  /* buffer queueing support... */
     6.6  
     6.7 -/* this expects that you managed thread safety elsewhere. */
     6.8 -static void
     6.9 -free_audio_queue(SDL_AudioBufferQueue *packet)
    6.10 -{
    6.11 -    while (packet) {
    6.12 -        SDL_AudioBufferQueue *next = packet->next;
    6.13 -        SDL_free(packet);
    6.14 -        packet = next;
    6.15 -    }
    6.16 -}
    6.17 -
    6.18 -/* NOTE: This assumes you'll hold the mixer lock before calling! */
    6.19 -static int
    6.20 -queue_audio_to_device(SDL_AudioDevice *device, const Uint8 *data, Uint32 len)
    6.21 -{
    6.22 -    SDL_AudioBufferQueue *orighead;
    6.23 -    SDL_AudioBufferQueue *origtail;
    6.24 -    Uint32 origlen;
    6.25 -    Uint32 datalen;
    6.26 -
    6.27 -    orighead = device->buffer_queue_head;
    6.28 -    origtail = device->buffer_queue_tail;
    6.29 -    origlen = origtail ? origtail->datalen : 0;
    6.30 -
    6.31 -    while (len > 0) {
    6.32 -        SDL_AudioBufferQueue *packet = device->buffer_queue_tail;
    6.33 -        SDL_assert(!packet || (packet->datalen <= SDL_AUDIOBUFFERQUEUE_PACKETLEN));
    6.34 -        if (!packet || (packet->datalen >= SDL_AUDIOBUFFERQUEUE_PACKETLEN)) {
    6.35 -            /* tail packet missing or completely full; we need a new packet. */
    6.36 -            packet = device->buffer_queue_pool;
    6.37 -            if (packet != NULL) {
    6.38 -                /* we have one available in the pool. */
    6.39 -                device->buffer_queue_pool = packet->next;
    6.40 -            } else {
    6.41 -                /* Have to allocate a new one! */
    6.42 -                packet = (SDL_AudioBufferQueue *) SDL_malloc(sizeof (SDL_AudioBufferQueue));
    6.43 -                if (packet == NULL) {
    6.44 -                    /* uhoh, reset so we've queued nothing new, free what we can. */
    6.45 -                    if (!origtail) {
    6.46 -                        packet = device->buffer_queue_head;  /* whole queue. */
    6.47 -                    } else {
    6.48 -                        packet = origtail->next;  /* what we added to existing queue. */
    6.49 -                        origtail->next = NULL;
    6.50 -                        origtail->datalen = origlen;
    6.51 -                    }
    6.52 -                    device->buffer_queue_head = orighead;
    6.53 -                    device->buffer_queue_tail = origtail;
    6.54 -                    device->buffer_queue_pool = NULL;
    6.55 -
    6.56 -                    free_audio_queue(packet);  /* give back what we can. */
    6.57 -
    6.58 -                    return SDL_OutOfMemory();
    6.59 -                }
    6.60 -            }
    6.61 -            packet->datalen = 0;
    6.62 -            packet->startpos = 0;
    6.63 -            packet->next = NULL;
    6.64 -
    6.65 -            SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
    6.66 -            if (device->buffer_queue_tail == NULL) {
    6.67 -                device->buffer_queue_head = packet;
    6.68 -            } else {
    6.69 -                device->buffer_queue_tail->next = packet;
    6.70 -            }
    6.71 -            device->buffer_queue_tail = packet;
    6.72 -        }
    6.73 -
    6.74 -        datalen = SDL_min(len, SDL_AUDIOBUFFERQUEUE_PACKETLEN - packet->datalen);
    6.75 -        SDL_memcpy(packet->data + packet->datalen, data, datalen);
    6.76 -        data += datalen;
    6.77 -        len -= datalen;
    6.78 -        packet->datalen += datalen;
    6.79 -        device->queued_bytes += datalen;
    6.80 -    }
    6.81 -
    6.82 -    return 0;
    6.83 -}
    6.84 -
    6.85 -/* NOTE: This assumes you'll hold the mixer lock before calling! */
    6.86 -static Uint32
    6.87 -dequeue_audio_from_device(SDL_AudioDevice *device, Uint8 *stream, Uint32 len)
    6.88 -{
    6.89 -    SDL_AudioBufferQueue *packet;
    6.90 -    Uint8 *ptr = stream;
    6.91 -
    6.92 -    while ((len > 0) && ((packet = device->buffer_queue_head) != NULL)) {
    6.93 -        const Uint32 avail = packet->datalen - packet->startpos;
    6.94 -        const Uint32 cpy = SDL_min(len, avail);
    6.95 -        SDL_assert(device->queued_bytes >= avail);
    6.96 -
    6.97 -        SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
    6.98 -        packet->startpos += cpy;
    6.99 -        ptr += cpy;
   6.100 -        device->queued_bytes -= cpy;
   6.101 -        len -= cpy;
   6.102 -
   6.103 -        if (packet->startpos == packet->datalen) {  /* packet is done, put it in the pool. */
   6.104 -            device->buffer_queue_head = packet->next;
   6.105 -            SDL_assert((packet->next != NULL) || (packet == device->buffer_queue_tail));
   6.106 -            packet->next = device->buffer_queue_pool;
   6.107 -            device->buffer_queue_pool = packet;
   6.108 -        }
   6.109 -    }
   6.110 -
   6.111 -    SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
   6.112 -
   6.113 -    if (device->buffer_queue_head == NULL) {
   6.114 -        device->buffer_queue_tail = NULL;  /* in case we drained the queue entirely. */
   6.115 -    }
   6.116 -
   6.117 -    return (Uint32) (ptr - stream);
   6.118 -}
   6.119 -
   6.120  static void SDLCALL
   6.121  SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
   6.122  {
   6.123      /* this function always holds the mixer lock before being called. */
   6.124      SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
   6.125 -    Uint32 written;
   6.126 +    size_t dequeued;
   6.127  
   6.128      SDL_assert(device != NULL);  /* this shouldn't ever happen, right?! */
   6.129      SDL_assert(!device->iscapture);  /* this shouldn't ever happen, right?! */
   6.130      SDL_assert(len >= 0);  /* this shouldn't ever happen, right?! */
   6.131  
   6.132 -    written = dequeue_audio_from_device(device, stream, (Uint32) len);
   6.133 -    stream += written;
   6.134 -    len -= (int) written;
   6.135 +    dequeued = SDL_ReadFromDataQueue(device->buffer_queue, stream, len);
   6.136 +    stream += dequeued;
   6.137 +    len -= (int) dequeued;
   6.138  
   6.139      if (len > 0) {  /* fill any remaining space in the stream with silence. */
   6.140 -        SDL_assert(device->buffer_queue_head == NULL);
   6.141 +        SDL_assert(SDL_CountDataQueue(device->buffer_queue) == 0);
   6.142          SDL_memset(stream, device->spec.silence, len);
   6.143      }
   6.144  }
   6.145 @@ -565,7 +452,7 @@
   6.146      /* note that if this needs to allocate more space and run out of memory,
   6.147         we have no choice but to quietly drop the data and hope it works out
   6.148         later, but you probably have bigger problems in this case anyhow. */
   6.149 -    queue_audio_to_device(device, stream, (Uint32) len);
   6.150 +    SDL_WriteToDataQueue(device->buffer_queue, stream, len);
   6.151  }
   6.152  
   6.153  int
   6.154 @@ -584,7 +471,7 @@
   6.155  
   6.156      if (len > 0) {
   6.157          current_audio.impl.LockDevice(device);
   6.158 -        rc = queue_audio_to_device(device, data, len);
   6.159 +        rc = SDL_WriteToDataQueue(device->buffer_queue, data, len);
   6.160          current_audio.impl.UnlockDevice(device);
   6.161      }
   6.162  
   6.163 @@ -605,7 +492,7 @@
   6.164      }
   6.165  
   6.166      current_audio.impl.LockDevice(device);
   6.167 -    rc = dequeue_audio_from_device(device, data, len);
   6.168 +    rc = (Uint32) SDL_ReadFromDataQueue(device->buffer_queue, data, len);
   6.169      current_audio.impl.UnlockDevice(device);
   6.170      return rc;
   6.171  }
   6.172 @@ -623,11 +510,11 @@
   6.173      /* Nothing to do unless we're set up for queueing. */
   6.174      if (device->spec.callback == SDL_BufferQueueDrainCallback) {
   6.175          current_audio.impl.LockDevice(device);
   6.176 -        retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device);
   6.177 +        retval = SDL_CountDataQueue(device->buffer_queue) + current_audio.impl.GetPendingBytes(device);
   6.178          current_audio.impl.UnlockDevice(device);
   6.179      } else if (device->spec.callback == SDL_BufferQueueFillCallback) {
   6.180          current_audio.impl.LockDevice(device);
   6.181 -        retval = device->queued_bytes;
   6.182 +        retval = SDL_CountDataQueue(device->buffer_queue);
   6.183          current_audio.impl.UnlockDevice(device);
   6.184      }
   6.185  
   6.186 @@ -638,7 +525,6 @@
   6.187  SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
   6.188  {
   6.189      SDL_AudioDevice *device = get_audio_device(devid);
   6.190 -    SDL_AudioBufferQueue *packet;
   6.191  
   6.192      if (!device) {
   6.193          return;  /* nothing to do. */
   6.194 @@ -647,35 +533,10 @@
   6.195      /* Blank out the device and release the mutex. Free it afterwards. */
   6.196      current_audio.impl.LockDevice(device);
   6.197  
   6.198 -    /* merge the available pool and the current queue into one list. */
   6.199 -    packet = device->buffer_queue_head;
   6.200 -    if (packet) {
   6.201 -        device->buffer_queue_tail->next = device->buffer_queue_pool;
   6.202 -    } else {
   6.203 -        packet = device->buffer_queue_pool;
   6.204 -    }
   6.205 -
   6.206 -    /* Remove the queued packets from the device. */
   6.207 -    device->buffer_queue_tail = NULL;
   6.208 -    device->buffer_queue_head = NULL;
   6.209 -    device->queued_bytes = 0;
   6.210 -    device->buffer_queue_pool = packet;
   6.211 -
   6.212      /* Keep up to two packets in the pool to reduce future malloc pressure. */
   6.213 -    if (packet) {
   6.214 -        if (!packet->next) {
   6.215 -            packet = NULL;  /* one packet (the only one) for the pool. */
   6.216 -        } else {
   6.217 -            SDL_AudioBufferQueue *next = packet->next->next;
   6.218 -            packet->next->next = NULL;  /* two packets for the pool. */
   6.219 -            packet = next;  /* rest will be freed. */
   6.220 -        }
   6.221 -    }
   6.222 +    SDL_ClearDataQueue(device->buffer_queue, SDL_AUDIOBUFFERQUEUE_PACKETLEN * 2);
   6.223  
   6.224      current_audio.impl.UnlockDevice(device);
   6.225 -
   6.226 -    /* free any extra packets we didn't keep in the pool. */
   6.227 -    free_audio_queue(packet);
   6.228  }
   6.229  
   6.230  
   6.231 @@ -1076,9 +937,7 @@
   6.232          current_audio.impl.CloseDevice(device);
   6.233      }
   6.234  
   6.235 -    free_audio_queue(device->buffer_queue_head);
   6.236 -    free_audio_queue(device->buffer_queue_pool);
   6.237 -
   6.238 +    SDL_FreeDataQueue(device->buffer_queue);
   6.239      SDL_free(device);
   6.240  }
   6.241  
   6.242 @@ -1348,19 +1207,13 @@
   6.243  
   6.244      if (device->spec.callback == NULL) {  /* use buffer queueing? */
   6.245          /* pool a few packets to start. Enough for two callbacks. */
   6.246 -        const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
   6.247 -        const int wantbytes = ((device->convert.needed) ? device->convert.len : device->spec.size) * 2;
   6.248 -        const int wantpackets = (wantbytes / packetlen) + ((wantbytes % packetlen) ? packetlen : 0);
   6.249 -        for (i = 0; i < wantpackets; i++) {
   6.250 -            SDL_AudioBufferQueue *packet = (SDL_AudioBufferQueue *) SDL_malloc(sizeof (SDL_AudioBufferQueue));
   6.251 -            if (packet) { /* don't care if this fails, we'll deal later. */
   6.252 -                packet->datalen = 0;
   6.253 -                packet->startpos = 0;
   6.254 -                packet->next = device->buffer_queue_pool;
   6.255 -                device->buffer_queue_pool = packet;
   6.256 -            }
   6.257 +        const size_t slack = ((device->convert.needed) ? device->convert.len : device->spec.size) * 2;
   6.258 +        device->buffer_queue = SDL_NewDataQueue(SDL_AUDIOBUFFERQUEUE_PACKETLEN, slack);
   6.259 +        if (!device->buffer_queue) {
   6.260 +            close_audio_device(device);
   6.261 +            SDL_SetError("Couldn't create audio buffer queue");
   6.262 +            return 0;
   6.263          }
   6.264 -
   6.265          device->spec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
   6.266          device->spec.userdata = device;
   6.267      }
     7.1 --- a/src/audio/SDL_sysaudio.h	Tue Dec 06 02:20:58 2016 -0500
     7.2 +++ b/src/audio/SDL_sysaudio.h	Tue Dec 06 02:23:54 2016 -0500
     7.3 @@ -25,6 +25,7 @@
     7.4  
     7.5  #include "SDL_mutex.h"
     7.6  #include "SDL_thread.h"
     7.7 +#include "../SDL_dataqueue.h"
     7.8  
     7.9  /* !!! FIXME: These are wordy and unlocalized... */
    7.10  #define DEFAULT_OUTPUT_DEVNAME "System audio output device"
    7.11 @@ -49,7 +50,6 @@
    7.12     as appropriate so SDL's list of devices is accurate. */
    7.13  extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
    7.14  
    7.15 -
    7.16  /* This is the size of a packet when using SDL_QueueAudio(). We allocate
    7.17     these as necessary and pool them, under the assumption that we'll
    7.18     eventually end up with a handful that keep recycling, meeting whatever
    7.19 @@ -61,15 +61,6 @@
    7.20     The system preallocates enough packets for 2 callbacks' worth of data. */
    7.21  #define SDL_AUDIOBUFFERQUEUE_PACKETLEN (8 * 1024)
    7.22  
    7.23 -/* Used by apps that queue audio instead of using the callback. */
    7.24 -typedef struct SDL_AudioBufferQueue
    7.25 -{
    7.26 -    Uint8 data[SDL_AUDIOBUFFERQUEUE_PACKETLEN];  /* packet data. */
    7.27 -    Uint32 datalen;  /* bytes currently in use in this packet. */
    7.28 -    Uint32 startpos;  /* bytes currently consumed in this packet. */
    7.29 -    struct SDL_AudioBufferQueue *next;  /* next item in linked list. */
    7.30 -} SDL_AudioBufferQueue;
    7.31 -
    7.32  typedef struct SDL_AudioDriverImpl
    7.33  {
    7.34      void (*DetectDevices) (void);
    7.35 @@ -175,10 +166,7 @@
    7.36      SDL_threadID threadid;
    7.37  
    7.38      /* Queued buffers (if app not using callback). */
    7.39 -    SDL_AudioBufferQueue *buffer_queue_head; /* device fed from here. */
    7.40 -    SDL_AudioBufferQueue *buffer_queue_tail; /* queue fills to here. */
    7.41 -    SDL_AudioBufferQueue *buffer_queue_pool; /* these are unused packets. */
    7.42 -    Uint32 queued_bytes;  /* number of bytes of audio data in the queue. */
    7.43 +    SDL_DataQueue *buffer_queue;
    7.44  
    7.45      /* * * */
    7.46      /* Data private to this driver */