]>
code.delx.au - pulseaudio/blob - src/pulsecore/memblockq.c
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include <pulse/xmalloc.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/mcalign.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/flist.h>
39 #include "memblockq.h"
42 struct list_item
*next
, *prev
;
47 PA_STATIC_FLIST_DECLARE(list_items
, 0, pa_xfree
);
50 struct list_item
*blocks
, *blocks_tail
;
51 struct list_item
*current_read
, *current_write
;
53 size_t maxlength
, tlength
, base
, prebuf
, minreq
, maxrewind
;
54 int64_t read_index
, write_index
;
58 int64_t missing
, requested
;
61 pa_memblockq
* pa_memblockq_new(
69 pa_memchunk
*silence
) {
75 bq
= pa_xnew(pa_memblockq
, 1);
76 bq
->blocks
= bq
->blocks_tail
= NULL
;
77 bq
->current_read
= bq
->current_write
= NULL
;
81 bq
->read_index
= bq
->write_index
= idx
;
83 pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
84 (unsigned long) maxlength
, (unsigned long) tlength
, (unsigned long) base
, (unsigned long) prebuf
, (unsigned long) minreq
, (unsigned long) maxrewind
);
86 bq
->missing
= bq
->requested
= 0;
87 bq
->maxlength
= bq
->tlength
= bq
->prebuf
= bq
->minreq
= bq
->maxrewind
= 0;
90 pa_memblockq_set_maxlength(bq
, maxlength
);
91 pa_memblockq_set_tlength(bq
, tlength
);
92 pa_memblockq_set_minreq(bq
, minreq
);
93 pa_memblockq_set_prebuf(bq
, prebuf
);
94 pa_memblockq_set_maxrewind(bq
, maxrewind
);
96 pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
97 (unsigned long) bq
->maxlength
, (unsigned long) bq
->tlength
, (unsigned long) bq
->base
, (unsigned long) bq
->prebuf
, (unsigned long) bq
->minreq
, (unsigned long) bq
->maxrewind
);
100 bq
->silence
= *silence
;
101 pa_memblock_ref(bq
->silence
.memblock
);
103 pa_memchunk_reset(&bq
->silence
);
105 bq
->mcalign
= pa_mcalign_new(bq
->base
);
110 void pa_memblockq_free(pa_memblockq
* bq
) {
113 pa_memblockq_silence(bq
);
115 if (bq
->silence
.memblock
)
116 pa_memblock_unref(bq
->silence
.memblock
);
119 pa_mcalign_free(bq
->mcalign
);
124 static void fix_current_read(pa_memblockq
*bq
) {
127 if (PA_UNLIKELY(!bq
->blocks
)) {
128 bq
->current_read
= NULL
;
132 if (PA_UNLIKELY(!bq
->current_read
))
133 bq
->current_read
= bq
->blocks
;
136 while (PA_UNLIKELY(bq
->current_read
->index
> bq
->read_index
))
138 if (bq
->current_read
->prev
)
139 bq
->current_read
= bq
->current_read
->prev
;
144 while (PA_LIKELY(bq
->current_read
!= NULL
) && PA_UNLIKELY(bq
->current_read
->index
+ (int64_t) bq
->current_read
->chunk
.length
<= bq
->read_index
))
145 bq
->current_read
= bq
->current_read
->next
;
147 /* At this point current_read will either point at or left of the
148 next block to play. It may be NULL in case everything in
149 the queue was already played */
152 static void fix_current_write(pa_memblockq
*bq
) {
155 if (PA_UNLIKELY(!bq
->blocks
)) {
156 bq
->current_write
= NULL
;
160 if (PA_UNLIKELY(!bq
->current_write
))
161 bq
->current_write
= bq
->blocks_tail
;
164 while (PA_UNLIKELY(bq
->current_write
->index
+ (int64_t) bq
->current_write
->chunk
.length
<= bq
->write_index
))
166 if (bq
->current_write
->next
)
167 bq
->current_write
= bq
->current_write
->next
;
172 while (PA_LIKELY(bq
->current_write
!= NULL
) && PA_UNLIKELY(bq
->current_write
->index
> bq
->write_index
))
173 bq
->current_write
= bq
->current_write
->prev
;
175 /* At this point current_write will either point at or right of
176 the next block to write data to. It may be NULL in case
177 everything in the queue is still to be played */
180 static void drop_block(pa_memblockq
*bq
, struct list_item
*q
) {
184 pa_assert(bq
->n_blocks
>= 1);
187 q
->prev
->next
= q
->next
;
189 pa_assert(bq
->blocks
== q
);
190 bq
->blocks
= q
->next
;
194 q
->next
->prev
= q
->prev
;
196 pa_assert(bq
->blocks_tail
== q
);
197 bq
->blocks_tail
= q
->prev
;
200 if (bq
->current_write
== q
)
201 bq
->current_write
= q
->prev
;
203 if (bq
->current_read
== q
)
204 bq
->current_read
= q
->next
;
206 pa_memblock_unref(q
->chunk
.memblock
);
208 if (pa_flist_push(PA_STATIC_FLIST_GET(list_items
), q
) < 0)
214 static void drop_backlog(pa_memblockq
*bq
) {
218 boundary
= bq
->read_index
- (int64_t) bq
->maxrewind
;
220 while (bq
->blocks
&& (bq
->blocks
->index
+ (int64_t) bq
->blocks
->chunk
.length
<= boundary
))
221 drop_block(bq
, bq
->blocks
);
224 static pa_bool_t
can_push(pa_memblockq
*bq
, size_t l
) {
229 if (bq
->read_index
> bq
->write_index
) {
230 int64_t d
= bq
->read_index
- bq
->write_index
;
238 end
= bq
->blocks_tail
? bq
->blocks_tail
->index
+ (int64_t) bq
->blocks_tail
->chunk
.length
: bq
->write_index
;
240 /* Make sure that the list doesn't get too long */
241 if (bq
->write_index
+ (int64_t) l
> end
)
242 if (bq
->write_index
+ (int64_t) l
- bq
->read_index
> (int64_t) bq
->maxlength
)
248 static void write_index_changed(pa_memblockq
*bq
, int64_t old_write_index
, pa_bool_t account
) {
253 delta
= bq
->write_index
- old_write_index
;
256 bq
->requested
-= delta
;
258 /* pa_log("pushed/seeked %lli: requested counter at %lli, account=%i", (long long) delta, (long long) bq->requested, account); */
261 static void read_index_changed(pa_memblockq
*bq
, int64_t old_read_index
) {
266 delta
= bq
->read_index
- old_read_index
;
267 bq
->missing
+= delta
;
269 /* pa_log("popped %lli: missing counter at %lli", (long long) delta, (long long) bq->missing); */
272 int pa_memblockq_push(pa_memblockq
* bq
, const pa_memchunk
*uchunk
) {
273 struct list_item
*q
, *n
;
279 pa_assert(uchunk
->memblock
);
280 pa_assert(uchunk
->length
> 0);
281 pa_assert(uchunk
->index
+ uchunk
->length
<= pa_memblock_get_length(uchunk
->memblock
));
283 if (uchunk
->length
% bq
->base
)
286 if (!can_push(bq
, uchunk
->length
))
289 old
= bq
->write_index
;
292 fix_current_write(bq
);
293 q
= bq
->current_write
;
295 /* First we advance the q pointer right of where we want to
299 while (bq
->write_index
+ (int64_t) chunk
.length
> q
->index
)
309 /* We go from back to front to look for the right place to add
310 * this new entry. Drop data we will overwrite on the way */
314 if (bq
->write_index
>= q
->index
+ (int64_t) q
->chunk
.length
)
315 /* We found the entry where we need to place the new entry immediately after */
317 else if (bq
->write_index
+ (int64_t) chunk
.length
<= q
->index
) {
318 /* This entry isn't touched at all, let's skip it */
320 } else if (bq
->write_index
<= q
->index
&&
321 bq
->write_index
+ (int64_t) chunk
.length
>= q
->index
+ (int64_t) q
->chunk
.length
) {
323 /* This entry is fully replaced by the new entry, so let's drop it */
329 } else if (bq
->write_index
>= q
->index
) {
330 /* The write index points into this memblock, so let's
331 * truncate or split it */
333 if (bq
->write_index
+ (int64_t) chunk
.length
< q
->index
+ (int64_t) q
->chunk
.length
) {
335 /* We need to save the end of this memchunk */
339 /* Create a new list entry for the end of thie memchunk */
340 if (!(p
= pa_flist_pop(PA_STATIC_FLIST_GET(list_items
))))
341 p
= pa_xnew(struct list_item
, 1);
344 pa_memblock_ref(p
->chunk
.memblock
);
346 /* Calculate offset */
347 d
= (size_t) (bq
->write_index
+ (int64_t) chunk
.length
- q
->index
);
350 /* Drop it from the new entry */
351 p
->index
= q
->index
+ (int64_t) d
;
352 p
->chunk
.length
-= d
;
354 /* Add it to the list */
356 if ((p
->next
= q
->next
))
365 /* Truncate the chunk */
366 if (!(q
->chunk
.length
= (size_t) (bq
->write_index
- q
->index
))) {
373 /* We had to truncate this block, hence we're now at the right position */
378 pa_assert(bq
->write_index
+ (int64_t)chunk
.length
> q
->index
&&
379 bq
->write_index
+ (int64_t)chunk
.length
< q
->index
+ (int64_t)q
->chunk
.length
&&
380 bq
->write_index
< q
->index
);
382 /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */
384 d
= (size_t) (bq
->write_index
+ (int64_t) chunk
.length
- q
->index
);
385 q
->index
+= (int64_t) d
;
387 q
->chunk
.length
-= d
;
394 pa_assert(bq
->write_index
>= q
->index
+ (int64_t)q
->chunk
.length
);
395 pa_assert(!q
->next
|| (bq
->write_index
+ (int64_t)chunk
.length
<= q
->next
->index
));
397 /* Try to merge memory blocks */
399 if (q
->chunk
.memblock
== chunk
.memblock
&&
400 q
->chunk
.index
+ q
->chunk
.length
== chunk
.index
&&
401 bq
->write_index
== q
->index
+ (int64_t) q
->chunk
.length
) {
403 q
->chunk
.length
+= chunk
.length
;
404 bq
->write_index
+= (int64_t) chunk
.length
;
408 pa_assert(!bq
->blocks
|| (bq
->write_index
+ (int64_t)chunk
.length
<= bq
->blocks
->index
));
410 if (!(n
= pa_flist_pop(PA_STATIC_FLIST_GET(list_items
))))
411 n
= pa_xnew(struct list_item
, 1);
414 pa_memblock_ref(n
->chunk
.memblock
);
415 n
->index
= bq
->write_index
;
416 bq
->write_index
+= (int64_t) n
->chunk
.length
;
418 n
->next
= q
? q
->next
: bq
->blocks
;
435 write_index_changed(bq
, old
, TRUE
);
439 pa_bool_t
pa_memblockq_prebuf_active(pa_memblockq
*bq
) {
443 return pa_memblockq_get_length(bq
) < bq
->prebuf
;
445 return bq
->prebuf
> 0 && bq
->read_index
>= bq
->write_index
;
448 static pa_bool_t
update_prebuf(pa_memblockq
*bq
) {
453 if (pa_memblockq_get_length(bq
) < bq
->prebuf
)
456 bq
->in_prebuf
= FALSE
;
460 if (bq
->prebuf
> 0 && bq
->read_index
>= bq
->write_index
) {
461 bq
->in_prebuf
= TRUE
;
469 int pa_memblockq_peek(pa_memblockq
* bq
, pa_memchunk
*chunk
) {
474 /* We need to pre-buffer */
475 if (update_prebuf(bq
))
478 fix_current_read(bq
);
480 /* Do we need to spit out silence? */
481 if (!bq
->current_read
|| bq
->current_read
->index
> bq
->read_index
) {
485 /* How much silence shall we return? */
486 if (bq
->current_read
)
487 length
= (size_t) (bq
->current_read
->index
- bq
->read_index
);
488 else if (bq
->write_index
> bq
->read_index
)
489 length
= (size_t) (bq
->write_index
- bq
->read_index
);
493 /* We need to return silence, since no data is yet available */
494 if (bq
->silence
.memblock
) {
495 *chunk
= bq
->silence
;
496 pa_memblock_ref(chunk
->memblock
);
498 if (length
> 0 && length
< chunk
->length
)
499 chunk
->length
= length
;
503 /* If the memblockq is empty, return -1, otherwise return
504 * the time to sleep */
508 chunk
->memblock
= NULL
;
509 chunk
->length
= length
;
516 /* Ok, let's pass real data to the caller */
517 *chunk
= bq
->current_read
->chunk
;
518 pa_memblock_ref(chunk
->memblock
);
520 pa_assert(bq
->read_index
>= bq
->current_read
->index
);
521 d
= bq
->read_index
- bq
->current_read
->index
;
522 chunk
->index
+= (size_t) d
;
523 chunk
->length
-= (size_t) d
;
528 void pa_memblockq_drop(pa_memblockq
*bq
, size_t length
) {
531 pa_assert(length
% bq
->base
== 0);
533 old
= bq
->read_index
;
537 /* Do not drop any data when we are in prebuffering mode */
538 if (update_prebuf(bq
))
541 fix_current_read(bq
);
543 if (bq
->current_read
) {
546 /* We go through this piece by piece to make sure we don't
547 * drop more than allowed by prebuf */
549 p
= bq
->current_read
->index
+ (int64_t) bq
->current_read
->chunk
.length
;
550 pa_assert(p
>= bq
->read_index
);
551 d
= p
- bq
->read_index
;
553 if (d
> (int64_t) length
)
554 d
= (int64_t) length
;
557 length
-= (size_t) d
;
561 /* The list is empty, there's nothing we could drop */
562 bq
->read_index
+= (int64_t) length
;
568 read_index_changed(bq
, old
);
571 void pa_memblockq_rewind(pa_memblockq
*bq
, size_t length
) {
574 pa_assert(length
% bq
->base
== 0);
576 old
= bq
->read_index
;
578 /* This is kind of the inverse of pa_memblockq_drop() */
580 bq
->read_index
-= (int64_t) length
;
582 read_index_changed(bq
, old
);
585 pa_bool_t
pa_memblockq_is_readable(pa_memblockq
*bq
) {
588 if (pa_memblockq_prebuf_active(bq
))
591 if (pa_memblockq_get_length(bq
) <= 0)
597 size_t pa_memblockq_get_length(pa_memblockq
*bq
) {
600 if (bq
->write_index
<= bq
->read_index
)
603 return (size_t) (bq
->write_index
- bq
->read_index
);
606 size_t pa_memblockq_missing(pa_memblockq
*bq
) {
610 if ((l
= pa_memblockq_get_length(bq
)) >= bq
->tlength
)
615 return l
>= bq
->minreq
? l
: 0;
618 void pa_memblockq_seek(pa_memblockq
*bq
, int64_t offset
, pa_seek_mode_t seek
, pa_bool_t account
) {
622 old
= bq
->write_index
;
625 case PA_SEEK_RELATIVE
:
626 bq
->write_index
+= offset
;
628 case PA_SEEK_ABSOLUTE
:
629 bq
->write_index
= offset
;
631 case PA_SEEK_RELATIVE_ON_READ
:
632 bq
->write_index
= bq
->read_index
+ offset
;
634 case PA_SEEK_RELATIVE_END
:
635 bq
->write_index
= (bq
->blocks_tail
? bq
->blocks_tail
->index
+ (int64_t) bq
->blocks_tail
->chunk
.length
: bq
->read_index
) + offset
;
638 pa_assert_not_reached();
642 write_index_changed(bq
, old
, account
);
645 void pa_memblockq_flush_write(pa_memblockq
*bq
) {
649 pa_memblockq_silence(bq
);
651 old
= bq
->write_index
;
652 bq
->write_index
= bq
->read_index
;
654 pa_memblockq_prebuf_force(bq
);
655 write_index_changed(bq
, old
, TRUE
);
658 void pa_memblockq_flush_read(pa_memblockq
*bq
) {
662 pa_memblockq_silence(bq
);
664 old
= bq
->read_index
;
665 bq
->read_index
= bq
->write_index
;
667 pa_memblockq_prebuf_force(bq
);
668 read_index_changed(bq
, old
);
671 size_t pa_memblockq_get_tlength(pa_memblockq
*bq
) {
677 size_t pa_memblockq_get_minreq(pa_memblockq
*bq
) {
683 size_t pa_memblockq_get_maxrewind(pa_memblockq
*bq
) {
686 return bq
->maxrewind
;
689 int64_t pa_memblockq_get_read_index(pa_memblockq
*bq
) {
692 return bq
->read_index
;
695 int64_t pa_memblockq_get_write_index(pa_memblockq
*bq
) {
698 return bq
->write_index
;
701 int pa_memblockq_push_align(pa_memblockq
* bq
, const pa_memchunk
*chunk
) {
708 return pa_memblockq_push(bq
, chunk
);
710 if (!can_push(bq
, pa_mcalign_csize(bq
->mcalign
, chunk
->length
)))
713 pa_mcalign_push(bq
->mcalign
, chunk
);
715 while (pa_mcalign_pop(bq
->mcalign
, &rchunk
) >= 0) {
717 r
= pa_memblockq_push(bq
, &rchunk
);
718 pa_memblock_unref(rchunk
.memblock
);
721 pa_mcalign_flush(bq
->mcalign
);
729 void pa_memblockq_prebuf_disable(pa_memblockq
*bq
) {
732 bq
->in_prebuf
= FALSE
;
735 void pa_memblockq_prebuf_force(pa_memblockq
*bq
) {
739 bq
->in_prebuf
= TRUE
;
742 size_t pa_memblockq_get_maxlength(pa_memblockq
*bq
) {
745 return bq
->maxlength
;
748 size_t pa_memblockq_get_prebuf(pa_memblockq
*bq
) {
754 size_t pa_memblockq_pop_missing(pa_memblockq
*bq
) {
759 /* pa_log("pop: %lli", bq->missing); */
761 if (bq
->missing
<= 0)
764 l
= (size_t) bq
->missing
;
766 bq
->requested
+= bq
->missing
;
769 /* pa_log("sent %lli: request counter is at %lli", (long long) l, (long long) bq->requested); */
774 void pa_memblockq_set_maxlength(pa_memblockq
*bq
, size_t maxlength
) {
777 bq
->maxlength
= ((maxlength
+bq
->base
-1)/bq
->base
)*bq
->base
;
779 if (bq
->maxlength
< bq
->base
)
780 bq
->maxlength
= bq
->base
;
782 if (bq
->tlength
> bq
->maxlength
)
783 pa_memblockq_set_tlength(bq
, bq
->maxlength
);
786 void pa_memblockq_set_tlength(pa_memblockq
*bq
, size_t tlength
) {
790 if (tlength
<= 0 || tlength
== (size_t) -1)
791 tlength
= bq
->maxlength
;
793 old_tlength
= bq
->tlength
;
794 bq
->tlength
= ((tlength
+bq
->base
-1)/bq
->base
)*bq
->base
;
796 if (bq
->tlength
> bq
->maxlength
)
797 bq
->tlength
= bq
->maxlength
;
799 if (bq
->minreq
> bq
->tlength
)
800 pa_memblockq_set_minreq(bq
, bq
->tlength
);
802 if (bq
->prebuf
> bq
->tlength
+bq
->base
-bq
->minreq
)
803 pa_memblockq_set_prebuf(bq
, bq
->tlength
+bq
->base
-bq
->minreq
);
805 bq
->missing
+= (int64_t) bq
->tlength
- (int64_t) old_tlength
;
808 void pa_memblockq_set_minreq(pa_memblockq
*bq
, size_t minreq
) {
811 bq
->minreq
= (minreq
/bq
->base
)*bq
->base
;
813 if (bq
->minreq
> bq
->tlength
)
814 bq
->minreq
= bq
->tlength
;
816 if (bq
->minreq
< bq
->base
)
817 bq
->minreq
= bq
->base
;
819 if (bq
->prebuf
> bq
->tlength
+bq
->base
-bq
->minreq
)
820 pa_memblockq_set_prebuf(bq
, bq
->tlength
+bq
->base
-bq
->minreq
);
823 void pa_memblockq_set_prebuf(pa_memblockq
*bq
, size_t prebuf
) {
826 if (prebuf
== (size_t) -1)
827 prebuf
= bq
->tlength
+bq
->base
-bq
->minreq
;
829 bq
->prebuf
= ((prebuf
+bq
->base
-1)/bq
->base
)*bq
->base
;
831 if (prebuf
> 0 && bq
->prebuf
< bq
->base
)
832 bq
->prebuf
= bq
->base
;
834 if (bq
->prebuf
> bq
->tlength
+bq
->base
-bq
->minreq
)
835 bq
->prebuf
= bq
->tlength
+bq
->base
-bq
->minreq
;
837 if (bq
->prebuf
<= 0 || pa_memblockq_get_length(bq
) >= bq
->prebuf
)
838 bq
->in_prebuf
= FALSE
;
841 void pa_memblockq_set_maxrewind(pa_memblockq
*bq
, size_t maxrewind
) {
844 bq
->maxrewind
= (maxrewind
/bq
->base
)*bq
->base
;
847 void pa_memblockq_apply_attr(pa_memblockq
*bq
, const pa_buffer_attr
*a
) {
851 pa_memblockq_set_maxlength(bq
, a
->maxlength
);
852 pa_memblockq_set_tlength(bq
, a
->tlength
);
853 pa_memblockq_set_prebuf(bq
, a
->prebuf
);
854 pa_memblockq_set_minreq(bq
, a
->minreq
);
857 void pa_memblockq_get_attr(pa_memblockq
*bq
, pa_buffer_attr
*a
) {
861 a
->maxlength
= (uint32_t) pa_memblockq_get_maxlength(bq
);
862 a
->tlength
= (uint32_t) pa_memblockq_get_tlength(bq
);
863 a
->prebuf
= (uint32_t) pa_memblockq_get_prebuf(bq
);
864 a
->minreq
= (uint32_t) pa_memblockq_get_minreq(bq
);
867 int pa_memblockq_splice(pa_memblockq
*bq
, pa_memblockq
*source
) {
872 pa_memblockq_prebuf_disable(bq
);
877 if (pa_memblockq_peek(source
, &chunk
) < 0)
880 pa_assert(chunk
.length
> 0);
882 if (chunk
.memblock
) {
884 if (pa_memblockq_push_align(bq
, &chunk
) < 0) {
885 pa_memblock_unref(chunk
.memblock
);
889 pa_memblock_unref(chunk
.memblock
);
891 pa_memblockq_seek(bq
, (int64_t) chunk
.length
, PA_SEEK_RELATIVE
, TRUE
);
893 pa_memblockq_drop(bq
, chunk
.length
);
897 void pa_memblockq_willneed(pa_memblockq
*bq
) {
902 fix_current_read(bq
);
904 for (q
= bq
->current_read
; q
; q
= q
->next
)
905 pa_memchunk_will_need(&q
->chunk
);
908 void pa_memblockq_set_silence(pa_memblockq
*bq
, pa_memchunk
*silence
) {
911 if (bq
->silence
.memblock
)
912 pa_memblock_unref(bq
->silence
.memblock
);
915 bq
->silence
= *silence
;
916 pa_memblock_ref(bq
->silence
.memblock
);
918 pa_memchunk_reset(&bq
->silence
);
921 pa_bool_t
pa_memblockq_is_empty(pa_memblockq
*bq
) {
927 void pa_memblockq_silence(pa_memblockq
*bq
) {
931 drop_block(bq
, bq
->blocks
);
933 pa_assert(bq
->n_blocks
== 0);
936 unsigned pa_memblockq_get_nblocks(pa_memblockq
*bq
) {
942 size_t pa_memblockq_get_base(pa_memblockq
*bq
) {