10 struct memblock_list *next;
11 struct pa_memchunk chunk;
16 struct memblock_list *blocks, *blocks_tail;
18 size_t current_length, maxlength, tlength, base, prebuf, minreq;
21 struct pa_mcalign *mcalign;
24 struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq) {
25 struct pa_memblockq* bq;
26 assert(maxlength && base && maxlength);
28 bq = malloc(sizeof(struct pa_memblockq));
30 bq->blocks = bq->blocks_tail = 0;
33 bq->current_length = 0;
35 fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq);
39 bq->maxlength = ((maxlength+base-1)/base)*base;
40 assert(bq->maxlength >= base);
42 bq->tlength = ((tlength+base-1)/base)*base;
43 if (bq->tlength == 0 || bq->tlength >= bq->maxlength)
44 bq->tlength = bq->maxlength;
46 bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf;
47 bq->prebuf = (bq->prebuf/base)*base;
48 if (bq->prebuf > bq->maxlength)
49 bq->prebuf = bq->maxlength;
51 bq->minreq = (minreq/base)*base;
55 fprintf(stderr, "memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq);
57 bq->measure_delay = 0;
65 void pa_memblockq_free(struct pa_memblockq* bq) {
66 struct memblock_list *l;
70 pa_mcalign_free(bq->mcalign);
72 while ((l = bq->blocks)) {
74 pa_memblock_unref(l->chunk.memblock);
81 void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) {
82 struct memblock_list *q;
83 assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0);
85 q = malloc(sizeof(struct memblock_list));
88 if (bq->measure_delay)
89 gettimeofday(&q->stamp, NULL);
91 timerclear(&q->stamp);
94 pa_memblock_ref(q->chunk.memblock);
95 assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length);
99 bq->blocks_tail->next = q;
106 bq->current_length += chunk->length;
108 pa_memblockq_shorten(bq, bq->maxlength);
111 int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) {
114 if (!bq->blocks || bq->current_length < bq->prebuf)
119 *chunk = bq->blocks->chunk;
120 pa_memblock_ref(chunk->memblock);
122 /* if (chunk->memblock->ref != 2) */
123 /* fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); */
129 int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) {
130 struct memblock_list *q;
134 if (!bq->blocks || bq->current_length < bq->prebuf)
140 bq->blocks = bq->blocks->next;
145 bq->current_length -= chunk->length;
152 static uint32_t age(struct timeval *tv) {
160 gettimeofday(&now, NULL);
162 r = (now.tv_sec-tv->tv_sec) * 1000000;
164 if (now.tv_usec >= tv->tv_usec)
165 r += now.tv_usec - tv->tv_usec;
167 r -= tv->tv_usec - now.tv_usec;
172 void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) {
173 assert(bq && length && (length % bq->base) == 0);
177 assert(bq->blocks && bq->current_length >= length);
179 if (l > bq->blocks->chunk.length)
180 l = bq->blocks->chunk.length;
182 if (bq->measure_delay)
183 bq->delay = age(&bq->blocks->stamp);
185 bq->blocks->chunk.index += l;
186 bq->blocks->chunk.length -= l;
187 bq->current_length -= l;
189 if (bq->blocks->chunk.length == 0) {
190 struct memblock_list *q;
193 bq->blocks = bq->blocks->next;
194 if (bq->blocks == NULL)
195 bq->blocks_tail = NULL;
196 pa_memblock_unref(q->chunk.memblock);
206 void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) {
210 if (bq->current_length <= length)
213 fprintf(stderr, "Warning! pa_memblockq_shorten()\n");
215 l = bq->current_length - length;
219 pa_memblockq_drop(bq, l);
223 void pa_memblockq_empty(struct pa_memblockq *bq) {
225 pa_memblockq_shorten(bq, 0);
228 int pa_memblockq_is_readable(struct pa_memblockq *bq) {
231 return bq->current_length && (bq->current_length >= bq->prebuf);
234 int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) {
237 return bq->current_length + length <= bq->tlength;
240 uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) {
245 uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) {
247 return bq->current_length;
250 uint32_t pa_memblockq_missing(struct pa_memblockq *bq) {
254 if (bq->current_length >= bq->tlength)
257 l = bq->tlength - bq->current_length;
260 return (l >= bq->minreq) ? l : 0;
263 void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) {
264 struct pa_memchunk rchunk;
265 assert(bq && chunk && bq->base);
268 pa_memblockq_push(bq, chunk, delta);
273 bq->mcalign = pa_mcalign_new(bq->base);
277 pa_mcalign_push(bq->mcalign, chunk);
279 while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) {
280 pa_memblockq_push(bq, &rchunk, delta);
281 pa_memblock_unref(rchunk.memblock);
286 uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq) {