Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : :
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.
10 : :
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.
15 : :
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
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <stdio.h>
27 : : #include <stdlib.h>
28 : : #include <string.h>
29 : :
30 : : #include <pulse/xmalloc.h>
31 : : #include <pulsecore/macro.h>
32 : :
33 : : #include "mcalign.h"
34 : :
35 : : struct pa_mcalign {
36 : : size_t base;
37 : : pa_memchunk leftover, current;
38 : : };
39 : :
40 : 1 : pa_mcalign *pa_mcalign_new(size_t base) {
41 : : pa_mcalign *m;
42 [ - + ]: 1 : pa_assert(base);
43 : :
44 : 1 : m = pa_xnew(pa_mcalign, 1);
45 : :
46 : 1 : m->base = base;
47 : 1 : pa_memchunk_reset(&m->leftover);
48 : 1 : pa_memchunk_reset(&m->current);
49 : :
50 : 1 : return m;
51 : : }
52 : :
53 : 1 : void pa_mcalign_free(pa_mcalign *m) {
54 [ - + ]: 1 : pa_assert(m);
55 : :
56 [ - + ]: 1 : if (m->leftover.memblock)
57 : 0 : pa_memblock_unref(m->leftover.memblock);
58 : :
59 [ - + ]: 1 : if (m->current.memblock)
60 : 0 : pa_memblock_unref(m->current.memblock);
61 : :
62 : 1 : pa_xfree(m);
63 : 1 : }
64 : :
65 : 0 : void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
66 [ # # ]: 0 : pa_assert(m);
67 [ # # ]: 0 : pa_assert(c);
68 : :
69 [ # # ]: 0 : pa_assert(c->memblock);
70 [ # # ]: 0 : pa_assert(c->length > 0);
71 : :
72 [ # # ]: 0 : pa_assert(!m->current.memblock);
73 : :
74 : : /* Append to the leftover memory block */
75 [ # # ]: 0 : if (m->leftover.memblock) {
76 : :
77 : : /* Try to merge */
78 [ # # ][ # # ]: 0 : if (m->leftover.memblock == c->memblock &&
79 : 0 : m->leftover.index + m->leftover.length == c->index) {
80 : :
81 : : /* Merge */
82 : 0 : m->leftover.length += c->length;
83 : :
84 : : /* If the new chunk is larger than m->base, move it to current */
85 [ # # ]: 0 : if (m->leftover.length >= m->base) {
86 : 0 : m->current = m->leftover;
87 : 0 : pa_memchunk_reset(&m->leftover);
88 : : }
89 : :
90 : : } else {
91 : : size_t l;
92 : : void *lo_data, *m_data;
93 : :
94 : : /* We have to copy */
95 [ # # ]: 0 : pa_assert(m->leftover.length < m->base);
96 : 0 : l = m->base - m->leftover.length;
97 : :
98 [ # # ]: 0 : if (l > c->length)
99 : 0 : l = c->length;
100 : :
101 : : /* Can we use the current block? */
102 : 0 : pa_memchunk_make_writable(&m->leftover, m->base);
103 : :
104 : 0 : lo_data = pa_memblock_acquire(m->leftover.memblock);
105 : 0 : m_data = pa_memblock_acquire(c->memblock);
106 : 0 : memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l);
107 : 0 : pa_memblock_release(m->leftover.memblock);
108 : 0 : pa_memblock_release(c->memblock);
109 : 0 : m->leftover.length += l;
110 : :
111 [ # # ]: 0 : pa_assert(m->leftover.length <= m->base);
112 [ # # ]: 0 : pa_assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock));
113 : :
114 [ # # ]: 0 : if (c->length > l) {
115 : : /* Save the remainder of the memory block */
116 : 0 : m->current = *c;
117 : 0 : m->current.index += l;
118 : 0 : m->current.length -= l;
119 : 0 : pa_memblock_ref(m->current.memblock);
120 : : }
121 : : }
122 : : } else {
123 : : /* Nothing to merge or copy, just store it */
124 : :
125 [ # # ]: 0 : if (c->length >= m->base)
126 : 0 : m->current = *c;
127 : : else
128 : 0 : m->leftover = *c;
129 : :
130 : 0 : pa_memblock_ref(c->memblock);
131 : : }
132 : 0 : }
133 : :
134 : 0 : int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
135 [ # # ]: 0 : pa_assert(m);
136 [ # # ]: 0 : pa_assert(c);
137 : :
138 : : /* First test if there's a leftover memory block available */
139 [ # # ]: 0 : if (m->leftover.memblock) {
140 [ # # ]: 0 : pa_assert(m->leftover.length > 0);
141 [ # # ]: 0 : pa_assert(m->leftover.length <= m->base);
142 : :
143 : : /* The leftover memory block is not yet complete */
144 [ # # ]: 0 : if (m->leftover.length < m->base)
145 : : return -1;
146 : :
147 : : /* Return the leftover memory block */
148 : 0 : *c = m->leftover;
149 : 0 : pa_memchunk_reset(&m->leftover);
150 : :
151 : : /* If the current memblock is too small move it the leftover */
152 [ # # ][ # # ]: 0 : if (m->current.memblock && m->current.length < m->base) {
153 : 0 : m->leftover = m->current;
154 : 0 : pa_memchunk_reset(&m->current);
155 : : }
156 : :
157 : : return 0;
158 : : }
159 : :
160 : : /* Now let's see if there is other data available */
161 [ # # ]: 0 : if (m->current.memblock) {
162 : : size_t l;
163 [ # # ]: 0 : pa_assert(m->current.length >= m->base);
164 : :
165 : : /* The length of the returned memory block */
166 : 0 : l = m->current.length;
167 : 0 : l /= m->base;
168 : 0 : l *= m->base;
169 [ # # ]: 0 : pa_assert(l > 0);
170 : :
171 : : /* Prepare the returned block */
172 : 0 : *c = m->current;
173 : 0 : pa_memblock_ref(c->memblock);
174 : 0 : c->length = l;
175 : :
176 : : /* Drop that from the current memory block */
177 [ # # ]: 0 : pa_assert(l <= m->current.length);
178 : 0 : m->current.index += l;
179 : 0 : m->current.length -= l;
180 : :
181 : : /* In case the whole block was dropped ... */
182 [ # # ]: 0 : if (m->current.length == 0)
183 : 0 : pa_memblock_unref(m->current.memblock);
184 : : else {
185 : : /* Move the remainder to leftover */
186 [ # # ][ # # ]: 0 : pa_assert(m->current.length < m->base && !m->leftover.memblock);
187 : :
188 : 0 : m->leftover = m->current;
189 : : }
190 : :
191 : 0 : pa_memchunk_reset(&m->current);
192 : :
193 : 0 : return 0;
194 : : }
195 : :
196 : : /* There's simply nothing */
197 : : return -1;
198 : : }
199 : :
200 : 0 : size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
201 [ # # ]: 0 : pa_assert(m);
202 [ # # ]: 0 : pa_assert(l > 0);
203 : :
204 [ # # ]: 0 : pa_assert(!m->current.memblock);
205 : :
206 [ # # ]: 0 : if (m->leftover.memblock)
207 : 0 : l += m->leftover.length;
208 : :
209 : 0 : return (l/m->base)*m->base;
210 : : }
211 : :
212 : 0 : void pa_mcalign_flush(pa_mcalign *m) {
213 : : pa_memchunk chunk;
214 [ # # ]: 0 : pa_assert(m);
215 : :
216 [ # # ]: 0 : while (pa_mcalign_pop(m, &chunk) >= 0)
217 : 0 : pa_memblock_unref(chunk.memblock);
218 : 0 : }
|