Free the buffer more often when there is less data in it
[Rockbox.git] / apps / buffering.c
blob3d45b411a4c7d1c26afed6da0651a976161c2d77
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"
52 #include "ata_idle_notify.h"
54 #ifdef SIMULATOR
55 #define ata_disk_is_active() 1
56 #endif
58 #if MEM > 1
59 #define GUARD_BUFSIZE (32*1024)
60 #else
61 #define GUARD_BUFSIZE (8*1024)
62 #endif
65 /* macros to enable logf for queues
66 logging on SYS_TIMEOUT can be disabled */
67 #ifdef SIMULATOR
68 /* Define this for logf output of all queuing except SYS_TIMEOUT */
69 #define BUFFERING_LOGQUEUES
70 /* Define this to logf SYS_TIMEOUT messages */
71 /* #define BUFFERING_LOGQUEUES_SYS_TIMEOUT */
72 #endif
74 #ifdef BUFFERING_LOGQUEUES
75 #define LOGFQUEUE logf
76 #else
77 #define LOGFQUEUE(...)
78 #endif
80 #ifdef BUFFERING_LOGQUEUES_SYS_TIMEOUT
81 #define LOGFQUEUE_SYS_TIMEOUT logf
82 #else
83 #define LOGFQUEUE_SYS_TIMEOUT(...)
84 #endif
87 /* amount of data to read in one read() call */
88 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
90 /* Ring buffer helper macros */
91 /* Buffer pointer (p) plus value (v), wrapped if necessary */
92 #define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
93 /* Buffer pointer (p) minus value (v), wrapped if necessary */
94 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
95 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
96 #define RINGBUF_ADD_CROSS(p1,v,p2) \
97 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
98 /* Bytes available in the buffer */
99 #define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
101 struct memory_handle {
102 int id; /* A unique ID for the handle */
103 enum data_type type;
104 char path[MAX_PATH];
105 int fd;
106 size_t data; /* Start index of the handle's data buffer */
107 size_t ridx; /* Current read pointer, relative to the main buffer */
108 size_t widx; /* Current write pointer */
109 size_t filesize; /* File total length */
110 size_t filerem; /* Remaining bytes of file NOT in buffer */
111 size_t available; /* Available bytes to read from buffer */
112 size_t offset; /* Offset at which we started reading the file */
113 struct memory_handle *next;
115 /* at all times, we have: filesize == offset + available + filerem */
118 static char *buffer;
119 static char *guard_buffer;
121 static size_t buffer_len;
123 static size_t buf_widx; /* current writing position */
124 static size_t buf_ridx; /* current reading position */
125 /* buf_*idx are values relative to the buffer, not real pointers. */
127 static size_t conf_filechunk = 0;
128 static size_t conf_watermark = 0; /* Level to trigger filebuf fill */
129 #if MEM > 8
130 static size_t high_watermark = 0; /* High watermark for rebuffer */
131 #endif
134 /* current memory handle in the linked list. NULL when the list is empty. */
135 static struct memory_handle *cur_handle;
136 /* first memory handle in the linked list. NULL when the list is empty. */
137 static struct memory_handle *first_handle;
139 static int num_handles; /* number of handles in the list */
141 /* Handle cache (makes find_handle faster).
142 These need to be global so that move_handle can invalidate them. */
143 static int cached_handle_id = -1;
144 static struct memory_handle *cached_handle = NULL;
148 LINKED LIST MANAGEMENT
149 ======================
151 add_handle : Add a handle to the list
152 rm_handle : Remove a handle from the list
153 find_handle : Get a handle pointer from an ID
154 move_handle : Move a handle in the buffer (with or without its data)
156 These functions only handle the linked list structure. They don't touch the
157 contents of the struct memory_handle headers. They also change the buf_*idx
158 pointers when necessary and manage the handle IDs.
160 The first and current (== last) handle are kept track of.
161 A new handle is added at buf_widx and becomes the current one.
162 buf_widx always points to the current writing position for the current handle
163 buf_ridx always points to the location of the first handle.
164 buf_ridx == buf_widx means the buffer is empty.
168 /* Add a new handle to the linked list and return it. It will have become the
169 new current handle. The handle will reserve "data_size" bytes or if that's
170 not possible, decrease "data_size" to allow adding the handle. */
171 static struct memory_handle *add_handle(size_t *data_size)
173 /* this will give each handle a unique id */
174 static int cur_handle_id = 1;
176 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
177 but before that we check we can actually align. */
178 if (RINGBUF_ADD_CROSS(buf_widx, 3, buf_ridx) >= 0) {
179 return NULL;
181 buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
183 size_t len = (data_size ? *data_size : 0)
184 + sizeof(struct memory_handle);
186 /* check that we actually can add the handle and its data */
187 int overlap = RINGBUF_ADD_CROSS(buf_widx, len, buf_ridx);
188 if (overlap >= 0) {
189 *data_size -= overlap;
190 len -= overlap;
192 if (len < sizeof(struct memory_handle)) {
193 /* There isn't even enough space to write the struct */
194 return NULL;
197 struct memory_handle *new_handle =
198 (struct memory_handle *)(&buffer[buf_widx]);
200 /* only advance the buffer write index of the size of the struct */
201 buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
203 if (!first_handle) {
204 /* the new handle is the first one */
205 first_handle = new_handle;
208 if (cur_handle) {
209 cur_handle->next = new_handle;
212 cur_handle = new_handle;
213 cur_handle->id = cur_handle_id++;
214 cur_handle->next = NULL;
215 num_handles++;
216 return cur_handle;
219 /* Delete a given memory handle from the linked list
220 and return true for success. Nothing is actually erased from memory. */
221 static bool rm_handle(struct memory_handle *h)
223 if (h == first_handle) {
224 first_handle = h->next;
225 if (h == cur_handle) {
226 /* h was the first and last handle: the buffer is now empty */
227 cur_handle = NULL;
228 buf_ridx = buf_widx;
229 } else {
230 /* update buf_ridx to point to the new first handle */
231 buf_ridx = (void *)first_handle - (void *)buffer;
233 } else {
234 struct memory_handle *m = first_handle;
235 while (m && m->next != h) {
236 m = m->next;
238 if (h && m && m->next == h) {
239 m->next = h->next;
240 if (h == cur_handle) {
241 cur_handle = m;
243 } else {
244 return false;
248 num_handles--;
249 return true;
252 /* Return a pointer to the memory handle of given ID.
253 NULL if the handle wasn't found */
254 static struct memory_handle *find_handle(int handle_id)
256 /* simple caching because most of the time the requested handle
257 will either be the same as the last, or the one after the last */
258 if (cached_handle)
260 if (cached_handle_id == handle_id &&
261 cached_handle_id == cached_handle->id)
262 return cached_handle;
263 else if (cached_handle->next && (cached_handle->next->id == handle_id))
265 /* JD's quick testing showd this block was only entered
266 2/1971 calls to find_handle.
267 8/1971 calls to find_handle resulted in a cache miss */
268 cached_handle = cached_handle->next;
269 cached_handle_id = handle_id;
270 return cached_handle;
274 struct memory_handle *m = first_handle;
275 while (m && m->id != handle_id) {
276 m = m->next;
278 cached_handle_id = handle_id;
279 cached_handle = m;
280 return (m && m->id == handle_id) ? m : NULL;
283 /* Move a memory handle and data_size of its data of delta.
284 Return a pointer to the new location of the handle.
285 delta is the value of which to move the struct data.
286 data_size is the amount of data to move along with the struct. */
287 static struct memory_handle *move_handle(struct memory_handle *h,
288 size_t *delta, size_t data_size)
290 if (*delta < 4) {
291 /* aligning backwards would yield a negative result,
292 and moving the handle of such a small amount is a waste
293 of time anyway. */
294 return NULL;
296 /* make sure delta is 32-bit aligned so that the handle struct is. */
297 *delta = (*delta - 3) & ~3;
299 size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
301 struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
303 /* Invalidate the cache to prevent it from keeping the old location of h */
304 if (h == cached_handle)
305 cached_handle = NULL;
307 /* the cur_handle pointer might need updating */
308 if (h == cur_handle) {
309 cur_handle = dest;
312 if (h == first_handle) {
313 first_handle = dest;
314 buf_ridx = newpos;
315 } else {
316 struct memory_handle *m = first_handle;
317 while (m && m->next != h) {
318 m = m->next;
320 if (h && m && m->next == h) {
321 m->next = dest;
322 } else {
323 return NULL;
327 memmove(dest, h, sizeof(struct memory_handle) + data_size);
329 return dest;
334 BUFFER SPACE MANAGEMENT
335 =======================
337 yield_codec : Used by buffer_handle to know if it should interrupt buffering
338 buffer_handle : Buffer data for a handle
339 reset_handle : Reset writing position and data buffer of a handle to its
340 current offset
341 rebuffer_handle : Seek to a nonbuffered part of a handle by rebuffering the data
342 shrink_handle : Free buffer space by moving a handle
343 fill_buffer : Call buffer_handle for all handles that have data to buffer
344 can_add_handle : Indicate whether it's safe to add a handle
345 data_rem : Total amount of data needing to be buffered
346 wasted_space : Total amount of space available for freeing
347 buffered_data : Total amount of data currently in the buffer
349 These functions are used by the buffering thread to manage buffer space.
352 static bool filebuf_is_lowdata(void)
354 return BUF_USED < AUDIO_FILEBUF_CRITICAL;
357 /* Yield to the codec thread for as long as possible if it is in need of data.
358 Return true if the caller should break to let the buffering thread process
359 new queue events */
360 static bool yield_codec(void)
362 yield();
364 if (!queue_empty(&buffering_queue))
365 return true;
367 while (pcmbuf_is_lowdata() && !filebuf_is_lowdata())
369 sleep(2);
371 if (!queue_empty(&buffering_queue))
372 return true;
375 return false;
378 /* Buffer data for the given handle. Return the amount of data buffered
379 or -1 if the handle wasn't found */
380 static ssize_t buffer_handle(int handle_id)
382 DEBUGF("buffer_handle(%d)\n", handle_id);
383 struct memory_handle *h = find_handle(handle_id);
384 if (!h)
385 return -1;
387 if (h->filerem == 0) {
388 /* nothing left to buffer */
389 return 0;
392 if (h->fd < 0) /* file closed, reopen */
394 if (*h->path)
395 h->fd = open(h->path, O_RDONLY);
396 else
397 return -1;
399 if (h->fd < 0)
400 return -1;
402 if (h->offset)
403 lseek(h->fd, h->offset, SEEK_SET);
406 trigger_cpu_boost();
408 ssize_t ret = 0;
409 while (h->filerem > 0)
411 /* max amount to copy */
412 size_t copy_n = MIN( MIN(h->filerem, conf_filechunk),
413 buffer_len - h->widx);
415 /* stop copying if it would overwrite the reading position
416 or the next handle */
417 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0 || (h->next &&
418 RINGBUF_ADD_CROSS(h->widx, copy_n, (unsigned)
419 ((void *)h->next - (void *)buffer)) > 0))
420 break;
422 /* rc is the actual amount read */
423 int rc = read(h->fd, &buffer[h->widx], copy_n);
425 if (rc < 0)
427 if (h->type == TYPE_CODEC) {
428 DEBUGF("Partial codec\n");
429 break;
432 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
433 h->filesize -= h->filerem;
434 h->filerem = 0;
435 break;
438 /* Advance buffer */
439 h->widx = RINGBUF_ADD(h->widx, rc);
440 if (h == cur_handle)
441 buf_widx = h->widx;
442 h->available += rc;
443 ret += rc;
444 h->filerem -= rc;
446 /* DEBUGF("buffer_handle(%d): buffered %ld bytes. done: %ld. remaining: %ld.\n",
447 h->id, rc, h->available, h->filerem); */
449 /* Stop buffering if new queue events have arrived */
450 if (yield_codec())
451 break;
454 if (h->filerem == 0) {
455 /* finished buffering the file */
456 close(h->fd);
457 h->fd = -1;
460 DEBUGF("buffered %ld bytes (%ld of %ld available, rem: %ld, off: %ld)\n",
461 (long)ret, (long)h->available, (long)h->filesize,
462 (long)h->filerem, (long)h->offset);
464 return ret;
467 /* Reset writing position and data buffer of a handle to its current offset.
468 Use this after having set the new offset to use.
469 Returns 0 for success or -1 if the handle wasn't found. */
470 static void reset_handle(int handle_id)
472 DEBUGF("reset_handle(%d)\n", handle_id);
474 struct memory_handle *h = find_handle(handle_id);
475 if (!h)
476 return;
478 h->widx = h->data;
479 if (h == cur_handle)
480 buf_widx = h->widx;
481 h->available = 0;
482 h->filerem = h->filesize - h->offset;
484 if (h->fd >= 0) {
485 lseek(h->fd, h->offset, SEEK_SET);
489 /* Seek to a nonbuffered part of a handle by rebuffering the data. */
490 static void rebuffer_handle(int handle_id, size_t newpos)
492 struct memory_handle *h = find_handle(handle_id);
493 if (!h)
494 return;
496 DEBUGF("rebuffer_handle: resetting the handle to offset %ld\n", (long)newpos);
497 h->offset = newpos;
499 LOGFQUEUE("? >| buffering Q_RESET_HANDLE");
500 queue_send(&buffering_queue, Q_RESET_HANDLE, handle_id);
502 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
503 queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
505 h->ridx = h->data;
508 /* Free buffer space by moving the handle struct right before the useful
509 part of its data buffer or by moving all the data. */
510 static void shrink_handle(int handle_id)
512 struct memory_handle *h = find_handle(handle_id);
513 if (!h)
514 return;
516 size_t delta;
517 /* The value of delta might change for alignment reasons */
519 if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
520 h->type == TYPE_IMAGE) && h->filerem == 0 )
522 /* metadata handle: we can move all of it */
523 delta = RINGBUF_SUB( (unsigned)((void *)h->next - (void *)buffer),
524 h->data) - h->available;
525 h = move_handle(h, &delta, h->available);
526 if (!h) return;
527 h->data = RINGBUF_ADD(h->data, delta);
528 h->ridx = RINGBUF_ADD(h->ridx, delta);
529 h->widx = RINGBUF_ADD(h->widx, delta);
531 /* when moving a struct mp3entry we need to readjust its pointers. */
532 if (h->type == TYPE_ID3 && h->filesize == sizeof(struct mp3entry)) {
533 adjust_mp3entry((struct mp3entry *)&buffer[h->data],
534 (void *)&buffer[h->data],
535 (void *)&buffer[RINGBUF_SUB(h->data, delta)]);
538 DEBUGF("shrink_handle(%d): metadata, moved by %ld bytes\n",
539 handle_id, (long)delta);
541 else
543 /* only move the handle struct */
544 delta = RINGBUF_SUB(h->ridx, h->data);
545 h = move_handle(h, &delta, 0);
546 if (!h) return;
547 h->data = RINGBUF_ADD(h->data, delta);
548 h->available -= delta;
549 h->offset += delta;
550 DEBUGF("shrink_handle(%d): audio, %ld bytes freed\n",
551 handle_id, (long)delta);
555 /* Fill the buffer by buffering as much data as possible for handles that still
556 have data left to buffer */
557 static void fill_buffer(void)
559 DEBUGF("fill buffer()\n");
560 struct memory_handle *m = first_handle;
561 while (m) {
562 if (m->filerem > 0) {
563 buffer_handle(m->id);
565 m = m->next;
569 /* Check whether it's safe to add a new handle and reserve space to let the
570 current one finish buffering its data. Used by bufopen and bufalloc as
571 a preliminary check before even trying to physically add the handle.
572 Returns true if it's ok to add a new handle, false if not.
574 static bool can_add_handle(void)
576 if (cur_handle && cur_handle->filerem > 0) {
577 /* the current handle hasn't finished buffering. We can only add
578 a new one if there is already enough free space to finish
579 the buffering. */
580 if (cur_handle->filerem < (buffer_len - BUF_USED)) {
581 /* Before adding the new handle we reserve some space for the
582 current one to finish buffering its data. */
583 buf_widx = RINGBUF_ADD(buf_widx, cur_handle->filerem);
584 } else {
585 return false;
589 return true;
592 /* Return the total amount of data left to be buffered for all the handles */
593 static size_t data_rem(void)
595 size_t ret = 0;
597 struct memory_handle *m = first_handle;
598 while (m) {
599 ret += m->filerem;
600 m = m->next;
603 return ret;
606 /* Return the amount of data we have but don't need anymore. This data can be
607 safely erased to reclaim buffer space. */
608 static size_t wasted_space(void)
610 size_t ret = 0;
612 struct memory_handle *m = first_handle;
613 while (m) {
614 ret += RINGBUF_SUB(m->ridx, m->data);
615 m = m->next;
618 return ret;
621 static size_t buffered_data(void)
623 size_t ret = 0;
624 struct memory_handle *m = first_handle;
625 while (m) {
626 ret += m->available;
627 m = m->next;
629 return ret;
634 BUFFERING API FUNCTIONS
635 =======================
637 bufopen : Request the opening of a new handle for a file
638 bufalloc : Open a new handle for data other than a file.
639 bufclose : Close an open handle
640 bufseek : Set the read pointer in a handle
641 bufadvance : Move the read pointer in a handle
642 bufread : Copy data from a handle into a given buffer
643 bufgetdata : Give a pointer to the handle's data
644 bufused : Return the amount of buffer space used
646 These functions are exported, to allow interaction with the buffer.
647 They take care of the content of the structs, and rely on the linked list
648 management functions for all the actual handle management work.
652 /* Reserve space in the buffer for a file.
653 filename: name of the file to open
654 offset: offset at which to start buffering the file, useful when the first
655 (offset-1) bytes of the file aren't needed.
656 return value: <0 if the file cannot be opened, or one file already
657 queued to be opened, otherwise the handle for the file in the buffer
659 int bufopen(char *file, size_t offset, enum data_type type)
661 if (!can_add_handle())
662 return -2;
664 int fd = open(file, O_RDONLY);
665 if (fd < 0)
666 return -1;
668 size_t size = filesize(fd) - offset;
670 if (type != TYPE_AUDIO &&
671 size + sizeof(struct memory_handle) > buffer_len - buf_widx)
673 /* for types other than audio, the data can't wrap, so we force it */
674 buf_widx = 0;
677 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
678 file, (long)offset, (long)size);
680 struct memory_handle *h = add_handle(&size);
681 if (!h)
683 DEBUGF("bufopen: failed to add handle\n");
684 close(fd);
685 return -2;
688 strncpy(h->path, file, MAX_PATH);
689 h->fd = -1;
690 h->filesize = filesize(fd);
691 h->filerem = h->filesize - offset;
692 h->offset = offset;
693 h->ridx = buf_widx;
694 h->widx = buf_widx;
695 h->data = buf_widx;
696 h->available = 0;
697 h->type = type;
699 close(fd);
701 DEBUGF("bufopen: allocated %ld bytes. ID: %d\n", (long)size, h->id);
703 if (type == TYPE_CODEC || type == TYPE_CUESHEET || type == TYPE_IMAGE) {
704 /* Immediately buffer those */
705 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
706 queue_send(&buffering_queue, Q_BUFFER_HANDLE, h->id);
709 DEBUGF("bufopen: opened handle %d\n", h->id);
710 return h->id;
713 /* Open a new handle from data that needs to be copied from memory.
714 src is the source buffer from which to copy data. It can be NULL to simply
715 reserve buffer space.
716 size is the requested size. The call will only be successful if the
717 requested amount of data can entirely fit in the buffer without wrapping.
718 Return value is the handle id for success or <0 for failure.
720 int bufalloc(void *src, size_t size, enum data_type type)
722 if (!can_add_handle())
723 return -2;
725 if (size + sizeof(struct memory_handle) > buffer_len - buf_widx) {
726 /* The data would need to wrap. */
727 DEBUGF("bufalloc: data wrap\n");
728 return -2;
731 size_t allocsize = size;
732 struct memory_handle *h = add_handle(&allocsize);
734 if (!h || allocsize != size)
735 return -2;
737 if (src) {
738 if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) {
739 DEBUGF("bufalloc: allocating metadata\n");
740 /* specially take care of struct mp3entry */
741 copy_mp3entry((struct mp3entry *)&buffer[buf_widx],
742 (struct mp3entry *)src);
743 } else {
744 memcpy(&buffer[buf_widx], src, size);
748 h->fd = -1;
749 *h->path = 0;
750 h->filesize = size;
751 h->filerem = 0;
752 h->offset = 0;
753 h->ridx = buf_widx;
754 h->widx = buf_widx;
755 h->data = buf_widx;
756 h->available = size;
757 h->type = type;
759 buf_widx = RINGBUF_ADD(buf_widx, size);
761 DEBUGF("bufalloc: opened handle %d\n", h->id);
762 return h->id;
765 /* Close the handle. Return 0 for success and < 0 for failure */
766 int bufclose(int handle_id)
768 DEBUGF("bufclose(%d)\n", handle_id);
769 struct memory_handle *h = find_handle(handle_id);
770 if (!h)
771 return -1;
773 if (h->fd >= 0) {
774 close(h->fd);
775 h->fd = -1;
778 rm_handle(h);
779 return 0;
782 /* Set reading index in handle (relatively to the start of the file).
783 Access before the available data will trigger a rebuffer.
784 Return 0 for success and < 0 for failure:
785 -1 if the handle wasn't found
786 -2 if the new requested position was beyond the end of the file
788 int bufseek(int handle_id, size_t newpos)
790 struct memory_handle *h = find_handle(handle_id);
791 if (!h)
792 return -1;
794 if (newpos > h->filesize) {
795 /* access beyond the end of the file */
796 return -3;
798 else if (newpos < h->offset || h->offset + h->available < newpos) {
799 /* access before or after buffered data. A rebuffer is needed. */
800 rebuffer_handle(handle_id, newpos);
802 else {
803 h->ridx = RINGBUF_ADD(h->data, newpos - h->offset);
805 return 0;
808 /* Advance the reading index in a handle (relatively to its current position).
809 Return 0 for success and < 0 for failure */
810 int bufadvance(int handle_id, off_t offset)
812 struct memory_handle *h = find_handle(handle_id);
813 if (!h)
814 return -1;
816 size_t newpos = h->offset + RINGBUF_SUB(h->ridx, h->data) + offset;
818 return bufseek(handle_id, newpos);
821 /* Copy data from the given handle to the dest buffer.
822 Return the number of bytes copied or < 0 for failure. */
823 ssize_t bufread(int handle_id, size_t size, void *dest)
825 struct memory_handle *h = find_handle(handle_id);
826 size_t buffered_data;
827 if (!h)
828 return -1;
830 if (size == 0 && h->filerem > 0 &&
831 h->available - RINGBUF_SUB(h->ridx, h->data) == 0)
832 /* Data isn't ready */
833 return -2;
835 if (h->available - RINGBUF_SUB(h->ridx, h->data) < size && h->filerem > 0)
836 /* Data isn't ready */
837 return -2;
839 if (h->available - RINGBUF_SUB(h->ridx, h->data) == 0 && h->filerem == 0)
840 /* File is finished reading */
841 return 0;
843 buffered_data = MIN(size, h->available - RINGBUF_SUB(h->ridx, h->data));
845 if (h->ridx + buffered_data > buffer_len)
847 /* the data wraps around the end of the buffer */
848 size_t read = buffer_len - h->ridx;
849 memcpy(dest, &buffer[h->ridx], read);
850 memcpy(dest+read, buffer, buffered_data - read);
852 else memcpy(dest, &buffer[h->ridx], buffered_data);
854 return buffered_data;
857 /* Update the "data" pointer to make the handle's data available to the caller.
858 Return the length of the available linear data or < 0 for failure.
859 size is the amount of linear data requested. it can be 0 to get as
860 much as possible.
861 The guard buffer may be used to provide the requested size */
862 ssize_t bufgetdata(int handle_id, size_t size, void **data)
864 struct memory_handle *h = find_handle(handle_id);
865 if (!h)
866 return -1;
868 if (size == 0 && h->filerem > 0 &&
869 h->available - RINGBUF_SUB(h->ridx, h->data) == 0)
870 /* Data isn't ready */
871 return -2;
873 if (h->available - RINGBUF_SUB(h->ridx, h->data) < size && h->filerem > 0)
874 /* Data isn't ready */
875 return -2;
877 if (h->available - RINGBUF_SUB(h->ridx, h->data) == 0 && h->filerem == 0)
878 /* File is finished reading */
879 return 0;
881 ssize_t ret;
883 if (h->ridx + size > buffer_len &&
884 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
886 /* the data wraps around the end of the buffer :
887 use the guard buffer to provide the requested amount of data. */
888 size_t copy_n = MIN(h->ridx + size - buffer_len, GUARD_BUFSIZE);
889 memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
890 ret = buffer_len - h->ridx + copy_n;
891 DEBUGF("used the guard buffer to complete\n");
893 else
895 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
896 buffer_len - h->ridx);
899 *data = &buffer[h->ridx];
901 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
902 (long)h->ridx, ret); */
903 return ret;
906 /* Return the amount of buffer space used */
907 size_t bufused(void)
909 return BUF_USED;
912 /* Initialise the buffering subsystem */
913 bool buffering_init(char *filebuf, size_t filebuflen)
915 if (!filebuf || !filebuflen)
916 return false;
918 buffer = filebuf;
919 buffer_len = filebuflen;
920 guard_buffer = buffer + buffer_len;
922 buf_widx = 0;
923 buf_ridx = 0;
925 first_handle = NULL;
926 num_handles = 0;
928 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
929 conf_watermark = AUDIO_DEFAULT_WATERMARK;
931 /* Set the high watermark as 75% full...or 25% empty :) */
932 #if MEM > 8
933 high_watermark = 3*filebuflen / 4;
934 #endif
936 queue_init(&buffering_queue, true);
937 queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list);
939 return true;
942 #if MEM > 8
943 /* we dont want this rebuffering on targets with little ram
944 because the disk may never spin down */
945 static bool ata_fillbuffer_callback(void)
947 queue_post(&buffering_queue, Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA, 0);
948 return true;
950 #endif
952 void buffering_thread(void)
954 struct queue_event ev;
956 while (true)
958 queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
960 #if MEM > 8
961 if ((ev.id == SYS_TIMEOUT) && (buffered_data() < high_watermark))
962 register_ata_idle_func(ata_fillbuffer_callback);
963 #endif
965 switch (ev.id)
967 case Q_BUFFER_HANDLE:
968 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
969 queue_reply(&buffering_queue, 1);
970 buffer_handle((int)ev.data);
971 break;
973 case Q_RESET_HANDLE:
974 LOGFQUEUE("buffering < Q_RESET_HANDLE");
975 queue_reply(&buffering_queue, 1);
976 reset_handle((int)ev.data);
977 break;
980 #if MEM > 8
981 case Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA:
982 /* only fill if the disk is still spining */
983 #ifndef SIMULATOR
984 if (!ata_disk_is_active())
985 break;
986 #endif
987 fill_buffer();
988 break;
989 #endif /* MEM > 8 */
991 #ifndef SIMULATOR
992 case SYS_USB_CONNECTED:
993 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
994 usb_acknowledge(SYS_USB_CONNECTED_ACK);
995 usb_wait_for_disconnect(&buffering_queue);
996 break;
997 #endif
999 case SYS_TIMEOUT:
1000 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1001 break;
1004 if (queue_empty(&buffering_queue) &&
1005 data_rem() > 0 && wasted_space() > buffered_data()/2) {
1006 DEBUGF("there is %ld bytes of wasted space\n", (long)wasted_space());
1008 /* free buffer from outdated audio data */
1009 struct memory_handle *m = first_handle;
1010 while (m) {
1011 if (m->type == TYPE_AUDIO)
1012 shrink_handle(m->id);
1013 m = m->next;
1016 /* free buffer by moving metadata */
1017 m = first_handle;
1018 while (m) {
1019 if (m->type != TYPE_AUDIO)
1020 shrink_handle(m->id);
1021 m = m->next;
1026 if (queue_empty(&buffering_queue) &&
1027 data_rem() > 0 && buffered_data() < conf_watermark)
1029 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
1030 (long)data_rem());
1031 fill_buffer();
1036 /* Get a buffer offset from a pointer */
1037 ssize_t get_offset(int handle_id, void *ptr)
1039 struct memory_handle *h = find_handle(handle_id);
1040 if (!h)
1041 return -1;
1043 return (size_t)ptr - (size_t)&buffer[h->ridx];
1046 void buffering_get_debugdata(struct buffering_debug *dbgdata)
1048 dbgdata->num_handles = num_handles;
1049 dbgdata->data_rem = data_rem();
1050 dbgdata->wasted_space = wasted_space();
1051 dbgdata->buffered_data = buffered_data();