source: roaraudio/libroar/buffer.c @ 4624:7cdf88681b49

Last change on this file since 4624:7cdf88681b49 was 4624:7cdf88681b49, checked in by phi, 13 years ago

updates for ringbuffer

File size: 14.0 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->refc      = 1;
96
97 new->data      = data;
98
99 new->flags     = ROAR_BUFFER_FLAG_NONE|ROAR_BUFFER_FLAG_NOFREE;
100
101 new->user_data = new->data;
102
103 new->next      = NULL;
104
105 new->len       = len;
106 new->user_len  = len;
107 *buf           = new;
108
109 ROAR_DBG("buffer_new(buf=%p, len=%i): New buffer at %p", buf, len, new);
110
111 return 0;
112}
113
114int roar_buffer_ref      (struct roar_buffer *  buf) {
115 if ( buf == NULL )
116  return -1;
117
118 buf->refc++;
119
120 return 0;
121}
122
123int roar_buffer_unref     (struct roar_buffer * buf) {
124 struct roar_buffer * next;
125
126 if ( buf == NULL )
127  return -1;
128
129 if ( buf->refc == 0 ) {
130  ROAR_WARN("roar_buffer_unref(buf=%p): Ref counter is wrong. assuming one.");
131  buf->refc = 1;
132 }
133
134 buf->refc--;
135
136 if ( buf->refc )
137  return 0;
138
139 while ((next = buf->next)) {
140  if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
141   roar_mm_free(buf->data);
142
143  roar_mm_free(buf);
144  buf = next;
145 }
146
147 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
148  roar_mm_free(buf->data);
149
150 roar_mm_free(buf);
151
152 return 0;
153}
154
155int roar_buffer_delete   (struct roar_buffer * buf, struct roar_buffer ** next) {
156 if ( buf == NULL ) {
157  if ( next != NULL )
158   *next = NULL;
159  return -1;
160 }
161
162 ROAR_DBG("buffer_delete(buf=%p, next=%p) = ?", buf, next);
163
164 if ( next != NULL )
165  *next = buf->next;
166
167 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
168  roar_mm_free(buf->data);
169
170 roar_mm_free(buf);
171
172 ROAR_DBG("buffer_delete(buf=%p, next=%p) = 0", buf, next);
173 return 0;
174}
175
176int roar_buffer_add      (struct roar_buffer * buf, struct roar_buffer *  next) {
177 unsigned int deep = 0;
178
179 if ( buf == NULL )
180  return -1;
181
182 ROAR_DBG("buffer_add(buf=%p, next=%p) = ?", buf, next);
183
184 if ( buf->flags & ROAR_BUFFER_FLAG_RING )
185  return -1;
186
187 if ( buf == next ) {
188  ROAR_ERR("buffer_add(*): both pointer are of the same destination, This is a error in the application");
189  return -1;
190 }
191
192 while ( buf->next != NULL ) {
193  ROAR_DBG("buffer_add(*): buf=%p, next=%p (len=%i)", buf, buf->next, buf->user_len);
194//  ROAR_DBG("buffer_add(): buf=%p, buf->next=%p", buf, buf->next);
195  buf = buf->next;
196  deep++;
197
198  if ( buf == next ) {
199   ROAR_ERR("buffer_add(*): Can not add buffer: loop detected at deep %u. This is a error in the application", deep);
200  }
201 }
202
203 buf->next = next;
204
205 ROAR_DBG("buffer_add(*): adding buffer at deep %u", deep);
206
207 return 0;
208}
209
210int roar_buffer_clear_next (struct roar_buffer *  buf) {
211 if ( buf == NULL )
212  return -1;
213
214 buf->next = NULL;
215
216 return 0;
217}
218
219int roar_buffer_get_next (struct roar_buffer *  buf, struct roar_buffer ** next) {
220 if ( buf == NULL )
221  return -1;
222
223 *next = buf->next;
224
225 return 0;
226}
227
228int roar_buffer_ring_new (struct roar_buffer ** buf, size_t len, int free_running) {
229 struct roar_buffer * n;
230
231 if ( buf == NULL || len == 0 )
232  return -1;
233
234 // just to be sure:
235 *buf = NULL;
236
237 if ( roar_buffer_new(&n, len) == -1 )
238  return -1;
239
240 n->flags |= ROAR_BUFFER_FLAG_RING;
241
242 if ( free_running )
243  n->flags |= ROAR_BUFFER_FLAG_FREE_RUNNING;
244
245 n->meta.ring.read_pos  = 0;
246 n->meta.ring.write_pos = 0;
247
248 memset(n->data, 0, n->len);
249
250 *buf = n;
251
252 return 0;
253}
254
255int roar_buffer_get_data (struct roar_buffer *  buf, void   ** data) {
256 if ( buf == NULL )
257  return -1;
258
259 *data = buf->user_data;
260
261 return 0;
262}
263
264int roar_buffer_set_offset (struct roar_buffer *  buf, size_t off) {
265 if ( buf == NULL )
266  return -1;
267
268 buf->user_len  -= off;
269 buf->user_data += off;
270
271 return 0;
272}
273
274int roar_buffer_shift_out (struct roar_buffer ** buf, void * data, size_t * len) {
275 size_t todo, cl;
276 struct roar_buffer * cur;
277 void * cd;
278
279 if ( len == NULL || buf == NULL || data == NULL ) {
280  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid input", buf, data, (unsigned long)*len);
281  return -1;
282 }
283
284 if ( *buf == NULL ) {
285  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid pointer to buffer ring", buf, data, (unsigned long)len);
286  return -1;
287 }
288
289 todo = *len;
290 cur  = *buf;
291
292 *len = 0;
293
294 while (todo && cur != NULL) {
295  ROAR_DBG("roar_buffer_shift_out(*): todo=%u, cur=%p", (unsigned int) todo, cur);
296
297  if ( roar_buffer_get_len(cur, &cl) == -1 )
298   return -1;
299
300  if ( cl > todo ) {
301   if ( roar_buffer_get_data(cur, &cd) == -1 )
302    return -1;
303
304   cl = todo;
305
306   memcpy(data, cd, cl);
307   todo -= cl;
308   data += cl;
309   *len += cl;
310
311   if ( roar_buffer_set_offset(cur, cl) == -1 )
312    return -1;
313  } else {
314   if ( roar_buffer_get_data(cur, &cd) == -1 )
315    return -1;
316
317   memcpy(data, cd, cl);
318   todo -= cl;
319   data += cl;
320   *len += cl;
321
322   if ( roar_buffer_next(&cur) == -1 )
323    return -1;
324  }
325
326/*
327  if ( cur == NULL )
328   break;
329*/
330 }
331
332 *buf = cur;
333
334 return 0;
335}
336
337int roar_buffer_set_meta (struct roar_buffer * buf, void *  meta) {
338 if ( buf == NULL )
339  return -1;
340
341 buf->meta.vp = meta;
342
343 return 0;
344}
345
346int roar_buffer_get_meta (struct roar_buffer * buf, void ** meta) {
347 if ( buf == NULL || meta == NULL )
348  return -1;
349
350 *meta = buf->meta.vp;
351
352 return 0;
353}
354
355int roar_buffer_set_meta_i32(struct roar_buffer *  buf, int32_t    meta) {
356 if ( buf == NULL )
357  return -1;
358
359 buf->meta.i32 = meta;
360
361 return 0;
362}
363
364int roar_buffer_get_meta_i32(struct roar_buffer *  buf, int32_t *  meta) {
365 if ( buf == NULL || meta == NULL )
366  return -1;
367
368 *meta = buf->meta.i32;
369
370 return 0;
371}
372
373int roar_buffer_set_len  (struct roar_buffer *  buf, size_t    len) {
374 size_t   totlen;
375 void   * newbuf;
376
377 if ( buf == NULL )
378  return -1;
379
380 // handle specal case where user length is zero:
381 if ( len && !buf->user_len ) {
382  buf->user_data = buf->data;
383  buf->user_len  = buf->len;
384 }
385
386 if ( len > buf->user_len ) {
387  // we can only enlage a buffer if it's one of our own memory segments
388  if ( buf->flags & ROAR_BUFFER_FLAG_NOFREE )
389   return -1;
390
391  totlen = buf->len - buf->user_len + len;
392  newbuf = roar_mm_realloc(buf->data, totlen);
393  if ( newbuf == NULL )
394   return -1;
395
396  buf->data = newbuf;
397  buf->user_len = len;
398 } else {
399  buf->user_len = len;
400 }
401
402 return 0;
403}
404
405int roar_buffer_get_len  (struct roar_buffer *  buf, size_t *  len) {
406 if ( buf == NULL )
407  return -1;
408
409 *len = buf->user_len;
410
411 return 0;
412}
413
414int roar_buffer_set_flag (struct roar_buffer *  buf, int flag, int reset) {
415 if ( buf == NULL )
416  return -1;
417
418 buf->flags |= flag;
419
420 if ( reset )
421  buf->flags -= flag;
422
423 return 0;
424}
425
426int roar_buffer_get_flag (struct roar_buffer *  buf, int flag) {
427 if ( buf == NULL )
428  return -1;
429
430 return buf->flags & flag;
431}
432
433int roar_buffer_duplicate (struct roar_buffer *  buf, struct roar_buffer ** copy) {
434 struct roar_buffer *  cur = buf;
435 struct roar_buffer *  new;
436 void * od, * nd;
437
438 *copy = NULL;
439
440 while (cur) {
441  if ( roar_buffer_new(&new, cur->user_len) == -1 ) {
442   roar_buffer_free(*copy);
443   return -1;
444  }
445
446  if ( *copy == NULL )
447   *copy = new;
448
449  roar_buffer_get_data(cur, &od);
450  roar_buffer_get_data(new, &nd);
451  memcpy(nd, od, cur->user_len);
452
453  roar_buffer_add(*copy, new);
454
455  cur = cur->next;
456 }
457 return 0;
458}
459
460int roar_buffer_ring_stats (struct roar_buffer *  buf, struct roar_buffer_stats * stats) {
461 if ( buf == NULL )
462  return -1;
463
464 stats->parts        = 0;
465 stats->bytes        = 0;
466 stats->memory_usage = 0;
467
468 while (buf) {
469  stats->parts++;
470  stats->bytes        += buf->user_len;
471  stats->memory_usage += buf->len + sizeof(struct roar_buffer);
472  buf = buf->next;
473 }
474
475 return 0;
476}
477
478int roar_buffer_ring_read  (struct roar_buffer *  buf, void * data, size_t * len) {
479 struct roar_buffer_ring * ring;
480 size_t havelen;
481 size_t done;
482 size_t tmp;
483
484 if ( buf == NULL || len == NULL )
485  return -1;
486
487 if ( data == NULL && *len != 0 )
488  return -1;
489
490 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) )
491  return -1;
492
493 if ( *len == 0 )
494  return 0;
495
496 // we may handle this later:
497 if ( *len > buf->user_len )
498  return -1;
499
500 if ( (buf->flags & ROAR_BUFFER_FLAG_FREE_RUNNING) ) {
501  if ( buf->meta.ring.read_pos >= buf->user_len )
502   buf->meta.ring.read_pos -= buf->user_len;
503
504  if ( (*len + buf->meta.ring.read_pos) > buf->user_len ) {
505   // wraped mode:
506   memcpy(data, buf->user_data+buf->meta.ring.read_pos, buf->user_len - buf->meta.ring.read_pos);
507   memcpy(data, buf->user_data, *len + buf->meta.ring.read_pos - buf->user_len);
508 
509   buf->meta.ring.read_pos += *len;
510   buf->meta.ring.read_pos -= buf->user_len;
511   return 0;
512  } else {
513   // unwarped mode:
514   memcpy(data, buf->user_data+buf->meta.ring.read_pos, *len);
515   buf->meta.ring.read_pos += *len;
516   return 0;
517  }
518 } else {
519  ring = &(buf->meta.ring);
520
521  if ( ring->read_pos == ring->write_pos ) {
522   *len = 0;
523   return 0;
524  } else if ( ring->read_pos < ring->write_pos ) {
525   havelen = ring->write_pos - ring->read_pos;
526
527   if ( havelen > *len )
528    havelen = *len;
529
530   memcpy(data, buf->user_data+ring->read_pos, havelen);
531   ring->read_pos += havelen;
532
533   *len = havelen;
534   return 0;
535  } else { // write_pos < read_pos
536   done = 0;
537
538   // first pass: use data up to end of buffer
539
540   havelen = buf->user_len - ring->read_pos;
541
542   if ( havelen > *len )
543    havelen = *len;
544
545   memcpy(data, buf->user_data+ring->read_pos, havelen);
546   ring->read_pos += havelen;
547
548   done += havelen;
549
550   if ( ring->read_pos == buf->user_len ) {
551    ring->read_pos = 0;
552   }
553
554   // second pass: use data from strat of buffer to write pointer
555
556   if ( *len > done ) {
557    tmp = *len - done;
558    if ( roar_buffer_ring_read(buf, data+done, &tmp) == 0 ) {
559     done += tmp;
560    }
561   }
562
563   *len = done;
564   return 0;
565  }
566
567  return -1;
568 }
569
570 return -1;
571}
572
573int roar_buffer_ring_write (struct roar_buffer *  buf, void * data, size_t * len) {
574 struct roar_buffer_ring * ring;
575 size_t havelen;
576 size_t done;
577 size_t tmp;
578
579 if ( buf == NULL || len == NULL )
580  return -1;
581
582 if ( data == NULL && *len != 0 )
583  return -1;
584
585 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) )
586  return -1;
587
588 if ( *len == 0 )
589  return 0;
590
591 // we may handle this later:
592 if ( *len > buf->user_len )
593  return -1;
594
595 if ( (buf->flags & ROAR_BUFFER_FLAG_FREE_RUNNING) ) {
596  if ( buf->meta.ring.write_pos >= buf->user_len )
597   buf->meta.ring.write_pos -= buf->user_len;
598
599  if ( (*len + buf->meta.ring.write_pos) > buf->user_len ) {
600   // wraped mode:
601   memcpy(buf->user_data+buf->meta.ring.write_pos, data, buf->user_len - buf->meta.ring.write_pos);
602   memcpy(buf->user_data, data, *len + buf->meta.ring.write_pos - buf->user_len);
603
604   buf->meta.ring.write_pos += *len;
605   buf->meta.ring.write_pos -= buf->user_len;
606   return 0;
607  } else {
608   // unwarped mode:
609   memcpy(buf->user_data+buf->meta.ring.write_pos, data, *len);
610   buf->meta.ring.write_pos += *len;
611   return 0;
612  }
613 } else {
614  ring = &(buf->meta.ring);
615  done = 0;
616
617  ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p): write_pos=%u, read_pos=%u, user_len=%u", buf, data, len, (unsigned int)ring->write_pos, (unsigned int)ring->read_pos, (unsigned int)buf->user_len);
618
619  if ( ring->write_pos >= ring->read_pos ) {
620   havelen = buf->user_len - ring->write_pos;
621
622   if ( ring->read_pos == 0 )
623    havelen--;
624
625   if ( havelen > *len )
626    havelen = *len;
627
628   memcpy(buf->user_data+ring->write_pos, data, havelen);
629
630   done += havelen;
631   ring->write_pos += havelen;
632
633   if ( ring->write_pos == buf->user_len )
634    ring->write_pos = 0;
635
636   if ( *len > done && ring->read_pos != 0 ) {
637    tmp = *len - done;
638    if ( roar_buffer_ring_write(buf, data+done, &tmp) == 0 ) {
639     done += tmp;
640    }
641   }
642
643   *len = done;
644   return 0;
645  } else {
646   // test for buffer-is-full:
647   if ( (ring->write_pos + 1) == ring->read_pos ) {
648    *len = 0;
649    return 0;
650   }
651
652   havelen = ring->read_pos - ring->write_pos - 1;
653
654   if ( havelen > *len )
655    havelen = *len;
656
657   memcpy(buf->user_data+ring->write_pos, data, havelen);
658
659   *len = havelen;
660   return 0;
661  }
662
663  return -1;
664 }
665
666 return -1;
667}
668
669//ll
Note: See TracBrowser for help on using the repository browser.