source: roaraudio/libroar/buffer.c @ 3811:49db840fb4f4

Last change on this file since 3811:49db840fb4f4 was 3811:49db840fb4f4, checked in by phi, 14 years ago

fixed some copyright statements

File size: 11.1 KB
Line 
1//buffer.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2010
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38// TODO: convert this to a macro.
39// TODO: but still provide a function->symbol
40// TODO: so we do not need to change SONAME-Version
41// TODO: Clean this up in next SONAME-Version
42int roar_buffer_new      (struct roar_buffer ** buf, size_t len) {
43 return roar_buffer_new_data(buf, len, NULL);
44}
45
46int roar_buffer_new_data (struct roar_buffer ** buf, size_t len, void ** data) {
47 void * bufdata;
48
49 if ((bufdata = roar_mm_malloc(len)) == NULL) {
50  return -1;
51 }
52
53 if ( roar_buffer_new_no_ma(buf, len, bufdata) == -1 ) {
54  roar_mm_free(bufdata);
55  return -1;
56 }
57
58 if ( roar_buffer_set_flag(*buf, ROAR_BUFFER_FLAG_NOFREE, ROAR_BUFFER_RESET) == -1 ) {
59  roar_buffer_free(*buf);
60  roar_mm_free(bufdata);
61  return -1;
62 }
63
64 if ( data != NULL )
65  *data = bufdata;
66
67 return 0;
68}
69
70int roar_buffer_new_no_ma(struct roar_buffer ** buf, size_t len, void * data) { // no internal malloc
71 struct roar_buffer * new;
72
73 ROAR_DBG("buffer_new(buf=%p, len=%i) = ?", buf, len);
74
75 if ( buf == NULL || data == NULL )
76  return -1;
77
78 if ((new = roar_mm_malloc(sizeof(struct roar_buffer))) == NULL) {
79  *buf = NULL;
80  return -1;
81 }
82
83 new->data      = data;
84
85 new->flags     = ROAR_BUFFER_FLAG_NONE|ROAR_BUFFER_FLAG_NOFREE;
86
87 new->user_data = new->data;
88
89 new->next      = NULL;
90
91 new->len       = len;
92 new->user_len  = len;
93 *buf           = new;
94
95 ROAR_DBG("buffer_new(buf=%p, len=%i): New buffer at %p", buf, len, new);
96
97 return 0;
98}
99
100int roar_buffer_free     (struct roar_buffer * buf) {
101 struct roar_buffer * next;
102
103 if ( buf == NULL )
104  return -1;
105
106 while ((next = buf->next)) {
107  if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
108   roar_mm_free(buf->data);
109
110  roar_mm_free(buf);
111  buf = next;
112 }
113
114 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
115  roar_mm_free(buf->data);
116
117 roar_mm_free(buf);
118
119 return 0;
120}
121
122int roar_buffer_delete   (struct roar_buffer * buf, struct roar_buffer ** next) {
123 if ( buf == NULL ) {
124  if ( next != NULL )
125   *next = NULL;
126  return -1;
127 }
128
129 ROAR_DBG("buffer_delete(buf=%p, next=%p) = ?", buf, next);
130
131 if ( next != NULL )
132  *next = buf->next;
133
134 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
135  roar_mm_free(buf->data);
136
137 roar_mm_free(buf);
138
139 ROAR_DBG("buffer_delete(buf=%p, next=%p) = 0", buf, next);
140 return 0;
141}
142
143int roar_buffer_add      (struct roar_buffer * buf, struct roar_buffer *  next) {
144 unsigned int deep = 0;
145
146 if ( buf == NULL )
147  return -1;
148
149 ROAR_DBG("buffer_add(buf=%p, next=%p) = ?", buf, next);
150
151 if ( buf->flags & ROAR_BUFFER_FLAG_RING )
152  return -1;
153
154 if ( buf == next ) {
155  ROAR_ERR("buffer_add(*): both pointer are of the same destination, This is a error in the application");
156  return -1;
157 }
158
159 while ( buf->next != NULL ) {
160  ROAR_DBG("buffer_add(*): buf=%p, next=%p (len=%i)", buf, buf->next, buf->user_len);
161//  ROAR_DBG("buffer_add(): buf=%p, buf->next=%p", buf, buf->next);
162  buf = buf->next;
163  deep++;
164
165  if ( buf == next ) {
166   ROAR_ERR("buffer_add(*): Can not add buffer: loop detected at deep %u. This is a error in the application", deep);
167  }
168 }
169
170 buf->next = next;
171
172 ROAR_DBG("buffer_add(*): adding buffer at deep %u", deep);
173
174 return 0;
175}
176
177int roar_buffer_get_next (struct roar_buffer *  buf, struct roar_buffer ** next) {
178 if ( buf == NULL )
179  return -1;
180
181 *next = buf->next;
182
183 return 0;
184}
185
186int roar_buffer_ring_new (struct roar_buffer ** buf, size_t len, int free_running) {
187 struct roar_buffer * n;
188
189 if ( buf == NULL || len == 0 )
190  return -1;
191
192 // just to be sure:
193 *buf = NULL;
194
195 // currently we are limited to free running mode
196 if ( !free_running )
197  return -1;
198
199 if ( roar_buffer_new(&n, len) == -1 )
200  return -1;
201
202 n->flags |= ROAR_BUFFER_FLAG_RING;
203
204 if ( free_running )
205  n->flags |= ROAR_BUFFER_FLAG_FREE_RUNNING;
206
207 n->meta.ring.read_pos  = 0;
208 n->meta.ring.write_pos = 0;
209
210 memset(n->data, 0, n->len);
211
212 *buf = n;
213
214 return 0;
215}
216
217int roar_buffer_get_data (struct roar_buffer *  buf, void   ** data) {
218 if ( buf == NULL )
219  return -1;
220
221 *data = buf->user_data;
222
223 return 0;
224}
225
226int roar_buffer_set_offset (struct roar_buffer *  buf, size_t off) {
227 if ( buf == NULL )
228  return -1;
229
230 buf->user_len  -= off;
231 buf->user_data += off;
232
233 return 0;
234}
235
236int roar_buffer_shift_out (struct roar_buffer ** buf, void * data, size_t * len) {
237 size_t todo, cl;
238 struct roar_buffer * cur;
239 void * cd;
240
241 if ( len == NULL || buf == NULL || data == NULL ) {
242  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid input", buf, data, (unsigned long)*len);
243  return -1;
244 }
245
246 if ( *buf == NULL ) {
247  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid pointer to buffer ring", buf, data, (unsigned long)len);
248  return -1;
249 }
250
251 todo = *len;
252 cur  = *buf;
253
254 *len = 0;
255
256 while (todo && cur != NULL) {
257  ROAR_DBG("roar_buffer_shift_out(*): todo=%u, cur=%p", (unsigned int) todo, cur);
258
259  if ( roar_buffer_get_len(cur, &cl) == -1 )
260   return -1;
261
262  if ( cl > todo ) {
263   if ( roar_buffer_get_data(cur, &cd) == -1 )
264    return -1;
265
266   cl = todo;
267
268   memcpy(data, cd, cl);
269   todo -= cl;
270   data += cl;
271   *len += cl;
272
273   if ( roar_buffer_set_offset(cur, cl) == -1 )
274    return -1;
275  } else {
276   if ( roar_buffer_get_data(cur, &cd) == -1 )
277    return -1;
278
279   memcpy(data, cd, cl);
280   todo -= cl;
281   data += cl;
282   *len += cl;
283
284   if ( roar_buffer_next(&cur) == -1 )
285    return -1;
286  }
287
288/*
289  if ( cur == NULL )
290   break;
291*/
292 }
293
294 *buf = cur;
295
296 return 0;
297}
298
299int roar_buffer_set_meta (struct roar_buffer * buf, void *  meta) {
300 if ( buf == NULL )
301  return -1;
302
303 buf->meta.vp = meta;
304
305 return 0;
306}
307
308int roar_buffer_get_meta (struct roar_buffer * buf, void ** meta) {
309 if ( buf == NULL || meta == NULL )
310  return -1;
311
312 *meta = buf->meta.vp;
313
314 return 0;
315}
316
317int roar_buffer_set_meta_i32(struct roar_buffer *  buf, int32_t    meta) {
318 if ( buf == NULL )
319  return -1;
320
321 buf->meta.i32 = meta;
322
323 return 0;
324}
325
326int roar_buffer_get_meta_i32(struct roar_buffer *  buf, int32_t *  meta) {
327 if ( buf == NULL || meta == NULL )
328  return -1;
329
330 *meta = buf->meta.i32;
331
332 return 0;
333}
334
335int roar_buffer_set_len  (struct roar_buffer *  buf, size_t    len) {
336 size_t   totlen;
337 void   * newbuf;
338
339 if ( buf == NULL )
340  return -1;
341
342 // handle specal case where user length is zero:
343 if ( len && !buf->user_len ) {
344  buf->user_data = buf->data;
345  buf->user_len  = buf->len;
346 }
347
348 if ( len > buf->user_len ) {
349  // we can only enlage a buffer if it's one of our own memory segments
350  if ( buf->flags & ROAR_BUFFER_FLAG_NOFREE )
351   return -1;
352
353  totlen = buf->len - buf->user_len + len;
354  newbuf = roar_mm_realloc(buf->data, totlen);
355  if ( newbuf == NULL )
356   return -1;
357
358  buf->data = newbuf;
359  buf->user_len = len;
360 } else {
361  buf->user_len = len;
362 }
363
364 return 0;
365}
366
367int roar_buffer_get_len  (struct roar_buffer *  buf, size_t *  len) {
368 if ( buf == NULL )
369  return -1;
370
371 *len = buf->user_len;
372
373 return 0;
374}
375
376int roar_buffer_set_flag (struct roar_buffer *  buf, int flag, int reset) {
377 if ( buf == NULL )
378  return -1;
379
380 buf->flags |= flag;
381
382 if ( reset )
383  buf->flags -= flag;
384
385 return 0;
386}
387
388int roar_buffer_get_flag (struct roar_buffer *  buf, int flag) {
389 if ( buf == NULL )
390  return -1;
391
392 return buf->flags & flag;
393}
394
395int roar_buffer_duplicate (struct roar_buffer *  buf, struct roar_buffer ** copy) {
396 struct roar_buffer *  cur = buf;
397 struct roar_buffer *  new;
398 void * od, * nd;
399
400 *copy = NULL;
401
402 while (cur) {
403  if ( roar_buffer_new(&new, cur->user_len) == -1 ) {
404   roar_buffer_free(*copy);
405   return -1;
406  }
407
408  if ( *copy == NULL )
409   *copy = new;
410
411  roar_buffer_get_data(cur, &od);
412  roar_buffer_get_data(new, &nd);
413  memcpy(nd, od, cur->user_len);
414
415  roar_buffer_add(*copy, new);
416
417  cur = cur->next;
418 }
419 return 0;
420}
421
422int roar_buffer_ring_stats (struct roar_buffer *  buf, struct roar_buffer_stats * stats) {
423 if ( buf == NULL )
424  return -1;
425
426 stats->parts        = 0;
427 stats->bytes        = 0;
428 stats->memory_usage = 0;
429
430 while (buf) {
431  stats->parts++;
432  stats->bytes        += buf->user_len;
433  stats->memory_usage += buf->len + sizeof(struct roar_buffer);
434  buf = buf->next;
435 }
436
437 return 0;
438}
439
440int roar_buffer_ring_read  (struct roar_buffer *  buf, void * data, size_t * len) {
441 if ( buf == NULL || len == NULL )
442  return -1;
443
444 if ( data == NULL && *len != 0 )
445  return -1;
446
447 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) )
448  return -1;
449
450 if ( *len == 0 )
451  return 0;
452
453 // we may handle this later:
454 if ( *len > buf->user_len )
455  return -1;
456
457 if ( buf->meta.ring.read_pos >= buf->user_len )
458  buf->meta.ring.read_pos -= buf->user_len;
459
460 if ( (*len + buf->meta.ring.read_pos) > buf->user_len ) {
461  // wraped mode:
462  memcpy(data, buf->user_data+buf->meta.ring.read_pos, buf->user_len - buf->meta.ring.read_pos);
463  memcpy(data, buf->user_data, *len + buf->meta.ring.read_pos - buf->user_len);
464
465  buf->meta.ring.read_pos += *len;
466  buf->meta.ring.read_pos -= buf->user_len;
467  return 0;
468 } else {
469  // unwarped mode:
470  memcpy(data, buf->user_data+buf->meta.ring.read_pos, *len);
471  buf->meta.ring.read_pos += *len;
472  return 0;
473 }
474
475 return -1;
476}
477
478int roar_buffer_ring_write (struct roar_buffer *  buf, void * data, size_t * len) {
479 if ( buf == NULL || len == NULL )
480  return -1;
481
482 if ( data == NULL && *len != 0 )
483  return -1;
484
485 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) )
486  return -1;
487
488 if ( *len == 0 )
489  return 0;
490
491 // we may handle this later:
492 if ( *len > buf->user_len )
493  return -1;
494
495 if ( buf->meta.ring.write_pos >= buf->user_len )
496  buf->meta.ring.write_pos -= buf->user_len;
497
498 if ( (*len + buf->meta.ring.write_pos) > buf->user_len ) {
499  // wraped mode:
500  memcpy(buf->user_data+buf->meta.ring.write_pos, data, buf->user_len - buf->meta.ring.write_pos);
501  memcpy(buf->user_data, data, *len + buf->meta.ring.write_pos - buf->user_len);
502
503  buf->meta.ring.write_pos += *len;
504  buf->meta.ring.write_pos -= buf->user_len;
505  return 0;
506 } else {
507  // unwarped mode:
508  memcpy(buf->user_data+buf->meta.ring.write_pos, data, *len);
509  buf->meta.ring.write_pos += *len;
510  return 0;
511 }
512
513 return -1;
514}
515
516//ll
Note: See TracBrowser for help on using the repository browser.