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, see <http://www.gnu.org/licenses/>.
28 #include <pulse/xmalloc.h>
29 #include <pulsecore/macro.h>
35 pa_memchunk leftover, current;
38 pa_mcalign *pa_mcalign_new(size_t base) {
42 m = pa_xnew(pa_mcalign, 1);
45 pa_memchunk_reset(&m->leftover);
46 pa_memchunk_reset(&m->current);
51 void pa_mcalign_free(pa_mcalign *m) {
54 if (m->leftover.memblock)
55 pa_memblock_unref(m->leftover.memblock);
57 if (m->current.memblock)
58 pa_memblock_unref(m->current.memblock);
63 void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
67 pa_assert(c->memblock);
68 pa_assert(c->length > 0);
70 pa_assert(!m->current.memblock);
72 /* Append to the leftover memory block */
73 if (m->leftover.memblock) {
76 if (m->leftover.memblock == c->memblock &&
77 m->leftover.index + m->leftover.length == c->index) {
80 m->leftover.length += c->length;
82 /* If the new chunk is larger than m->base, move it to current */
83 if (m->leftover.length >= m->base) {
84 m->current = m->leftover;
85 pa_memchunk_reset(&m->leftover);
90 void *lo_data, *m_data;
93 pa_assert(m->leftover.length < m->base);
94 l = m->base - m->leftover.length;
99 /* Can we use the current block? */
100 pa_memchunk_make_writable(&m->leftover, m->base);
102 lo_data = pa_memblock_acquire(m->leftover.memblock);
103 m_data = pa_memblock_acquire(c->memblock);
104 memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l);
105 pa_memblock_release(m->leftover.memblock);
106 pa_memblock_release(c->memblock);
107 m->leftover.length += l;
109 pa_assert(m->leftover.length <= m->base);
110 pa_assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock));
113 /* Save the remainder of the memory block */
115 m->current.index += l;
116 m->current.length -= l;
117 pa_memblock_ref(m->current.memblock);
121 /* Nothing to merge or copy, just store it */
123 if (c->length >= m->base)
128 pa_memblock_ref(c->memblock);
132 int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
136 /* First test if there's a leftover memory block available */
137 if (m->leftover.memblock) {
138 pa_assert(m->leftover.length > 0);
139 pa_assert(m->leftover.length <= m->base);
141 /* The leftover memory block is not yet complete */
142 if (m->leftover.length < m->base)
145 /* Return the leftover memory block */
147 pa_memchunk_reset(&m->leftover);
149 /* If the current memblock is too small move it the leftover */
150 if (m->current.memblock && m->current.length < m->base) {
151 m->leftover = m->current;
152 pa_memchunk_reset(&m->current);
158 /* Now let's see if there is other data available */
159 if (m->current.memblock) {
161 pa_assert(m->current.length >= m->base);
163 /* The length of the returned memory block */
164 l = m->current.length;
169 /* Prepare the returned block */
171 pa_memblock_ref(c->memblock);
174 /* Drop that from the current memory block */
175 pa_assert(l <= m->current.length);
176 m->current.index += l;
177 m->current.length -= l;
179 /* In case the whole block was dropped ... */
180 if (m->current.length == 0)
181 pa_memblock_unref(m->current.memblock);
183 /* Move the remainder to leftover */
184 pa_assert(m->current.length < m->base && !m->leftover.memblock);
186 m->leftover = m->current;
189 pa_memchunk_reset(&m->current);
194 /* There's simply nothing */
198 size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
202 pa_assert(!m->current.memblock);
204 if (m->leftover.memblock)
205 l += m->leftover.length;
207 return (l/m->base)*m->base;
210 void pa_mcalign_flush(pa_mcalign *m) {
214 while (pa_mcalign_pop(m, &chunk) >= 0)
215 pa_memblock_unref(chunk.memblock);