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
30 #include <pulse/xmalloc.h>
32 #include <pulsecore/log.h>
33 #include <pulsecore/mcalign.h>
34 #include <pulsecore/macro.h>
35 #include <pulsecore/flist.h>
37 #include "memblockq.h"
39 /* #define MEMBLOCKQ_DEBUG */
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
;
60 pa_sample_spec sample_spec
;
63 pa_memblockq
* pa_memblockq_new(
68 const pa_sample_spec
*sample_spec
,
72 pa_memchunk
*silence
) {
76 pa_assert(sample_spec
);
79 bq
= pa_xnew0(pa_memblockq
, 1);
80 bq
->name
= pa_xstrdup(name
);
82 bq
->sample_spec
= *sample_spec
;
83 bq
->base
= pa_frame_size(sample_spec
);
84 bq
->read_index
= bq
->write_index
= idx
;
86 pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
87 (unsigned long) maxlength
, (unsigned long) tlength
, (unsigned long) bq
->base
, (unsigned long) prebuf
, (unsigned long) minreq
, (unsigned long) maxrewind
);
91 pa_memblockq_set_maxlength(bq
, maxlength
);
92 pa_memblockq_set_tlength(bq
, tlength
);
93 pa_memblockq_set_minreq(bq
, minreq
);
94 pa_memblockq_set_prebuf(bq
, prebuf
);
95 pa_memblockq_set_maxrewind(bq
, maxrewind
);
97 pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
98 (unsigned long) bq
->maxlength
, (unsigned long) bq
->tlength
, (unsigned long) bq
->base
, (unsigned long) bq
->prebuf
, (unsigned long) bq
->minreq
, (unsigned long) bq
->maxrewind
);
101 bq
->silence
= *silence
;
102 pa_memblock_ref(bq
->silence
.memblock
);
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
);
125 static void fix_current_read(pa_memblockq
*bq
) {
128 if (PA_UNLIKELY(!bq
->blocks
)) {
129 bq
->current_read
= NULL
;
133 if (PA_UNLIKELY(!bq
->current_read
))
134 bq
->current_read
= bq
->blocks
;
137 while (PA_UNLIKELY(bq
->current_read
->index
> bq
->read_index
))
139 if (bq
->current_read
->prev
)
140 bq
->current_read
= bq
->current_read
->prev
;
145 while (PA_LIKELY(bq
->current_read
!= NULL
) && PA_UNLIKELY(bq
->current_read
->index
+ (int64_t) bq
->current_read
->chunk
.length
<= bq
->read_index
))
146 bq
->current_read
= bq
->current_read
->next
;
148 /* At this point current_read will either point at or left of the
149 next block to play. It may be NULL in case everything in
150 the queue was already played */
153 static void fix_current_write(pa_memblockq
*bq
) {
156 if (PA_UNLIKELY(!bq
->blocks
)) {
157 bq
->current_write
= NULL
;
161 if (PA_UNLIKELY(!bq
->current_write
))
162 bq
->current_write
= bq
->blocks_tail
;
165 while (PA_UNLIKELY(bq
->current_write
->index
+ (int64_t) bq
->current_write
->chunk
.length
<= bq
->write_index
))
167 if (bq
->current_write
->next
)
168 bq
->current_write
= bq
->current_write
->next
;
173 while (PA_LIKELY(bq
->current_write
!= NULL
) && PA_UNLIKELY(bq
->current_write
->index
> bq
->write_index
))
174 bq
->current_write
= bq
->current_write
->prev
;
176 /* At this point current_write will either point at or right of
177 the next block to write data to. It may be NULL in case
178 everything in the queue is still to be played */
181 static void drop_block(pa_memblockq
*bq
, struct list_item
*q
) {
185 pa_assert(bq
->n_blocks
>= 1);
188 q
->prev
->next
= q
->next
;
190 pa_assert(bq
->blocks
== q
);
191 bq
->blocks
= q
->next
;
195 q
->next
->prev
= q
->prev
;
197 pa_assert(bq
->blocks_tail
== q
);
198 bq
->blocks_tail
= q
->prev
;
201 if (bq
->current_write
== q
)
202 bq
->current_write
= q
->prev
;
204 if (bq
->current_read
== q
)
205 bq
->current_read
= q
->next
;
207 pa_memblock_unref(q
->chunk
.memblock
);
209 if (pa_flist_push(PA_STATIC_FLIST_GET(list_items
), q
) < 0)
215 static void drop_backlog(pa_memblockq
*bq
) {
219 boundary
= bq
->read_index
- (int64_t) bq
->maxrewind
;
221 while (bq
->blocks
&& (bq
->blocks
->index
+ (int64_t) bq
->blocks
->chunk
.length
<= boundary
))
222 drop_block(bq
, bq
->blocks
);
225 static bool can_push(pa_memblockq
*bq
, size_t l
) {
230 if (bq
->read_index
> bq
->write_index
) {
231 int64_t d
= bq
->read_index
- bq
->write_index
;
239 end
= bq
->blocks_tail
? bq
->blocks_tail
->index
+ (int64_t) bq
->blocks_tail
->chunk
.length
: bq
->write_index
;
241 /* Make sure that the list doesn't get too long */
242 if (bq
->write_index
+ (int64_t) l
> end
)
243 if (bq
->write_index
+ (int64_t) l
- bq
->read_index
> (int64_t) bq
->maxlength
)
249 static void write_index_changed(pa_memblockq
*bq
, int64_t old_write_index
, bool account
) {
254 delta
= bq
->write_index
- old_write_index
;
257 bq
->requested
-= delta
;
259 bq
->missing
-= delta
;
261 #ifdef MEMBLOCKQ_DEBUG
262 pa_log_debug("[%s] pushed/seeked %lli: requested counter at %lli, account=%i", bq
->name
, (long long) delta
, (long long) bq
->requested
, account
);
266 static void read_index_changed(pa_memblockq
*bq
, int64_t old_read_index
) {
271 delta
= bq
->read_index
- old_read_index
;
272 bq
->missing
+= delta
;
274 #ifdef MEMBLOCKQ_DEBUG
275 pa_log_debug("[%s] popped %lli: missing counter at %lli", bq
->name
, (long long) delta
, (long long) bq
->missing
);
279 int pa_memblockq_push(pa_memblockq
* bq
, const pa_memchunk
*uchunk
) {
280 struct list_item
*q
, *n
;
286 pa_assert(uchunk
->memblock
);
287 pa_assert(uchunk
->length
> 0);
288 pa_assert(uchunk
->index
+ uchunk
->length
<= pa_memblock_get_length(uchunk
->memblock
));
290 pa_assert_se(uchunk
->length
% bq
->base
== 0);
292 if (!can_push(bq
, uchunk
->length
))
295 old
= bq
->write_index
;
298 fix_current_write(bq
);
299 q
= bq
->current_write
;
301 /* First we advance the q pointer right of where we want to
305 while (bq
->write_index
+ (int64_t) chunk
.length
> q
->index
)
315 /* We go from back to front to look for the right place to add
316 * this new entry. Drop data we will overwrite on the way */
320 if (bq
->write_index
>= q
->index
+ (int64_t) q
->chunk
.length
)
321 /* We found the entry where we need to place the new entry immediately after */
323 else if (bq
->write_index
+ (int64_t) chunk
.length
<= q
->index
) {
324 /* This entry isn't touched at all, let's skip it */
326 } else if (bq
->write_index
<= q
->index
&&
327 bq
->write_index
+ (int64_t) chunk
.length
>= q
->index
+ (int64_t) q
->chunk
.length
) {
329 /* This entry is fully replaced by the new entry, so let's drop it */
335 } else if (bq
->write_index
>= q
->index
) {
336 /* The write index points into this memblock, so let's
337 * truncate or split it */
339 if (bq
->write_index
+ (int64_t) chunk
.length
< q
->index
+ (int64_t) q
->chunk
.length
) {
341 /* We need to save the end of this memchunk */
345 /* Create a new list entry for the end of the memchunk */
346 if (!(p
= pa_flist_pop(PA_STATIC_FLIST_GET(list_items
))))
347 p
= pa_xnew(struct list_item
, 1);
350 pa_memblock_ref(p
->chunk
.memblock
);
352 /* Calculate offset */
353 d
= (size_t) (bq
->write_index
+ (int64_t) chunk
.length
- q
->index
);
356 /* Drop it from the new entry */
357 p
->index
= q
->index
+ (int64_t) d
;
358 p
->chunk
.length
-= d
;
360 /* Add it to the list */
362 if ((p
->next
= q
->next
))
371 /* Truncate the chunk */
372 if (!(q
->chunk
.length
= (size_t) (bq
->write_index
- q
->index
))) {
379 /* We had to truncate this block, hence we're now at the right position */
384 pa_assert(bq
->write_index
+ (int64_t)chunk
.length
> q
->index
&&
385 bq
->write_index
+ (int64_t)chunk
.length
< q
->index
+ (int64_t)q
->chunk
.length
&&
386 bq
->write_index
< q
->index
);
388 /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */
390 d
= (size_t) (bq
->write_index
+ (int64_t) chunk
.length
- q
->index
);
391 q
->index
+= (int64_t) d
;
393 q
->chunk
.length
-= d
;
400 pa_assert(bq
->write_index
>= q
->index
+ (int64_t)q
->chunk
.length
);
401 pa_assert(!q
->next
|| (bq
->write_index
+ (int64_t)chunk
.length
<= q
->next
->index
));
403 /* Try to merge memory blocks */
405 if (q
->chunk
.memblock
== chunk
.memblock
&&
406 q
->chunk
.index
+ q
->chunk
.length
== chunk
.index
&&
407 bq
->write_index
== q
->index
+ (int64_t) q
->chunk
.length
) {
409 q
->chunk
.length
+= chunk
.length
;
410 bq
->write_index
+= (int64_t) chunk
.length
;
414 pa_assert(!bq
->blocks
|| (bq
->write_index
+ (int64_t)chunk
.length
<= bq
->blocks
->index
));
416 if (!(n
= pa_flist_pop(PA_STATIC_FLIST_GET(list_items
))))
417 n
= pa_xnew(struct list_item
, 1);
420 pa_memblock_ref(n
->chunk
.memblock
);
421 n
->index
= bq
->write_index
;
422 bq
->write_index
+= (int64_t) n
->chunk
.length
;
424 n
->next
= q
? q
->next
: bq
->blocks
;
441 write_index_changed(bq
, old
, true);
445 bool pa_memblockq_prebuf_active(pa_memblockq
*bq
) {
449 return pa_memblockq_get_length(bq
) < bq
->prebuf
;
451 return bq
->prebuf
> 0 && bq
->read_index
>= bq
->write_index
;
454 static bool update_prebuf(pa_memblockq
*bq
) {
459 if (pa_memblockq_get_length(bq
) < bq
->prebuf
)
462 bq
->in_prebuf
= false;
466 if (bq
->prebuf
> 0 && bq
->read_index
>= bq
->write_index
) {
467 bq
->in_prebuf
= true;
475 int pa_memblockq_peek(pa_memblockq
* bq
, pa_memchunk
*chunk
) {
480 /* We need to pre-buffer */
481 if (update_prebuf(bq
))
484 fix_current_read(bq
);
486 /* Do we need to spit out silence? */
487 if (!bq
->current_read
|| bq
->current_read
->index
> bq
->read_index
) {
490 /* How much silence shall we return? */
491 if (bq
->current_read
)
492 length
= (size_t) (bq
->current_read
->index
- bq
->read_index
);
493 else if (bq
->write_index
> bq
->read_index
)
494 length
= (size_t) (bq
->write_index
- bq
->read_index
);
498 /* We need to return silence, since no data is yet available */
499 if (bq
->silence
.memblock
) {
500 *chunk
= bq
->silence
;
501 pa_memblock_ref(chunk
->memblock
);
503 if (length
> 0 && length
< chunk
->length
)
504 chunk
->length
= length
;
508 /* If the memblockq is empty, return -1, otherwise return
509 * the time to sleep */
513 chunk
->memblock
= NULL
;
514 chunk
->length
= length
;
521 /* Ok, let's pass real data to the caller */
522 *chunk
= bq
->current_read
->chunk
;
523 pa_memblock_ref(chunk
->memblock
);
525 pa_assert(bq
->read_index
>= bq
->current_read
->index
);
526 d
= bq
->read_index
- bq
->current_read
->index
;
527 chunk
->index
+= (size_t) d
;
528 chunk
->length
-= (size_t) d
;
533 int pa_memblockq_peek_fixed_size(pa_memblockq
*bq
, size_t block_size
, pa_memchunk
*chunk
) {
534 pa_memchunk tchunk
, rchunk
;
536 struct list_item
*item
;
539 pa_assert(block_size
> 0);
541 pa_assert(bq
->silence
.memblock
);
543 if (pa_memblockq_peek(bq
, &tchunk
) < 0)
546 if (tchunk
.length
>= block_size
) {
548 chunk
->length
= block_size
;
552 rchunk
.memblock
= pa_memblock_new(pa_memblock_get_pool(tchunk
.memblock
), block_size
);
554 rchunk
.length
= tchunk
.length
;
556 pa_memchunk_memcpy(&rchunk
, &tchunk
);
557 pa_memblock_unref(tchunk
.memblock
);
559 rchunk
.index
+= tchunk
.length
;
561 /* We don't need to call fix_current_read() here, since
562 * pa_memblock_peek() already did that */
563 item
= bq
->current_read
;
564 ri
= bq
->read_index
+ tchunk
.length
;
566 while (rchunk
.index
< block_size
) {
568 if (!item
|| item
->index
> ri
) {
569 /* Do we need to append silence? */
570 tchunk
= bq
->silence
;
573 tchunk
.length
= PA_MIN(tchunk
.length
, (size_t) (item
->index
- ri
));
578 /* We can append real data! */
579 tchunk
= item
->chunk
;
581 d
= ri
- item
->index
;
582 tchunk
.index
+= (size_t) d
;
583 tchunk
.length
-= (size_t) d
;
585 /* Go to next item for the next iteration */
589 rchunk
.length
= tchunk
.length
= PA_MIN(tchunk
.length
, block_size
- rchunk
.index
);
590 pa_memchunk_memcpy(&rchunk
, &tchunk
);
592 rchunk
.index
+= rchunk
.length
;
597 rchunk
.length
= block_size
;
603 void pa_memblockq_drop(pa_memblockq
*bq
, size_t length
) {
606 pa_assert(length
% bq
->base
== 0);
608 old
= bq
->read_index
;
612 /* Do not drop any data when we are in prebuffering mode */
613 if (update_prebuf(bq
))
616 fix_current_read(bq
);
618 if (bq
->current_read
) {
621 /* We go through this piece by piece to make sure we don't
622 * drop more than allowed by prebuf */
624 p
= bq
->current_read
->index
+ (int64_t) bq
->current_read
->chunk
.length
;
625 pa_assert(p
>= bq
->read_index
);
626 d
= p
- bq
->read_index
;
628 if (d
> (int64_t) length
)
629 d
= (int64_t) length
;
632 length
-= (size_t) d
;
636 /* The list is empty, there's nothing we could drop */
637 bq
->read_index
+= (int64_t) length
;
643 read_index_changed(bq
, old
);
646 void pa_memblockq_rewind(pa_memblockq
*bq
, size_t length
) {
649 pa_assert(length
% bq
->base
== 0);
651 old
= bq
->read_index
;
653 /* This is kind of the inverse of pa_memblockq_drop() */
655 bq
->read_index
-= (int64_t) length
;
657 read_index_changed(bq
, old
);
660 bool pa_memblockq_is_readable(pa_memblockq
*bq
) {
663 if (pa_memblockq_prebuf_active(bq
))
666 if (pa_memblockq_get_length(bq
) <= 0)
672 size_t pa_memblockq_get_length(pa_memblockq
*bq
) {
675 if (bq
->write_index
<= bq
->read_index
)
678 return (size_t) (bq
->write_index
- bq
->read_index
);
681 size_t pa_memblockq_missing(pa_memblockq
*bq
) {
685 if ((l
= pa_memblockq_get_length(bq
)) >= bq
->tlength
)
690 return l
>= bq
->minreq
? l
: 0;
693 void pa_memblockq_seek(pa_memblockq
*bq
, int64_t offset
, pa_seek_mode_t seek
, bool account
) {
697 old
= bq
->write_index
;
700 case PA_SEEK_RELATIVE
:
701 bq
->write_index
+= offset
;
703 case PA_SEEK_ABSOLUTE
:
704 bq
->write_index
= offset
;
706 case PA_SEEK_RELATIVE_ON_READ
:
707 bq
->write_index
= bq
->read_index
+ offset
;
709 case PA_SEEK_RELATIVE_END
:
710 bq
->write_index
= (bq
->blocks_tail
? bq
->blocks_tail
->index
+ (int64_t) bq
->blocks_tail
->chunk
.length
: bq
->read_index
) + offset
;
713 pa_assert_not_reached();
717 write_index_changed(bq
, old
, account
);
720 void pa_memblockq_flush_write(pa_memblockq
*bq
, bool account
) {
724 pa_memblockq_silence(bq
);
726 old
= bq
->write_index
;
727 bq
->write_index
= bq
->read_index
;
729 pa_memblockq_prebuf_force(bq
);
730 write_index_changed(bq
, old
, account
);
733 void pa_memblockq_flush_read(pa_memblockq
*bq
) {
737 pa_memblockq_silence(bq
);
739 old
= bq
->read_index
;
740 bq
->read_index
= bq
->write_index
;
742 pa_memblockq_prebuf_force(bq
);
743 read_index_changed(bq
, old
);
746 size_t pa_memblockq_get_tlength(pa_memblockq
*bq
) {
752 size_t pa_memblockq_get_minreq(pa_memblockq
*bq
) {
758 size_t pa_memblockq_get_maxrewind(pa_memblockq
*bq
) {
761 return bq
->maxrewind
;
764 int64_t pa_memblockq_get_read_index(pa_memblockq
*bq
) {
767 return bq
->read_index
;
770 int64_t pa_memblockq_get_write_index(pa_memblockq
*bq
) {
773 return bq
->write_index
;
776 int pa_memblockq_push_align(pa_memblockq
* bq
, const pa_memchunk
*chunk
) {
783 return pa_memblockq_push(bq
, chunk
);
785 if (!can_push(bq
, pa_mcalign_csize(bq
->mcalign
, chunk
->length
)))
788 pa_mcalign_push(bq
->mcalign
, chunk
);
790 while (pa_mcalign_pop(bq
->mcalign
, &rchunk
) >= 0) {
792 r
= pa_memblockq_push(bq
, &rchunk
);
793 pa_memblock_unref(rchunk
.memblock
);
796 pa_mcalign_flush(bq
->mcalign
);
804 void pa_memblockq_prebuf_disable(pa_memblockq
*bq
) {
807 bq
->in_prebuf
= false;
810 void pa_memblockq_prebuf_force(pa_memblockq
*bq
) {
814 bq
->in_prebuf
= true;
817 size_t pa_memblockq_get_maxlength(pa_memblockq
*bq
) {
820 return bq
->maxlength
;
823 size_t pa_memblockq_get_prebuf(pa_memblockq
*bq
) {
829 size_t pa_memblockq_pop_missing(pa_memblockq
*bq
) {
834 #ifdef MEMBLOCKQ_DEBUG
835 pa_log_debug("[%s] pop: %lli", bq
->name
, (long long) bq
->missing
);
838 if (bq
->missing
<= 0)
841 l
= (size_t) bq
->missing
;
843 bq
->requested
+= bq
->missing
;
846 #ifdef MEMBLOCKQ_DEBUG
847 pa_log_debug("[%s] sent %lli: request counter is at %lli", bq
->name
, (long long) l
, (long long) bq
->requested
);
853 void pa_memblockq_set_maxlength(pa_memblockq
*bq
, size_t maxlength
) {
856 bq
->maxlength
= ((maxlength
+bq
->base
-1)/bq
->base
)*bq
->base
;
858 if (bq
->maxlength
< bq
->base
)
859 bq
->maxlength
= bq
->base
;
861 if (bq
->tlength
> bq
->maxlength
)
862 pa_memblockq_set_tlength(bq
, bq
->maxlength
);
865 void pa_memblockq_set_tlength(pa_memblockq
*bq
, size_t tlength
) {
869 if (tlength
<= 0 || tlength
== (size_t) -1)
870 tlength
= bq
->maxlength
;
872 old_tlength
= bq
->tlength
;
873 bq
->tlength
= ((tlength
+bq
->base
-1)/bq
->base
)*bq
->base
;
875 if (bq
->tlength
> bq
->maxlength
)
876 bq
->tlength
= bq
->maxlength
;
878 if (bq
->minreq
> bq
->tlength
)
879 pa_memblockq_set_minreq(bq
, bq
->tlength
);
881 if (bq
->prebuf
> bq
->tlength
+bq
->base
-bq
->minreq
)
882 pa_memblockq_set_prebuf(bq
, bq
->tlength
+bq
->base
-bq
->minreq
);
884 bq
->missing
+= (int64_t) bq
->tlength
- (int64_t) old_tlength
;
887 void pa_memblockq_set_minreq(pa_memblockq
*bq
, size_t minreq
) {
890 bq
->minreq
= (minreq
/bq
->base
)*bq
->base
;
892 if (bq
->minreq
> bq
->tlength
)
893 bq
->minreq
= bq
->tlength
;
895 if (bq
->minreq
< bq
->base
)
896 bq
->minreq
= bq
->base
;
898 if (bq
->prebuf
> bq
->tlength
+bq
->base
-bq
->minreq
)
899 pa_memblockq_set_prebuf(bq
, bq
->tlength
+bq
->base
-bq
->minreq
);
902 void pa_memblockq_set_prebuf(pa_memblockq
*bq
, size_t prebuf
) {
905 if (prebuf
== (size_t) -1)
906 prebuf
= bq
->tlength
+bq
->base
-bq
->minreq
;
908 bq
->prebuf
= ((prebuf
+bq
->base
-1)/bq
->base
)*bq
->base
;
910 if (prebuf
> 0 && bq
->prebuf
< bq
->base
)
911 bq
->prebuf
= bq
->base
;
913 if (bq
->prebuf
> bq
->tlength
+bq
->base
-bq
->minreq
)
914 bq
->prebuf
= bq
->tlength
+bq
->base
-bq
->minreq
;
916 if (bq
->prebuf
<= 0 || pa_memblockq_get_length(bq
) >= bq
->prebuf
)
917 bq
->in_prebuf
= false;
920 void pa_memblockq_set_maxrewind(pa_memblockq
*bq
, size_t maxrewind
) {
923 bq
->maxrewind
= (maxrewind
/bq
->base
)*bq
->base
;
926 void pa_memblockq_apply_attr(pa_memblockq
*bq
, const pa_buffer_attr
*a
) {
930 pa_memblockq_set_maxlength(bq
, a
->maxlength
);
931 pa_memblockq_set_tlength(bq
, a
->tlength
);
932 pa_memblockq_set_minreq(bq
, a
->minreq
);
933 pa_memblockq_set_prebuf(bq
, a
->prebuf
);
936 void pa_memblockq_get_attr(pa_memblockq
*bq
, pa_buffer_attr
*a
) {
940 a
->maxlength
= (uint32_t) pa_memblockq_get_maxlength(bq
);
941 a
->tlength
= (uint32_t) pa_memblockq_get_tlength(bq
);
942 a
->prebuf
= (uint32_t) pa_memblockq_get_prebuf(bq
);
943 a
->minreq
= (uint32_t) pa_memblockq_get_minreq(bq
);
946 int pa_memblockq_splice(pa_memblockq
*bq
, pa_memblockq
*source
) {
951 pa_memblockq_prebuf_disable(bq
);
956 if (pa_memblockq_peek(source
, &chunk
) < 0)
959 pa_assert(chunk
.length
> 0);
961 if (chunk
.memblock
) {
963 if (pa_memblockq_push_align(bq
, &chunk
) < 0) {
964 pa_memblock_unref(chunk
.memblock
);
968 pa_memblock_unref(chunk
.memblock
);
970 pa_memblockq_seek(bq
, (int64_t) chunk
.length
, PA_SEEK_RELATIVE
, true);
972 pa_memblockq_drop(bq
, chunk
.length
);
976 void pa_memblockq_willneed(pa_memblockq
*bq
) {
981 fix_current_read(bq
);
983 for (q
= bq
->current_read
; q
; q
= q
->next
)
984 pa_memchunk_will_need(&q
->chunk
);
987 void pa_memblockq_set_silence(pa_memblockq
*bq
, pa_memchunk
*silence
) {
990 if (bq
->silence
.memblock
)
991 pa_memblock_unref(bq
->silence
.memblock
);
994 bq
->silence
= *silence
;
995 pa_memblock_ref(bq
->silence
.memblock
);
997 pa_memchunk_reset(&bq
->silence
);
1000 bool pa_memblockq_is_empty(pa_memblockq
*bq
) {
1006 void pa_memblockq_silence(pa_memblockq
*bq
) {
1010 drop_block(bq
, bq
->blocks
);
1012 pa_assert(bq
->n_blocks
== 0);
1015 unsigned pa_memblockq_get_nblocks(pa_memblockq
*bq
) {
1018 return bq
->n_blocks
;
1021 size_t pa_memblockq_get_base(pa_memblockq
*bq
) {