Replace yield_codec() with a call to queue_wait_w_tmo()
[Rockbox.git] / apps / buffering.c
blobfceb8747c88d8d99dd8a43669485b8a617a963ba
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;
242 buf_widx = cur_handle->widx;
244 } else {
245 return false;
249 num_handles--;
250 return true;
253 /* Return a pointer to the memory handle of given ID.
254 NULL if the handle wasn't found */
255 static struct memory_handle *find_handle(int handle_id)
257 /* simple caching because most of the time the requested handle
258 will either be the same as the last, or the one after the last */
259 if (cached_handle)
261 if (cached_handle_id == handle_id &&
262 cached_handle_id == cached_handle->id)
263 return cached_handle;
264 else if (cached_handle->next && (cached_handle->next->id == handle_id))
266 /* JD's quick testing showd this block was only entered
267 2/1971 calls to find_handle.
268 8/1971 calls to find_handle resulted in a cache miss */
269 cached_handle = cached_handle->next;
270 cached_handle_id = handle_id;
271 return cached_handle;
275 struct memory_handle *m = first_handle;
276 while (m && m->id != handle_id) {
277 m = m->next;
279 cached_handle_id = handle_id;
280 cached_handle = m;
281 return (m && m->id == handle_id) ? m : NULL;
284 /* Move a memory handle and data_size of its data of delta.
285 Return a pointer to the new location of the handle.
286 delta is the value of which to move the struct data.
287 data_size is the amount of data to move along with the struct. */
288 static struct memory_handle *move_handle(struct memory_handle *h,
289 size_t *delta, size_t data_size)
291 if (*delta < 4) {
292 /* aligning backwards would yield a negative result,
293 and moving the handle of such a small amount is a waste
294 of time anyway. */
295 return NULL;
297 /* make sure delta is 32-bit aligned so that the handle struct is. */
298 *delta = (*delta - 3) & ~3;
300 size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
302 struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
304 /* Invalidate the cache to prevent it from keeping the old location of h */
305 if (h == cached_handle)
306 cached_handle = NULL;
308 /* the cur_handle pointer might need updating */
309 if (h == cur_handle) {
310 cur_handle = dest;
313 if (h == first_handle) {
314 first_handle = dest;
315 buf_ridx = newpos;
316 } else {
317 struct memory_handle *m = first_handle;
318 while (m && m->next != h) {
319 m = m->next;
321 if (h && m && m->next == h) {
322 m->next = dest;
323 } else {
324 return NULL;
328 memmove(dest, h, sizeof(struct memory_handle) + data_size);
330 return dest;
335 BUFFER SPACE MANAGEMENT
336 =======================
338 yield_codec : Used by buffer_handle to know if it should interrupt buffering
339 buffer_handle : Buffer data for a handle
340 reset_handle : Reset writing position and data buffer of a handle to its
341 current offset
342 rebuffer_handle : Seek to a nonbuffered part of a handle by rebuffering the data
343 shrink_handle : Free buffer space by moving a handle
344 fill_buffer : Call buffer_handle for all handles that have data to buffer
345 can_add_handle : Indicate whether it's safe to add a handle
346 data_rem : Total amount of data needing to be buffered
347 wasted_space : Total amount of space available for freeing
348 buffered_data : Total amount of data currently in the buffer
350 These functions are used by the buffering thread to manage buffer space.
353 static bool filebuf_is_lowdata(void)
355 return BUF_USED < AUDIO_FILEBUF_CRITICAL;
358 /* Buffer data for the given handle. Return when finished or when an event was
359 received on the buffering queue.
360 ev is where queue events will be received. If buffering wasn't interrupted,
361 ev->id == SYS_TIMEOUT.
362 Return value is the amount of data buffered, or -1 if the handle wasn't found
364 static ssize_t buffer_handle(int handle_id, struct queue_event *ev)
366 DEBUGF("buffer_handle(%d)\n", handle_id);
367 struct memory_handle *h = find_handle(handle_id);
368 if (!h)
369 return -1;
371 if (h->filerem == 0) {
372 /* nothing left to buffer */
373 return 0;
376 if (h->fd < 0) /* file closed, reopen */
378 if (*h->path)
379 h->fd = open(h->path, O_RDONLY);
380 else
381 return -1;
383 if (h->fd < 0)
384 return -1;
386 if (h->offset)
387 lseek(h->fd, h->offset, SEEK_SET);
390 trigger_cpu_boost();
392 ssize_t ret = 0;
393 while (h->filerem > 0)
395 /* max amount to copy */
396 size_t copy_n = MIN( MIN(h->filerem, conf_filechunk),
397 buffer_len - h->widx);
399 /* stop copying if it would overwrite the reading position
400 or the next handle */
401 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0 || (h->next &&
402 RINGBUF_ADD_CROSS(h->widx, copy_n, (unsigned)
403 ((void *)h->next - (void *)buffer)) > 0))
404 break;
406 /* rc is the actual amount read */
407 int rc = read(h->fd, &buffer[h->widx], copy_n);
409 if (rc < 0)
411 if (h->type == TYPE_CODEC) {
412 DEBUGF("Partial codec\n");
413 break;
416 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
417 h->filesize -= h->filerem;
418 h->filerem = 0;
419 break;
422 /* Advance buffer */
423 h->widx = RINGBUF_ADD(h->widx, rc);
424 if (h == cur_handle)
425 buf_widx = h->widx;
426 h->available += rc;
427 ret += rc;
428 h->filerem -= rc;
430 /* DEBUGF("buffer_handle(%d): buffered %ld bytes. done: %ld. remaining: %ld.\n",
431 h->id, rc, h->available, h->filerem); */
433 /* Sleep a bit and stop buffering if new queue events have arrived */
434 queue_wait_w_tmo(&buffering_queue, ev, 10);
436 if (ev->id == Q_BUFFER_HANDLE && (int)ev->data == handle_id) {
437 /* Don't stop buffering if the request is to buffer the same file */
438 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
439 DEBUGF("buffer_handle: continuing buffering of handle %d\n",
440 handle_id);
442 else if (ev->id != SYS_TIMEOUT) {
443 /* An event was received, break the loop so it can be treated */
444 DEBUGF("buffer_handle: event received, interrupting buffering\n");
445 break;
449 if (h->filerem == 0) {
450 /* finished buffering the file */
451 close(h->fd);
452 h->fd = -1;
455 DEBUGF("buffer_handle(%d): buffered %ld bytes (%ld of %ld available, "
456 "rem: %ld, off: %ld)\n",
457 handle_id, (long)ret, (long)h->available, (long)h->filesize,
458 (long)h->filerem, (long)h->offset);
460 return ret;
463 /* Reset writing position and data buffer of a handle to its current offset.
464 Use this after having set the new offset to use.
465 Returns 0 for success or -1 if the handle wasn't found. */
466 static void reset_handle(int handle_id)
468 DEBUGF("reset_handle(%d)\n", handle_id);
470 struct memory_handle *h = find_handle(handle_id);
471 if (!h)
472 return;
474 h->widx = h->data;
475 if (h == cur_handle)
476 buf_widx = h->widx;
477 h->available = 0;
478 h->filerem = h->filesize - h->offset;
480 if (h->fd >= 0) {
481 lseek(h->fd, h->offset, SEEK_SET);
485 /* Seek to a nonbuffered part of a handle by rebuffering the data. */
486 static void rebuffer_handle(int handle_id, size_t newpos)
488 struct memory_handle *h = find_handle(handle_id);
489 if (!h)
490 return;
492 DEBUGF("rebuffer_handle: resetting the handle to offset %ld\n", (long)newpos);
493 h->offset = newpos;
495 LOGFQUEUE("? >| buffering Q_RESET_HANDLE");
496 queue_send(&buffering_queue, Q_RESET_HANDLE, handle_id);
498 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
499 queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
501 h->ridx = h->data;
504 /* Free buffer space by moving the handle struct right before the useful
505 part of its data buffer or by moving all the data. */
506 static void shrink_handle(int handle_id)
508 struct memory_handle *h = find_handle(handle_id);
509 if (!h)
510 return;
512 size_t delta;
513 /* The value of delta might change for alignment reasons */
515 if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
516 h->type == TYPE_IMAGE) && h->filerem == 0 )
518 /* metadata handle: we can move all of it */
519 delta = RINGBUF_SUB( (unsigned)((void *)h->next - (void *)buffer),
520 h->data) - h->available;
521 h = move_handle(h, &delta, h->available);
522 if (!h) return;
523 h->data = RINGBUF_ADD(h->data, delta);
524 h->ridx = RINGBUF_ADD(h->ridx, delta);
525 h->widx = RINGBUF_ADD(h->widx, delta);
527 /* when moving a struct mp3entry we need to readjust its pointers. */
528 if (h->type == TYPE_ID3 && h->filesize == sizeof(struct mp3entry)) {
529 adjust_mp3entry((struct mp3entry *)&buffer[h->data],
530 (void *)&buffer[h->data],
531 (void *)&buffer[RINGBUF_SUB(h->data, delta)]);
534 DEBUGF("shrink_handle(%d): metadata, moved by %ld bytes\n",
535 handle_id, (long)delta);
537 else
539 /* only move the handle struct */
540 delta = RINGBUF_SUB(h->ridx, h->data);
541 h = move_handle(h, &delta, 0);
542 if (!h) return;
543 h->data = RINGBUF_ADD(h->data, delta);
544 h->available -= delta;
545 h->offset += delta;
546 DEBUGF("shrink_handle(%d): audio, %ld bytes freed\n",
547 handle_id, (long)delta);
551 /* Fill the buffer by buffering as much data as possible for handles that still
552 have data left to buffer */
553 static void fill_buffer(struct queue_event *ev)
555 DEBUGF("fill buffer()\n");
556 struct memory_handle *m = first_handle;
557 while (m) {
558 if (m->filerem > 0) {
559 buffer_handle(m->id, ev);
560 if (ev->id != SYS_TIMEOUT)
561 return;
563 m = m->next;
567 /* Check whether it's safe to add a new handle and reserve space to let the
568 current one finish buffering its data. Used by bufopen and bufalloc as
569 a preliminary check before even trying to physically add the handle.
570 Returns true if it's ok to add a new handle, false if not.
572 static bool can_add_handle(void)
574 if (cur_handle && cur_handle->filerem > 0) {
575 /* the current handle hasn't finished buffering. We can only add
576 a new one if there is already enough free space to finish
577 the buffering. */
578 if (cur_handle->filerem < (buffer_len - BUF_USED)) {
579 /* Before adding the new handle we reserve some space for the
580 current one to finish buffering its data. */
581 buf_widx = RINGBUF_ADD(buf_widx, cur_handle->filerem);
582 } else {
583 return false;
587 return true;
590 /* Return the total amount of data left to be buffered for all the handles */
591 static size_t data_rem(void)
593 size_t ret = 0;
595 struct memory_handle *m = first_handle;
596 while (m) {
597 ret += m->filerem;
598 m = m->next;
601 return ret;
604 /* Return the amount of data we have but don't need anymore. This data can be
605 safely erased to reclaim buffer space. */
606 static size_t wasted_space(void)
608 size_t ret = 0;
610 struct memory_handle *m = first_handle;
611 while (m) {
612 ret += RINGBUF_SUB(m->ridx, m->data);
613 m = m->next;
616 return ret;
619 static size_t buffered_data(void)
621 size_t ret = 0;
622 struct memory_handle *m = first_handle;
623 while (m) {
624 ret += m->available;
625 m = m->next;
627 return ret;
632 BUFFERING API FUNCTIONS
633 =======================
635 bufopen : Request the opening of a new handle for a file
636 bufalloc : Open a new handle for data other than a file.
637 bufclose : Close an open handle
638 bufseek : Set the read pointer in a handle
639 bufadvance : Move the read pointer in a handle
640 bufread : Copy data from a handle into a given buffer
641 bufgetdata : Give a pointer to the handle's data
642 bufused : Return the amount of buffer space used
644 These functions are exported, to allow interaction with the buffer.
645 They take care of the content of the structs, and rely on the linked list
646 management functions for all the actual handle management work.
650 /* Reserve space in the buffer for a file.
651 filename : name of the file to open
652 offset : offset at which to start buffering the file, useful when the first
653 (offset-1) bytes of the file aren't needed.
654 returns : <0 if the file cannot be opened, or one file already
655 queued to be opened, otherwise the handle for the file in the buffer
657 int bufopen(char *file, size_t offset, enum data_type type)
659 if (!can_add_handle())
660 return -2;
662 int fd = open(file, O_RDONLY);
663 if (fd < 0)
664 return -1;
666 size_t size = filesize(fd) - offset;
668 if (type != TYPE_AUDIO &&
669 size + sizeof(struct memory_handle) > buffer_len - buf_widx)
671 /* for types other than audio, the data can't wrap, so we force it */
672 buf_widx = 0;
675 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
676 file, (long)offset, (long)size);
678 struct memory_handle *h = add_handle(&size);
679 if (!h)
681 DEBUGF("bufopen: failed to add handle\n");
682 close(fd);
683 return -2;
686 strncpy(h->path, file, MAX_PATH);
687 h->fd = -1;
688 h->filesize = filesize(fd);
689 h->filerem = h->filesize - offset;
690 h->offset = offset;
691 h->ridx = buf_widx;
692 h->widx = buf_widx;
693 h->data = buf_widx;
694 h->available = 0;
695 h->type = type;
697 close(fd);
699 DEBUGF("bufopen: allocated %ld bytes. ID: %d\n", (long)size, h->id);
701 if (type == TYPE_CODEC || type == TYPE_CUESHEET || type == TYPE_IMAGE) {
702 /* Immediately buffer those */
703 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
704 queue_send(&buffering_queue, Q_BUFFER_HANDLE, h->id);
707 DEBUGF("bufopen: opened handle %d\n", h->id);
708 return h->id;
711 /* Open a new handle from data that needs to be copied from memory.
712 src is the source buffer from which to copy data. It can be NULL to simply
713 reserve buffer space.
714 size is the requested size. The call will only be successful if the
715 requested amount of data can entirely fit in the buffer without wrapping.
716 Return value is the handle id for success or <0 for failure.
718 int bufalloc(void *src, size_t size, enum data_type type)
720 if (!can_add_handle())
721 return -2;
723 if (size + sizeof(struct memory_handle) > buffer_len - buf_widx) {
724 /* The data would need to wrap. */
725 DEBUGF("bufalloc: data wrap\n");
726 return -2;
729 size_t allocsize = size;
730 struct memory_handle *h = add_handle(&allocsize);
732 if (!h || allocsize != size)
733 return -2;
735 if (src) {
736 if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) {
737 DEBUGF("bufalloc: allocating metadata\n");
738 /* specially take care of struct mp3entry */
739 copy_mp3entry((struct mp3entry *)&buffer[buf_widx],
740 (struct mp3entry *)src);
741 } else {
742 memcpy(&buffer[buf_widx], src, size);
746 h->fd = -1;
747 *h->path = 0;
748 h->filesize = size;
749 h->filerem = 0;
750 h->offset = 0;
751 h->ridx = buf_widx;
752 h->widx = buf_widx;
753 h->data = buf_widx;
754 h->available = size;
755 h->type = type;
757 buf_widx = RINGBUF_ADD(buf_widx, size);
759 DEBUGF("bufalloc: opened handle %d\n", h->id);
760 return h->id;
763 /* Close the handle. Return 0 for success and < 0 for failure */
764 int bufclose(int handle_id)
766 DEBUGF("bufclose(%d)\n", handle_id);
767 struct memory_handle *h = find_handle(handle_id);
768 if (!h)
769 return -1;
771 if (h->fd >= 0) {
772 close(h->fd);
773 h->fd = -1;
776 rm_handle(h);
777 return 0;
780 /* Set reading index in handle (relatively to the start of the file).
781 Access before the available data will trigger a rebuffer.
782 Return 0 for success and < 0 for failure:
783 -1 if the handle wasn't found
784 -2 if the new requested position was beyond the end of the file
786 int bufseek(int handle_id, size_t newpos)
788 struct memory_handle *h = find_handle(handle_id);
789 if (!h)
790 return -1;
792 if (newpos > h->filesize) {
793 /* access beyond the end of the file */
794 return -3;
796 else if (newpos < h->offset || h->offset + h->available < newpos) {
797 /* access before or after buffered data. A rebuffer is needed. */
798 rebuffer_handle(handle_id, newpos);
800 else {
801 h->ridx = RINGBUF_ADD(h->data, newpos - h->offset);
803 return 0;
806 /* Advance the reading index in a handle (relatively to its current position).
807 Return 0 for success and < 0 for failure */
808 int bufadvance(int handle_id, off_t offset)
810 struct memory_handle *h = find_handle(handle_id);
811 if (!h)
812 return -1;
814 size_t newpos = h->offset + RINGBUF_SUB(h->ridx, h->data) + offset;
816 return bufseek(handle_id, newpos);
819 /* Copy data from the given handle to the dest buffer.
820 Return the number of bytes copied or < 0 for failure. */
821 ssize_t bufread(int handle_id, size_t size, void *dest)
823 struct memory_handle *h = find_handle(handle_id);
824 size_t buffered_data;
825 if (!h)
826 return -1;
828 if (size == 0 && h->filerem > 0 &&
829 h->available - RINGBUF_SUB(h->ridx, h->data) == 0)
830 /* Data isn't ready */
831 return -2;
833 if (h->available - RINGBUF_SUB(h->ridx, h->data) < size && h->filerem > 0)
834 /* Data isn't ready */
835 return -2;
837 if (h->available - RINGBUF_SUB(h->ridx, h->data) == 0 && h->filerem == 0)
838 /* File is finished reading */
839 return 0;
841 buffered_data = MIN(size, h->available - RINGBUF_SUB(h->ridx, h->data));
843 if (h->ridx + buffered_data > buffer_len)
845 /* the data wraps around the end of the buffer */
846 size_t read = buffer_len - h->ridx;
847 memcpy(dest, &buffer[h->ridx], read);
848 memcpy(dest+read, buffer, buffered_data - read);
850 else memcpy(dest, &buffer[h->ridx], buffered_data);
852 return buffered_data;
855 /* Update the "data" pointer to make the handle's data available to the caller.
856 Return the length of the available linear data or < 0 for failure.
857 size is the amount of linear data requested. it can be 0 to get as
858 much as possible.
859 The guard buffer may be used to provide the requested size */
860 ssize_t bufgetdata(int handle_id, size_t size, void **data)
862 struct memory_handle *h = find_handle(handle_id);
863 if (!h)
864 return -1;
866 if (size == 0 && h->filerem > 0 &&
867 h->available - RINGBUF_SUB(h->ridx, h->data) == 0)
868 /* Data isn't ready */
869 return -2;
871 if (h->available - RINGBUF_SUB(h->ridx, h->data) < size && h->filerem > 0)
872 /* Data isn't ready */
873 return -2;
875 if (h->available - RINGBUF_SUB(h->ridx, h->data) == 0 && h->filerem == 0)
876 /* File is finished reading */
877 return 0;
879 ssize_t ret;
881 if (h->ridx + size > buffer_len &&
882 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
884 /* the data wraps around the end of the buffer :
885 use the guard buffer to provide the requested amount of data. */
886 size_t copy_n = MIN(h->ridx + size - buffer_len, GUARD_BUFSIZE);
887 memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
888 ret = buffer_len - h->ridx + copy_n;
889 DEBUGF("used the guard buffer to complete\n");
891 else
893 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
894 buffer_len - h->ridx);
897 *data = &buffer[h->ridx];
899 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
900 (long)h->ridx, ret); */
901 return ret;
904 /* Return the amount of buffer space used */
905 size_t bufused(void)
907 return BUF_USED;
910 /* Initialise the buffering subsystem */
911 bool buffering_init(char *filebuf, size_t filebuflen)
913 if (!filebuf || !filebuflen)
914 return false;
916 buffer = filebuf;
917 buffer_len = filebuflen;
918 guard_buffer = buffer + buffer_len;
920 buf_widx = 0;
921 buf_ridx = 0;
923 first_handle = NULL;
924 num_handles = 0;
926 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
927 conf_watermark = AUDIO_DEFAULT_WATERMARK;
929 /* Set the high watermark as 75% full...or 25% empty :) */
930 #if MEM > 8
931 high_watermark = 3*filebuflen / 4;
932 #endif
934 queue_init(&buffering_queue, true);
935 queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list);
937 return true;
940 #if MEM > 8
941 /* we dont want this rebuffering on targets with little ram
942 because the disk may never spin down */
943 static bool ata_fillbuffer_callback(void)
945 queue_post(&buffering_queue, Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA, 0);
946 return true;
948 #endif
950 void buffering_thread(void)
952 struct queue_event ev;
954 while (true)
956 queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
958 #if MEM > 8
959 if ((ev.id == SYS_TIMEOUT) && (buffered_data() < high_watermark))
960 register_ata_idle_func(ata_fillbuffer_callback);
961 #endif
963 next_event:
964 switch (ev.id)
966 case Q_BUFFER_HANDLE:
967 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
968 queue_reply(&buffering_queue, 1);
969 buffer_handle((int)ev.data, &ev);
970 /* ev is now an event received by buffer_handle() */
971 goto next_event;
972 break;
974 case Q_RESET_HANDLE:
975 LOGFQUEUE("buffering < Q_RESET_HANDLE");
976 queue_reply(&buffering_queue, 1);
977 reset_handle((int)ev.data);
978 break;
981 #if MEM > 8
982 case Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA:
983 /* only fill if the disk is still spining */
984 #ifndef SIMULATOR
985 if (!ata_disk_is_active())
986 break;
987 #endif
988 if (num_handles > 0 && data_rem() > 0) {
989 fill_buffer(&ev);
990 goto next_event;
992 break;
993 #endif /* MEM > 8 */
995 #ifndef SIMULATOR
996 case SYS_USB_CONNECTED:
997 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
998 usb_acknowledge(SYS_USB_CONNECTED_ACK);
999 usb_wait_for_disconnect(&buffering_queue);
1000 break;
1001 #endif
1003 case SYS_TIMEOUT:
1004 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1005 break;
1008 if (queue_empty(&buffering_queue) &&
1009 data_rem() > 0 && wasted_space() > buffered_data()/2) {
1010 DEBUGF("there is %ld bytes of wasted space\n", (long)wasted_space());
1012 /* free buffer from outdated audio data */
1013 struct memory_handle *m = first_handle;
1014 while (m) {
1015 if (m->type == TYPE_AUDIO)
1016 shrink_handle(m->id);
1017 m = m->next;
1020 /* free buffer by moving metadata */
1021 m = first_handle;
1022 while (m) {
1023 if (m->type != TYPE_AUDIO)
1024 shrink_handle(m->id);
1025 m = m->next;
1030 if (queue_empty(&buffering_queue) &&
1031 data_rem() > 0 && buffered_data() < conf_watermark)
1033 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
1034 (long)data_rem());
1035 fill_buffer(&ev);
1036 goto next_event;
1041 /* Get a buffer offset from a pointer */
1042 ssize_t get_offset(int handle_id, void *ptr)
1044 struct memory_handle *h = find_handle(handle_id);
1045 if (!h)
1046 return -1;
1048 return (size_t)ptr - (size_t)&buffer[h->ridx];
1051 void buffering_get_debugdata(struct buffering_debug *dbgdata)
1053 dbgdata->num_handles = num_handles;
1054 dbgdata->data_rem = data_rem();
1055 dbgdata->wasted_space = wasted_space();
1056 dbgdata->buffered_data = buffered_data();