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
8 published by the Free Software Foundation; either version 2.1 of the
9 License, 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 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License 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>
31 #include <pulsecore/macro.h>
37 pa_memchunk leftover
, current
;
40 pa_mcalign
*pa_mcalign_new(size_t base
) {
44 m
= pa_xnew(pa_mcalign
, 1);
47 pa_memchunk_reset(&m
->leftover
);
48 pa_memchunk_reset(&m
->current
);
53 void pa_mcalign_free(pa_mcalign
*m
) {
56 if (m
->leftover
.memblock
)
57 pa_memblock_unref(m
->leftover
.memblock
);
59 if (m
->current
.memblock
)
60 pa_memblock_unref(m
->current
.memblock
);
65 void pa_mcalign_push(pa_mcalign
*m
, const pa_memchunk
*c
) {
69 pa_assert(c
->memblock
);
70 pa_assert(c
->length
> 0);
72 pa_assert(!m
->current
.memblock
);
74 /* Append to the leftover memory block */
75 if (m
->leftover
.memblock
) {
78 if (m
->leftover
.memblock
== c
->memblock
&&
79 m
->leftover
.index
+ m
->leftover
.length
== c
->index
) {
82 m
->leftover
.length
+= c
->length
;
84 /* If the new chunk is larger than m->base, move it to current */
85 if (m
->leftover
.length
>= m
->base
) {
86 m
->current
= m
->leftover
;
87 pa_memchunk_reset(&m
->leftover
);
92 void *lo_data
, *m_data
;
95 pa_assert(m
->leftover
.length
< m
->base
);
96 l
= m
->base
- m
->leftover
.length
;
101 /* Can we use the current block? */
102 pa_memchunk_make_writable(&m
->leftover
, m
->base
);
104 lo_data
= pa_memblock_acquire(m
->leftover
.memblock
);
105 m_data
= pa_memblock_acquire(c
->memblock
);
106 memcpy((uint8_t*) lo_data
+ m
->leftover
.index
+ m
->leftover
.length
, (uint8_t*) m_data
+ c
->index
, l
);
107 pa_memblock_release(m
->leftover
.memblock
);
108 pa_memblock_release(c
->memblock
);
109 m
->leftover
.length
+= l
;
111 pa_assert(m
->leftover
.length
<= m
->base
);
112 pa_assert(m
->leftover
.length
<= pa_memblock_get_length(m
->leftover
.memblock
));
115 /* Save the remainder of the memory block */
117 m
->current
.index
+= l
;
118 m
->current
.length
-= l
;
119 pa_memblock_ref(m
->current
.memblock
);
123 /* Nothing to merge or copy, just store it */
125 if (c
->length
>= m
->base
)
130 pa_memblock_ref(c
->memblock
);
134 int pa_mcalign_pop(pa_mcalign
*m
, pa_memchunk
*c
) {
138 /* First test if there's a leftover memory block available */
139 if (m
->leftover
.memblock
) {
140 pa_assert(m
->leftover
.length
> 0);
141 pa_assert(m
->leftover
.length
<= m
->base
);
143 /* The leftover memory block is not yet complete */
144 if (m
->leftover
.length
< m
->base
)
147 /* Return the leftover memory block */
149 pa_memchunk_reset(&m
->leftover
);
151 /* If the current memblock is too small move it the leftover */
152 if (m
->current
.memblock
&& m
->current
.length
< m
->base
) {
153 m
->leftover
= m
->current
;
154 pa_memchunk_reset(&m
->current
);
160 /* Now let's see if there is other data available */
161 if (m
->current
.memblock
) {
163 pa_assert(m
->current
.length
>= m
->base
);
165 /* The length of the returned memory block */
166 l
= m
->current
.length
;
171 /* Prepare the returned block */
173 pa_memblock_ref(c
->memblock
);
176 /* Drop that from the current memory block */
177 pa_assert(l
<= m
->current
.length
);
178 m
->current
.index
+= l
;
179 m
->current
.length
-= l
;
181 /* In case the whole block was dropped ... */
182 if (m
->current
.length
== 0)
183 pa_memblock_unref(m
->current
.memblock
);
185 /* Move the raimainder to leftover */
186 pa_assert(m
->current
.length
< m
->base
&& !m
->leftover
.memblock
);
188 m
->leftover
= m
->current
;
191 pa_memchunk_reset(&m
->current
);
196 /* There's simply nothing */
200 size_t pa_mcalign_csize(pa_mcalign
*m
, size_t l
) {
204 pa_assert(!m
->current
.memblock
);
206 if (m
->leftover
.memblock
)
207 l
+= m
->leftover
.length
;
209 return (l
/m
->base
)*m
->base
;
212 void pa_mcalign_flush(pa_mcalign
*m
) {
216 while (pa_mcalign_pop(m
, &chunk
) >= 0)
217 pa_memblock_unref(chunk
.memblock
);