source: roaraudio/libroar/buffer.c @ 4516:f2314a12d62a

Last change on this file since 4516:f2314a12d62a was 4516:f2314a12d62a, checked in by phi, 14 years ago

removed the public struct define of struct roar_buffer

File size: 11.3 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
38struct roar_buffer_ring {
39 size_t read_pos;
40 size_t write_pos;
41};
42
43struct roar_buffer {
44 size_t               refc;
45 size_t               len;
46 size_t               user_len;
47 int                  flags;
48 void               * data;
49 void               * user_data;
50 union {
51  void                    * vp;
52  int32_t                   i32;
53  struct roar_buffer_ring   ring;
54 }                    meta;
55 struct roar_buffer * next;
56};
57
58int roar_buffer_new_data (struct roar_buffer ** buf, size_t len, void ** data) {
59 void * bufdata;
60
61 if ((bufdata = roar_mm_malloc(len)) == NULL) {
62  return -1;
63 }
64
65 if ( roar_buffer_new_no_ma(buf, len, bufdata) == -1 ) {
66  roar_mm_free(bufdata);
67  return -1;
68 }
69
70 if ( roar_buffer_set_flag(*buf, ROAR_BUFFER_FLAG_NOFREE, ROAR_BUFFER_RESET) == -1 ) {
71  roar_buffer_free(*buf);
72  roar_mm_free(bufdata);
73  return -1;
74 }
75
76 if ( data != NULL )
77  *data = bufdata;
78
79 return 0;
80}
81
82int roar_buffer_new_no_ma(struct roar_buffer ** buf, size_t len, void * data) { // no internal malloc
83 struct roar_buffer * new;
84
85 ROAR_DBG("buffer_new(buf=%p, len=%i) = ?", buf, len);
86
87 if ( buf == NULL || data == NULL )
88  return -1;
89
90 if ((new = roar_mm_malloc(sizeof(struct roar_buffer))) == NULL) {
91  *buf = NULL;
92  return -1;
93 }
94
95 new->data      = data;
96
97 new->flags     = ROAR_BUFFER_FLAG_NONE|ROAR_BUFFER_FLAG_NOFREE;
98
99 new->user_data = new->data;
100
101 new->next      = NULL;
102
103 new->len       = len;
104 new->user_len  = len;
105 *buf           = new;
106
107 ROAR_DBG("buffer_new(buf=%p, len=%i): New buffer at %p", buf, len, new);
108
109 return 0;
110}
111
112int roar_buffer_free     (struct roar_buffer * buf) {
113 struct roar_buffer * next;
114
115 if ( buf == NULL )
116  return -1;
117
118 while ((next = buf->next)) {
119  if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
120   roar_mm_free(buf->data);
121
122  roar_mm_free(buf);
123  buf = next;
124 }
125
126 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
127  roar_mm_free(buf->data);
128
129 roar_mm_free(buf);
130
131 return 0;
132}
133
134int roar_buffer_delete   (struct roar_buffer * buf, struct roar_buffer ** next) {
135 if ( buf == NULL ) {
136  if ( next != NULL )
137   *next = NULL;
138  return -1;
139 }
140
141 ROAR_DBG("buffer_delete(buf=%p, next=%p) = ?", buf, next);
142
143 if ( next != NULL )
144  *next = buf->next;
145
146 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
147  roar_mm_free(buf->data);
148
149 roar_mm_free(buf);
150
151 ROAR_DBG("buffer_delete(buf=%p, next=%p) = 0", buf, next);
152 return 0;
153}
154
155int roar_buffer_add      (struct roar_buffer * buf, struct roar_buffer *  next) {
156 unsigned int deep = 0;
157
158 if ( buf == NULL )
159  return -1;
160
161 ROAR_DBG("buffer_add(buf=%p, next=%p) = ?", buf, next);
162
163 if ( buf->flags & ROAR_BUFFER_FLAG_RING )
164  return -1;
165
166 if ( buf == next ) {
167  ROAR_ERR("buffer_add(*): both pointer are of the same destination, This is a error in the application");
168  return -1;
169 }
170
171 while ( buf->next != NULL ) {
172  ROAR_DBG("buffer_add(*): buf=%p, next=%p (len=%i)", buf, buf->next, buf->user_len);
173//  ROAR_DBG("buffer_add(): buf=%p, buf->next=%p", buf, buf->next);
174  buf = buf->next;
175  deep++;
176
177  if ( buf == next ) {
178   ROAR_ERR("buffer_add(*): Can not add buffer: loop detected at deep %u. This is a error in the application", deep);
179  }
180 }
181
182 buf->next = next;
183
184 ROAR_DBG("buffer_add(*): adding buffer at deep %u", deep);
185
186 return 0;
187}
188
189int roar_buffer_clear_next (struct roar_buffer *  buf) {
190 if ( buf == NULL )
191  return -1;
192
193 buf->next = NULL;
194
195 return 0;
196}
197
198int roar_buffer_get_next (struct roar_buffer *  buf, struct roar_buffer ** next) {
199 if ( buf == NULL )
200  return -1;
201
202 *next = buf->next;
203
204 return 0;
205}
206
207int roar_buffer_ring_new (struct roar_buffer ** buf, size_t len, int free_running) {
208 struct roar_buffer * n;
209
210 if ( buf == NULL || len == 0 )
211  return -1;
212
213 // just to be sure:
214 *buf = NULL;
215
216 // currently we are limited to free running mode
217 if ( !free_running )
218  return -1;
219
220 if ( roar_buffer_new(&n, len) == -1 )
221  return -1;
222
223 n->flags |= ROAR_BUFFER_FLAG_RING;
224
225 if ( free_running )
226  n->flags |= ROAR_BUFFER_FLAG_FREE_RUNNING;
227
228 n->meta.ring.read_pos  = 0;
229 n->meta.ring.write_pos = 0;
230
231 memset(n->data, 0, n->len);
232
233 *buf = n;
234
235 return 0;
236}
237
238int roar_buffer_get_data (struct roar_buffer *  buf, void   ** data) {
239 if ( buf == NULL )
240  return -1;
241
242 *data = buf->user_data;
243
244 return 0;
245}
246
247int roar_buffer_set_offset (struct roar_buffer *  buf, size_t off) {
248 if ( buf == NULL )
249  return -1;
250
251 buf->user_len  -= off;
252 buf->user_data += off;
253
254 return 0;
255}
256
257int roar_buffer_shift_out (struct roar_buffer ** buf, void * data, size_t * len) {
258 size_t todo, cl;
259 struct roar_buffer * cur;
260 void * cd;
261
262 if ( len == NULL || buf == NULL || data == NULL ) {
263  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid input", buf, data, (unsigned long)*len);
264  return -1;
265 }
266
267 if ( *buf == NULL ) {
268  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid pointer to buffer ring", buf, data, (unsigned long)len);
269  return -1;
270 }
271
272 todo = *len;
273 cur  = *buf;
274
275 *len = 0;
276
277 while (todo && cur != NULL) {
278  ROAR_DBG("roar_buffer_shift_out(*): todo=%u, cur=%p", (unsigned int) todo, cur);
279
280  if ( roar_buffer_get_len(cur, &cl) == -1 )
281   return -1;
282
283  if ( cl > todo ) {
284   if ( roar_buffer_get_data(cur, &cd) == -1 )
285    return -1;
286
287   cl = todo;
288
289   memcpy(data, cd, cl);
290   todo -= cl;
291   data += cl;
292   *len += cl;
293
294   if ( roar_buffer_set_offset(cur, cl) == -1 )
295    return -1;
296  } else {
297   if ( roar_buffer_get_data(cur, &cd) == -1 )
298    return -1;
299
300   memcpy(data, cd, cl);
301   todo -= cl;
302   data += cl;
303   *len += cl;
304
305   if ( roar_buffer_next(&cur) == -1 )
306    return -1;
307  }
308
309/*
310  if ( cur == NULL )
311   break;
312*/
313 }
314
315 *buf = cur;
316
317 return 0;
318}
319
320int roar_buffer_set_meta (struct roar_buffer * buf, void *  meta) {
321 if ( buf == NULL )
322  return -1;
323
324 buf->meta.vp = meta;
325
326 return 0;
327}
328
329int roar_buffer_get_meta (struct roar_buffer * buf, void ** meta) {
330 if ( buf == NULL || meta == NULL )
331  return -1;
332
333 *meta = buf->meta.vp;
334
335 return 0;
336}
337
338int roar_buffer_set_meta_i32(struct roar_buffer *  buf, int32_t    meta) {
339 if ( buf == NULL )
340  return -1;
341
342 buf->meta.i32 = meta;
343
344 return 0;
345}
346
347int roar_buffer_get_meta_i32(struct roar_buffer *  buf, int32_t *  meta) {
348 if ( buf == NULL || meta == NULL )
349  return -1;
350
351 *meta = buf->meta.i32;
352
353 return 0;
354}
355
356int roar_buffer_set_len  (struct roar_buffer *  buf, size_t    len) {
357 size_t   totlen;
358 void   * newbuf;
359
360 if ( buf == NULL )
361  return -1;
362
363 // handle specal case where user length is zero:
364 if ( len && !buf->user_len ) {
365  buf->user_data = buf->data;
366  buf->user_len  = buf->len;
367 }
368
369 if ( len > buf->user_len ) {
370  // we can only enlage a buffer if it's one of our own memory segments
371  if ( buf->flags & ROAR_BUFFER_FLAG_NOFREE )
372   return -1;
373
374  totlen = buf->len - buf->user_len + len;
375  newbuf = roar_mm_realloc(buf->data, totlen);
376  if ( newbuf == NULL )
377   return -1;
378
379  buf->data = newbuf;
380  buf->user_len = len;
381 } else {
382  buf->user_len = len;
383 }
384
385 return 0;
386}
387
388int roar_buffer_get_len  (struct roar_buffer *  buf, size_t *  len) {
389 if ( buf == NULL )
390  return -1;
391
392 *len = buf->user_len;
393
394 return 0;
395}
396
397int roar_buffer_set_flag (struct roar_buffer *  buf, int flag, int reset) {
398 if ( buf == NULL )
399  return -1;
400
401 buf->flags |= flag;
402
403 if ( reset )
404  buf->flags -= flag;
405
406 return 0;
407}
408
409int roar_buffer_get_flag (struct roar_buffer *  buf, int flag) {
410 if ( buf == NULL )
411  return -1;
412
413 return buf->flags & flag;
414}
415
416int roar_buffer_duplicate (struct roar_buffer *  buf, struct roar_buffer ** copy) {
417 struct roar_buffer *  cur = buf;
418 struct roar_buffer *  new;
419 void * od, * nd;
420
421 *copy = NULL;
422
423 while (cur) {
424  if ( roar_buffer_new(&new, cur->user_len) == -1 ) {
425   roar_buffer_free(*copy);
426   return -1;
427  }
428
429  if ( *copy == NULL )
430   *copy = new;
431
432  roar_buffer_get_data(cur, &od);
433  roar_buffer_get_data(new, &nd);
434  memcpy(nd, od, cur->user_len);
435
436  roar_buffer_add(*copy, new);
437
438  cur = cur->next;
439 }
440 return 0;
441}
442
443int roar_buffer_ring_stats (struct roar_buffer *  buf, struct roar_buffer_stats * stats) {
444 if ( buf == NULL )
445  return -1;
446
447 stats->parts        = 0;
448 stats->bytes        = 0;
449 stats->memory_usage = 0;
450
451 while (buf) {
452  stats->parts++;
453  stats->bytes        += buf->user_len;
454  stats->memory_usage += buf->len + sizeof(struct roar_buffer);
455  buf = buf->next;
456 }
457
458 return 0;
459}
460
461int roar_buffer_ring_read  (struct roar_buffer *  buf, void * data, size_t * len) {
462 if ( buf == NULL || len == NULL )
463  return -1;
464
465 if ( data == NULL && *len != 0 )
466  return -1;
467
468 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) )
469  return -1;
470
471 if ( *len == 0 )
472  return 0;
473
474 // we may handle this later:
475 if ( *len > buf->user_len )
476  return -1;
477
478 if ( buf->meta.ring.read_pos >= buf->user_len )
479  buf->meta.ring.read_pos -= buf->user_len;
480
481 if ( (*len + buf->meta.ring.read_pos) > buf->user_len ) {
482  // wraped mode:
483  memcpy(data, buf->user_data+buf->meta.ring.read_pos, buf->user_len - buf->meta.ring.read_pos);
484  memcpy(data, buf->user_data, *len + buf->meta.ring.read_pos - buf->user_len);
485
486  buf->meta.ring.read_pos += *len;
487  buf->meta.ring.read_pos -= buf->user_len;
488  return 0;
489 } else {
490  // unwarped mode:
491  memcpy(data, buf->user_data+buf->meta.ring.read_pos, *len);
492  buf->meta.ring.read_pos += *len;
493  return 0;
494 }
495
496 return -1;
497}
498
499int roar_buffer_ring_write (struct roar_buffer *  buf, void * data, size_t * len) {
500 if ( buf == NULL || len == NULL )
501  return -1;
502
503 if ( data == NULL && *len != 0 )
504  return -1;
505
506 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) )
507  return -1;
508
509 if ( *len == 0 )
510  return 0;
511
512 // we may handle this later:
513 if ( *len > buf->user_len )
514  return -1;
515
516 if ( buf->meta.ring.write_pos >= buf->user_len )
517  buf->meta.ring.write_pos -= buf->user_len;
518
519 if ( (*len + buf->meta.ring.write_pos) > buf->user_len ) {
520  // wraped mode:
521  memcpy(buf->user_data+buf->meta.ring.write_pos, data, buf->user_len - buf->meta.ring.write_pos);
522  memcpy(buf->user_data, data, *len + buf->meta.ring.write_pos - buf->user_len);
523
524  buf->meta.ring.write_pos += *len;
525  buf->meta.ring.write_pos -= buf->user_len;
526  return 0;
527 } else {
528  // unwarped mode:
529  memcpy(buf->user_data+buf->meta.ring.write_pos, data, *len);
530  buf->meta.ring.write_pos += *len;
531  return 0;
532 }
533
534 return -1;
535}
536
537//ll
Note: See TracBrowser for help on using the repository browser.