Revert r1404 and keep it on a development branch until it is fully tested.
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / mcalign.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
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 <assert.h>
29 #include <string.h>
30
31 #include <pulse/xmalloc.h>
32
33 #include "mcalign.h"
34
35 struct pa_mcalign {
36     size_t base;
37     pa_memchunk leftover, current;
38 };
39
40 pa_mcalign *pa_mcalign_new(size_t base) {
41     pa_mcalign *m;
42     assert(base);
43
44     m = pa_xnew(pa_mcalign, 1);
45     
46     m->base = base;
47     pa_memchunk_reset(&m->leftover);
48     pa_memchunk_reset(&m->current);
49     
50     return m;
51 }
52
53 void pa_mcalign_free(pa_mcalign *m) {
54     assert(m);
55
56     if (m->leftover.memblock)
57         pa_memblock_unref(m->leftover.memblock);
58
59     if (m->current.memblock)
60         pa_memblock_unref(m->current.memblock);
61     
62     pa_xfree(m);
63 }
64
65 void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
66     assert(m);
67     assert(c);
68     
69     assert(c->memblock);
70     assert(c->length > 0);
71
72     assert(!m->current.memblock);
73     
74     /* Append to the leftover memory block */
75     if (m->leftover.memblock) {
76         
77         /* Try to merge */
78         if (m->leftover.memblock == c->memblock &&
79             m->leftover.index + m->leftover.length == c->index) {
80
81             /* Merge */
82             m->leftover.length += c->length;
83
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);
88             } 
89
90         } else {
91             size_t l;
92
93             /* We have to copy */
94             assert(m->leftover.length < m->base);
95             l = m->base - m->leftover.length;
96             
97             if (l > c->length)
98                 l = c->length;
99
100             /* Can we use the current block? */
101             pa_memchunk_make_writable(&m->leftover, m->base);
102
103             memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l);
104             m->leftover.length += l;
105
106             assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length);
107
108             if (c->length > l) {
109                 /* Save the remainder of the memory block */
110                 m->current = *c;
111                 m->current.index += l;
112                 m->current.length -= l;
113                 pa_memblock_ref(m->current.memblock);
114             }
115         }
116     } else {
117         /* Nothing to merge or copy, just store it */
118         
119         if (c->length >= m->base)
120             m->current = *c;
121         else
122             m->leftover = *c;
123
124         pa_memblock_ref(c->memblock);
125     }
126 }
127
128 int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
129     assert(m);
130     assert(c);
131
132     /* First test if there's a leftover memory block available */
133     if (m->leftover.memblock) {
134         assert(m->leftover.length > 0 && m->leftover.length <= m->base);
135
136         /* The leftover memory block is not yet complete */
137         if (m->leftover.length < m->base)
138             return -1;
139
140         /* Return the leftover memory block */
141         *c = m->leftover;
142         pa_memchunk_reset(&m->leftover);
143
144         /* If the current memblock is too small move it the leftover */
145         if (m->current.memblock && m->current.length < m->base) {
146             m->leftover = m->current;
147             pa_memchunk_reset(&m->current);
148         }
149         
150         return 0;
151     }
152
153     /* Now let's see if there is other data available */
154     if (m->current.memblock) {
155         size_t l;
156         assert(m->current.length >= m->base);
157
158         /* The length of the returned memory block */
159         l = m->current.length;
160         l /= m->base;
161         l *= m->base;
162         assert(l > 0);
163
164         /* Prepare the returned block */
165         *c = m->current;
166         pa_memblock_ref(c->memblock);
167         c->length = l;
168
169         /* Drop that from the current memory block */
170         assert(l <= m->current.length);
171         m->current.index += l;
172         m->current.length -= l;
173
174         /* In case the whole block was dropped ... */
175         if (m->current.length == 0)
176             pa_memblock_unref(m->current.memblock);
177         else {
178             /* Move the raimainder to leftover */
179             assert(m->current.length < m->base && !m->leftover.memblock);
180
181             m->leftover = m->current;
182         }
183
184         pa_memchunk_reset(&m->current);
185             
186         return 0;
187     }
188
189     /* There's simply nothing */
190     return -1;
191     
192 }
193
194 size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
195     assert(m);
196     assert(l > 0);
197
198     assert(!m->current.memblock);
199            
200     if (m->leftover.memblock)
201         l += m->leftover.length;
202     
203     return (l/m->base)*m->base;
204 }