Make the target behave the same as the sim (don't care about the disk)
[Rockbox.git] / apps / buffering.c
blob549806ef12ed954acbb94c5997a0aef02f0f200e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Nicolas Pennequin
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include "buffering.h"
27 #include "ata.h"
28 #include "system.h"
29 #include "thread.h"
30 #include "file.h"
31 #include "panic.h"
32 #include "memory.h"
33 #include "lcd.h"
34 #include "font.h"
35 #include "button.h"
36 #include "kernel.h"
37 #include "tree.h"
38 #include "debug.h"
39 #include "sprintf.h"
40 #include "settings.h"
41 #include "codecs.h"
42 #include "audio.h"
43 #include "logf.h"
44 #include "mp3_playback.h"
45 #include "usb.h"
46 #include "status.h"
47 #include "screens.h"
48 #include "playlist.h"
49 #include "playback.h"
50 #include "pcmbuf.h"
51 #include "buffer.h"
53 #ifdef SIMULATOR
54 #define ata_disk_is_active() 1
55 #endif
57 #if MEM > 1
58 #define GUARD_BUFSIZE (32*1024)
59 #else
60 #define GUARD_BUFSIZE (8*1024)
61 #endif
63 #define LOGFQUEUE logf
65 /* amount of data to read in one read() call */
66 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
68 /* Ring buffer helper macros */
69 /* Buffer pointer (p) plus value (v), wrapped if necessary */
70 #define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
71 /* Buffer pointer (p) minus value (v), wrapped if necessary */
72 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
73 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
74 #define RINGBUF_ADD_CROSS(p1,v,p2) \
75 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
76 /* Bytes available in the buffer */
77 #define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
79 struct memory_handle {
80 int id; /* A unique ID for the handle */
81 enum data_type type;
82 char path[MAX_PATH];
83 int fd;
84 size_t data; /* Start index of the handle's data buffer */
85 size_t ridx; /* Current read pointer, relative to the main buffer */
86 size_t widx; /* Current write pointer */
87 size_t filesize; /* File total length */
88 size_t filerem; /* Remaining bytes of file NOT in buffer */
89 size_t available; /* Available bytes to read from buffer */
90 size_t offset; /* Offset at which we started reading the file */
91 struct memory_handle *next;
93 /* at all times, we have: filesize == offset + available + filerem */
96 static char *buffer;
97 static char *guard_buffer;
99 static size_t buffer_len;
101 static size_t buf_widx; /* current writing position */
102 static size_t buf_ridx; /* current reading position */
103 /* buf_*idx are values relative to the buffer, not real pointers. */
105 static size_t conf_filechunk;
107 /* current memory handle in the linked list. NULL when the list is empty. */
108 static struct memory_handle *cur_handle;
109 /* first memory handle in the linked list. NULL when the list is empty. */
110 static struct memory_handle *first_handle;
112 static int num_handles; /* number of handles in the list */
114 /* Handle cache (makes find_handle faster).
115 These need to be global so that move_handle can invalidate them. */
116 static int cached_handle_id = -1;
117 static struct memory_handle *cached_handle = NULL;
121 LINKED LIST MANAGEMENT
122 ======================
124 add_handle : Add a handle to the list
125 rm_handle : Remove a handle from the list
126 find_handle : Get a handle pointer from an ID
127 move_handle : Move a handle in the buffer (with or without its data)
129 These functions only handle the linked list structure. They don't touch the
130 contents of the struct memory_handle headers. They also change the buf_*idx
131 pointers when necessary and manage the handle IDs.
133 The first and current (== last) handle are kept track of.
134 A new handle is added at buf_widx and becomes the current one.
135 buf_widx always points to the current writing position for the current handle
136 buf_ridx always points to the location of the first handle.
137 buf_ridx == buf_widx means the buffer is empty.
141 /* Add a new handle to the linked list and return it. It will have become the
142 new current handle. The handle will reserve "data_size" bytes or if that's
143 not possible, decrease "data_size" to allow adding the handle. */
144 static struct memory_handle *add_handle(size_t *data_size)
146 /* this will give each handle a unique id */
147 static int cur_handle_id = 1;
149 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
150 but before that we check we can actually align. */
151 if (RINGBUF_ADD_CROSS(buf_widx, 3, buf_ridx) >= 0) {
152 return NULL;
154 buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
156 size_t len = (data_size ? *data_size : 0)
157 + sizeof(struct memory_handle);
159 /* check that we actually can add the handle and its data */
160 int overlap = RINGBUF_ADD_CROSS(buf_widx, len, buf_ridx);
161 if (overlap >= 0) {
162 *data_size -= overlap;
163 len -= overlap;
165 if (len < sizeof(struct memory_handle)) {
166 /* There isn't even enough space to write the struct */
167 return NULL;
170 struct memory_handle *new_handle =
171 (struct memory_handle *)(&buffer[buf_widx]);
173 /* only advance the buffer write index of the size of the struct */
174 buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
176 if (!first_handle) {
177 /* the new handle is the first one */
178 first_handle = new_handle;
181 if (cur_handle) {
182 cur_handle->next = new_handle;
185 cur_handle = new_handle;
186 cur_handle->id = cur_handle_id++;
187 cur_handle->next = NULL;
188 num_handles++;
189 return cur_handle;
192 /* Delete a given memory handle from the linked list
193 and return true for success. Nothing is actually erased from memory. */
194 static bool rm_handle(struct memory_handle *h)
196 if (h == first_handle) {
197 first_handle = h->next;
198 if (h == cur_handle) {
199 /* h was the first and last handle: the buffer is now empty */
200 cur_handle = NULL;
201 buf_ridx = buf_widx;
202 } else {
203 /* update buf_ridx to point to the new first handle */
204 buf_ridx = (void *)first_handle - (void *)buffer;
206 } else {
207 struct memory_handle *m = first_handle;
208 while (m && m->next != h) {
209 m = m->next;
211 if (h && m && m->next == h) {
212 m->next = h->next;
213 if (h == cur_handle) {
214 cur_handle = m;
216 } else {
217 return false;
221 num_handles--;
222 return true;
225 /* Return a pointer to the memory handle of given ID.
226 NULL if the handle wasn't found */
227 static struct memory_handle *find_handle(int handle_id)
229 /* simple caching because most of the time the requested handle
230 will either be the same as the last, or the one after the last */
231 if (cached_handle)
233 if (cached_handle_id == handle_id &&
234 cached_handle_id == cached_handle->id)
235 return cached_handle;
236 else if (cached_handle->next && (cached_handle->next->id == handle_id))
238 /* JD's quick testing showd this block was only entered
239 2/1971 calls to find_handle.
240 8/1971 calls to find_handle resulted in a cache miss */
241 cached_handle = cached_handle->next;
242 cached_handle_id = handle_id;
243 return cached_handle;
247 struct memory_handle *m = first_handle;
248 while (m && m->id != handle_id) {
249 m = m->next;
251 cached_handle_id = handle_id;
252 cached_handle = m;
253 return (m && m->id == handle_id) ? m : NULL;
256 /* Move a memory handle and data_size of its data of delta.
257 Return a pointer to the new location of the handle.
258 delta is the value of which to move the struct data.
259 data_size is the amount of data to move along with the struct. */
260 static struct memory_handle *move_handle(struct memory_handle *h,
261 size_t *delta, size_t data_size)
263 if (*delta < 4) {
264 /* aligning backwards would yield a negative result,
265 and moving the handle of such a small amount is a waste
266 of time anyway. */
267 return NULL;
269 /* make sure delta is 32-bit aligned so that the handle struct is. */
270 *delta = (*delta - 3) & ~3;
272 size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
274 struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
276 /* Invalidate the cache to prevent it from keeping the old location of h */
277 if (h == cached_handle)
278 cached_handle = NULL;
280 /* the cur_handle pointer might need updating */
281 if (h == cur_handle) {
282 cur_handle = dest;
285 if (h == first_handle) {
286 first_handle = dest;
287 buf_ridx = newpos;
288 } else {
289 struct memory_handle *m = first_handle;
290 while (m && m->next != h) {
291 m = m->next;
293 if (h && m && m->next == h) {
294 m->next = dest;
295 } else {
296 return NULL;
300 memmove(dest, h, sizeof(struct memory_handle) + data_size);
302 return dest;
307 BUFFER SPACE MANAGEMENT
308 =======================
310 buffer_handle : Buffer data for a handle
311 free_buffer : Free buffer space by moving a handle
312 fill_buffer : Call buffer_handle for all handles that have data to buffer
313 can_add_handle : Indicate whether it's safe to add a handle.
314 data_rem : Total amount of data needing to be buffered
315 wasted_space : Total amount of space available for freeing
317 These functions are used by the buffering thread to manage buffer space.
320 /* Buffer data for the given handle. Return the amount of data buffered
321 or -1 if the handle wasn't found */
322 /* TODO: add an argument for the requested amount */
323 static ssize_t buffer_handle(int handle_id)
325 DEBUGF("buffer_handle(%d)\n", handle_id);
326 struct memory_handle *h = find_handle(handle_id);
327 if (!h)
328 return -1;
330 if (h->filerem == 0) {
331 /* nothing left to buffer */
332 return 0;
335 if (h->fd < 0) /* file closed, reopen */
337 if (*h->path)
338 h->fd = open(h->path, O_RDONLY);
339 else
340 return -1;
342 if (h->fd < 0)
343 return -1;
345 if (h->offset)
346 lseek(h->fd, h->offset, SEEK_SET);
349 trigger_cpu_boost();
351 ssize_t ret = 0;
352 while (h->filerem > 0)
354 /* max amount to copy */
355 size_t copy_n = MIN( MIN(h->filerem, conf_filechunk),
356 buffer_len - h->widx);
358 /* stop copying if it would overwrite the reading position
359 or the next handle */
360 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0 || (h->next &&
361 RINGBUF_ADD_CROSS(h->widx, copy_n, (unsigned)
362 ((void *)h->next - (void *)buffer)) > 0))
363 break;
365 /* rc is the actual amount read */
366 int rc = read(h->fd, &buffer[h->widx], copy_n);
368 if (rc < 0)
370 if (h->type == TYPE_CODEC) {
371 DEBUGF("Partial codec\n");
372 break;
375 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
376 h->filesize -= h->filerem;
377 h->filerem = 0;
378 break;
381 /* Advance buffer */
382 h->widx = RINGBUF_ADD(h->widx, rc);
383 if (h == cur_handle)
384 buf_widx = h->widx;
385 h->available += rc;
386 ret += rc;
387 h->filerem -= rc;
389 /* DEBUGF("buffer_handle(%d): buffered %ld bytes. done: %ld. remaining: %ld.\n",
390 h->id, rc, h->available, h->filerem); */
393 if (h->filerem == 0) {
394 /* finished buffering the file */
395 close(h->fd);
396 h->fd = -1;
399 DEBUGF("buffered %ld bytes (%ld of %ld available, rem: %ld, off: %ld)\n",
400 ret, h->available, h->filesize, h->filerem, h->offset);
402 return ret;
405 /* Free buffer space by moving the handle struct right before the useful
406 part of its data buffer or by moving all the data. */
407 static void free_buffer(int handle_id)
409 struct memory_handle *h = find_handle(handle_id);
410 if (!h)
411 return;
413 size_t delta;
414 /* The value of delta might change for alignment reasons */
416 if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
417 h->type == TYPE_IMAGE) && h->filerem == 0 )
419 /* metadata handle: we can move all of it */
420 delta = RINGBUF_SUB( (unsigned)((void *)h->next - (void *)buffer),
421 h->data) - h->available;
422 h = move_handle(h, &delta, h->available);
423 if (!h) return;
424 h->data = RINGBUF_ADD(h->data, delta);
425 h->ridx = RINGBUF_ADD(h->ridx, delta);
426 h->widx = RINGBUF_ADD(h->widx, delta);
428 /* when moving a struct mp3entry we need to readjust its pointers. */
429 if (h->type == TYPE_ID3 && h->filesize == sizeof(struct mp3entry)) {
430 adjust_mp3entry((struct mp3entry *)&buffer[h->data],
431 (void *)&buffer[h->data],
432 (void *)&buffer[RINGBUF_SUB(h->data, delta)]);
435 DEBUGF("free_buffer(%d): metadata, moved by %ld bytes\n",
436 handle_id, delta);
438 else
440 /* only move the handle struct */
441 delta = RINGBUF_SUB(h->ridx, h->data);
442 h = move_handle(h, &delta, 0);
443 if (!h) return;
444 h->data = RINGBUF_ADD(h->data, delta);
445 h->available -= delta;
446 h->offset += delta;
447 DEBUGF("free_buffer(%d): audio, %ld bytes freed\n", handle_id, delta);
451 /* Fill the buffer by buffering as much data as possible for handles that still
452 have data left to buffer */
453 static void fill_buffer(void)
455 DEBUGF("fill buffer()\n");
456 struct memory_handle *m = first_handle;
457 while (m) {
458 if (m->filerem > 0) {
459 buffer_handle(m->id);
461 m = m->next;
465 /* Check whether it's safe to add a new handle and reserve space to let the
466 current one finish buffering its data. Used by bufopen and bufalloc as
467 a preliminary check before even trying to physically add the handle.
468 Returns true if it's ok to add a new handle, false if not.
470 static bool can_add_handle(void)
472 if (cur_handle && cur_handle->filerem > 0) {
473 /* the current handle hasn't finished buffering. We can only add
474 a new one if there is already enough free space to finish
475 the buffering. */
476 if (cur_handle->filerem < (buffer_len - BUF_USED)) {
477 /* Before adding the new handle we reserve some space for the
478 current one to finish buffering its data. */
479 buf_widx = RINGBUF_ADD(buf_widx, cur_handle->filerem);
480 } else {
481 return false;
485 return true;
488 /* Return the total amount of data left to be buffered for all the handles */
489 static size_t data_rem(void)
491 size_t ret = 0;
493 struct memory_handle *m = first_handle;
494 while (m) {
495 ret += m->filerem;
496 m = m->next;
499 return ret;
502 /* Return the amount of data we have but don't need anymore. This data can be
503 safely erased to reclaim buffer space. */
504 static size_t wasted_space(void)
506 size_t ret = 0;
508 struct memory_handle *m = first_handle;
509 while (m) {
510 ret += RINGBUF_SUB(m->ridx, m->data);
511 m = m->next;
514 return ret;
519 BUFFERING API FUNCTIONS
520 =======================
522 bufopen : Request the opening of a new handle for a file
523 bufalloc : Open a new handle for data other than a file.
524 bufclose : Close an open handle
525 bufseek : Set the read pointer in a handle
526 bufadvance : Move the read pointer in a handle
527 bufread : Copy data from a handle into a given buffer
528 bufgetdata : Give a pointer to the handle's data
529 bufused : Return the amount of buffer space used
531 These functions are exported, to allow interaction with the buffer.
532 They take care of the content of the structs, and rely on the linked list
533 management functions for all the actual handle management work.
537 /* Request a file be buffered
538 filename: name of the file to open
539 offset: offset at which to start buffering the file, useful when the first
540 (offset-1) bytes of the file aren't needed.
541 return value: <0 if the file cannot be opened, or one file already
542 queued to be opened, otherwise the handle for the file in the buffer
544 int bufopen(char *file, size_t offset, enum data_type type)
546 if (!can_add_handle())
547 return -2;
549 int fd = open(file, O_RDONLY);
550 if (fd < 0)
551 return -1;
553 size_t size = filesize(fd) - offset;
555 if (type != TYPE_AUDIO &&
556 size + sizeof(struct memory_handle) > buffer_len - buf_widx)
558 /* for types other than audio, the data can't wrap */
559 return -2;
562 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
563 file, offset, size);
565 struct memory_handle *h = add_handle(&size);
566 if (!h)
568 DEBUGF("bufopen: failed to add handle\n");
569 close(fd);
570 return -2;
573 if (offset) lseek(fd, offset, SEEK_SET);
574 strncpy(h->path, file, MAX_PATH);
575 h->fd = fd;
576 h->filesize = filesize(fd);
577 h->filerem = h->filesize - offset;
578 h->offset = offset;
579 h->ridx = buf_widx;
580 h->widx = buf_widx;
581 h->data = buf_widx;
582 h->available = 0;
583 h->type = type;
585 DEBUGF("bufopen: allocated %ld bytes. ID: %d\n", size, h->id);
587 if (type == TYPE_CODEC || type == TYPE_CUESHEET || type == TYPE_IMAGE) {
588 /* Immediately buffer those */
589 ssize_t ret = buffer_handle(h->id);
591 /* Check that we got the complete file */
592 if ((size_t)ret != h->filesize) {
593 bufclose(h->id);
594 return -3;
598 DEBUGF("bufopen: opened handle %d\n", h->id);
599 return h->id;
602 /* Open a new handle from data that isn't in a file.
603 src is the source buffer from which to copy data. It can be NULL to simply
604 reserve buffer space.
605 size is the requested size. The call will only be successful if the
606 requested amount of data can entirely fit in the buffer without wrapping.
607 Return value is the handle id for success or <0 for failure.
609 int bufalloc(void *src, size_t size, enum data_type type)
611 if (!can_add_handle())
612 return -2;
614 if (size + sizeof(struct memory_handle) > buffer_len - buf_widx) {
615 /* The data would need to wrap. */
616 DEBUGF("bufalloc: data wrap\n");
617 return -2;
620 size_t allocsize = size;
621 struct memory_handle *h = add_handle(&allocsize);
623 if (!h || allocsize != size)
624 return -2;
626 if (src) {
627 if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) {
628 DEBUGF("bufalloc: allocating metadata\n");
629 /* specially take care of struct mp3entry */
630 copy_mp3entry((struct mp3entry *)&buffer[buf_widx],
631 (struct mp3entry *)src);
632 } else {
633 memcpy(&buffer[buf_widx], src, size);
637 h->fd = -1;
638 *h->path = 0;
639 h->filesize = size;
640 h->filerem = 0;
641 h->offset = 0;
642 h->ridx = buf_widx;
643 h->widx = buf_widx;
644 h->data = buf_widx;
645 h->available = size;
646 h->type = type;
648 buf_widx = RINGBUF_ADD(buf_widx, size);
650 DEBUGF("bufalloc: opened handle %d\n", h->id);
651 return h->id;
654 /* Close the handle. Return 0 for success and < 0 for failure */
655 int bufclose(int handle_id)
657 DEBUGF("bufclose(%d)\n", handle_id);
658 struct memory_handle *h = find_handle(handle_id);
659 if (!h)
660 return -1;
662 rm_handle(h);
663 return 0;
666 /* Set reading index in handle (relatively to the start of the file).
667 Access before the available data will trigger a rebuffer.
668 TODO: Test this
669 TODO: Maybe force an immediate rebuffer by calling buffer_handle() ?
670 Return 0 for success and < 0 for failure:
671 -1 if the handle wasn't found
672 -2 if there is no data available at the new position
673 (the reading index is still moved)
674 -3 if the new requested position was beyond the end of the file
676 int bufseek(int handle_id, size_t newpos)
678 int ret = 0;
679 struct memory_handle *h = find_handle(handle_id);
680 if (!h)
681 return -1;
683 if (newpos > h->filesize) {
684 /* access beyond the end of the file */
685 return -3;
688 else if (newpos < h->offset) {
689 /* access before what we currently have. A rebuffer is needed. */
690 h->offset = newpos;
691 h->available = 0;
692 h->filerem = h->filesize - newpos;
693 /* having changed filerem should be enough to trigger the rebuffer. */
694 h->widx = h->data;
695 ret = -2;
698 else if (newpos > h->offset + h->available) {
699 /* data isn't available yet. */
700 ret = -2;
703 h->ridx = RINGBUF_ADD(h->data, newpos);
704 return ret;
707 /* Advance the reading index in a handle (relatively to its current position).
708 Return 0 for success and < 0 for failure
709 TODO: Add some rebuffering like in bufseek */
710 int bufadvance(int handle_id, off_t offset)
712 struct memory_handle *h = find_handle(handle_id);
713 if (!h)
714 return -1;
716 if (offset >= 0)
718 /* check for access beyond what's available */
719 if ((size_t)offset > (h->available - RINGBUF_SUB(h->ridx, h->data))) {
720 DEBUGF("bufadvance: failed, access after data\n");
721 return -2;
724 h->ridx = RINGBUF_ADD(h->ridx, offset);
726 else
728 /* check for access before what's available */
729 if ((size_t)(-offset) > RINGBUF_SUB(h->ridx, h->data)) {
730 DEBUGF("bufadvance: failed, access before data\n");
731 return -2;
734 h->ridx = RINGBUF_SUB(h->ridx, (size_t)(-offset));
737 //DEBUGF("bufadvance: %ld\n", (long)offset);
738 return 0;
741 /* Copy data from the given handle to the dest buffer.
742 Return the number of bytes copied or < 0 for failure. */
743 ssize_t bufread(int handle_id, size_t size, char *dest)
745 struct memory_handle *h = find_handle(handle_id);
746 size_t buffered_data;
747 if (!h)
748 return -1;
750 if (h->available < size && h->filerem > 0) /* Data isn't ready */
751 return -2;
753 if (h->available == 0 && h->filerem == 0) /* File is finished reading */
754 return 0;
756 buffered_data = MIN(size, h->available - RINGBUF_SUB(h->ridx, h->data));
758 if (h->ridx + buffered_data > buffer_len)
760 /* the data wraps around the end of the buffer */
761 size_t read = buffer_len - h->ridx;
762 memcpy(dest, &buffer[h->ridx], read);
763 memcpy(dest+read, buffer, buffered_data - read);
765 else memcpy(dest, &buffer[h->ridx], buffered_data);
767 return buffered_data;
770 /* Update the "data" pointer to make the handle's data available to the caller.
771 Return the length of the available linear data or < 0 for failure.
772 size is the amount of linear data requested. it can be 0 to get as
773 much as possible.
774 The guard buffer may be used to provide the requested size */
775 ssize_t bufgetdata(int handle_id, size_t size, unsigned char **data)
777 struct memory_handle *h = find_handle(handle_id);
778 if (!h)
779 return -1;
781 if (h->available < size && h->filerem > 0) /* Data isn't ready */
782 return -2;
784 if (h->available == 0 && h->filerem == 0) /* File is finished reading */
785 return 0;
787 ssize_t ret;
789 if (h->ridx + size > buffer_len &&
790 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
792 /* the data wraps around the end of the buffer :
793 use the guard buffer to provide the requested amount of data. */
794 size_t copy_n = MIN(h->ridx + size - buffer_len, GUARD_BUFSIZE);
795 memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
796 ret = buffer_len - h->ridx + copy_n;
797 DEBUGF("used the guard buffer to complete\n");
799 else
801 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
802 buffer_len - h->ridx);
805 *data = (unsigned char *)&buffer[h->ridx];
807 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
808 (long)h->ridx, ret); */
809 return ret;
812 /* Return the amount of buffer space used */
813 size_t bufused(void)
815 return BUF_USED;
818 bool buffering_init(char *filebuf, size_t filebuflen)
820 if (!filebuf || !filebuflen)
821 return false;
823 buffer = filebuf;
824 buffer_len = filebuflen;
825 guard_buffer = buffer + buffer_len;
827 buf_widx = 0;
828 buf_ridx = 0;
830 first_handle = NULL;
831 num_handles = 0;
833 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
835 queue_init(&buffering_queue, true);
836 queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list);
838 return true;
841 void buffering_thread(void)
843 struct queue_event ev;
845 while (true)
847 queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
848 switch (ev.id)
850 case Q_BUFFER_HANDLE:
851 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
852 queue_reply(&buffering_queue, buffer_handle((int)ev.data));
853 break;
856 if (data_rem() > 0 && wasted_space() > buffer_len/5) {
857 DEBUGF("there is %ld bytes of wasted space\n", wasted_space());
859 /* free buffer from outdated audio data */
860 struct memory_handle *m = first_handle;
861 while (m) {
862 if (m->type == TYPE_AUDIO)
863 free_buffer(m->id);
864 m = m->next;
867 /* free buffer by moving metadata */
868 m = first_handle;
869 while (m) {
870 if (m->type != TYPE_AUDIO)
871 free_buffer(m->id);
872 m = m->next;
877 if (data_rem() > 0 && BUF_USED < 3*buffer_len/4 /* &&
878 ata_disk_is_active() */)
880 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
881 data_rem());
882 fill_buffer();
883 } /* else {
884 sleep(HZ/2);
885 } */
889 ssize_t get_offset(int handle_id, void *ptr)
891 struct memory_handle *h = find_handle(handle_id);
892 if (!h)
893 return -1;
895 return (size_t)ptr - (size_t)&buffer[h->ridx];