Hide the buffering thread and queue inside buffering.c
[Rockbox.git] / apps / buffering.c
blobe53fe70d0ed523c600d4be0b54fd00a0c10c7dd8
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;
147 /* Messages available to communicate with the buffering thread */
148 enum {
149 Q_BUFFER_HANDLE = 1, /* Request buffering of a handle */
150 Q_RESET_HANDLE, /* (internal) Request resetting of a handle to its
151 offset (the offset has to be set beforehand) */
152 Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA,
155 /* Buffering thread */
156 void buffering_thread(void);
157 static long buffering_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)];
158 static const char buffering_thread_name[] = "buffering";
159 struct thread_entry *buffering_thread_p;
160 struct event_queue buffering_queue;
161 struct queue_sender_list buffering_queue_sender_list;
165 LINKED LIST MANAGEMENT
166 ======================
168 add_handle : Add a handle to the list
169 rm_handle : Remove a handle from the list
170 find_handle : Get a handle pointer from an ID
171 move_handle : Move a handle in the buffer (with or without its data)
173 These functions only handle the linked list structure. They don't touch the
174 contents of the struct memory_handle headers. They also change the buf_*idx
175 pointers when necessary and manage the handle IDs.
177 The first and current (== last) handle are kept track of.
178 A new handle is added at buf_widx and becomes the current one.
179 buf_widx always points to the current writing position for the current handle
180 buf_ridx always points to the location of the first handle.
181 buf_ridx == buf_widx means the buffer is empty.
185 /* Add a new handle to the linked list and return it. It will have become the
186 new current handle. The handle will reserve "data_size" bytes or if that's
187 not possible, decrease "data_size" to allow adding the handle. */
188 static struct memory_handle *add_handle(size_t *data_size)
190 /* this will give each handle a unique id */
191 static int cur_handle_id = 1;
193 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
194 but before that we check we can actually align. */
195 if (RINGBUF_ADD_CROSS(buf_widx, 3, buf_ridx) >= 0) {
196 return NULL;
198 buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
200 size_t len = (data_size ? *data_size : 0)
201 + sizeof(struct memory_handle);
203 /* check that we actually can add the handle and its data */
204 int overlap = RINGBUF_ADD_CROSS(buf_widx, len, buf_ridx);
205 if (overlap >= 0) {
206 *data_size -= overlap;
207 len -= overlap;
209 if (len < sizeof(struct memory_handle)) {
210 /* There isn't even enough space to write the struct */
211 return NULL;
214 struct memory_handle *new_handle =
215 (struct memory_handle *)(&buffer[buf_widx]);
217 /* only advance the buffer write index of the size of the struct */
218 buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
220 if (!first_handle) {
221 /* the new handle is the first one */
222 first_handle = new_handle;
225 if (cur_handle) {
226 cur_handle->next = new_handle;
229 cur_handle = new_handle;
230 cur_handle->id = cur_handle_id++;
231 cur_handle->next = NULL;
232 num_handles++;
233 return cur_handle;
236 /* Delete a given memory handle from the linked list
237 and return true for success. Nothing is actually erased from memory. */
238 static bool rm_handle(struct memory_handle *h)
240 if (h == first_handle) {
241 first_handle = h->next;
242 if (h == cur_handle) {
243 /* h was the first and last handle: the buffer is now empty */
244 cur_handle = NULL;
245 buf_ridx = buf_widx;
246 } else {
247 /* update buf_ridx to point to the new first handle */
248 buf_ridx = (void *)first_handle - (void *)buffer;
250 } else {
251 struct memory_handle *m = first_handle;
252 while (m && m->next != h) {
253 m = m->next;
255 if (h && m && m->next == h) {
256 m->next = h->next;
257 if (h == cur_handle) {
258 cur_handle = m;
259 buf_widx = cur_handle->widx;
261 } else {
262 return false;
266 num_handles--;
267 return true;
270 /* Return a pointer to the memory handle of given ID.
271 NULL if the handle wasn't found */
272 static struct memory_handle *find_handle(int handle_id)
274 /* simple caching because most of the time the requested handle
275 will either be the same as the last, or the one after the last */
276 if (cached_handle)
278 if (cached_handle_id == handle_id &&
279 cached_handle_id == cached_handle->id)
280 return cached_handle;
281 else if (cached_handle->next && (cached_handle->next->id == handle_id))
283 /* JD's quick testing showd this block was only entered
284 2/1971 calls to find_handle.
285 8/1971 calls to find_handle resulted in a cache miss */
286 cached_handle = cached_handle->next;
287 cached_handle_id = handle_id;
288 return cached_handle;
292 struct memory_handle *m = first_handle;
293 while (m && m->id != handle_id) {
294 m = m->next;
296 cached_handle_id = handle_id;
297 cached_handle = m;
298 return (m && m->id == handle_id) ? m : NULL;
301 /* Move a memory handle and data_size of its data of delta.
302 Return a pointer to the new location of the handle.
303 delta is the value of which to move the struct data.
304 data_size is the amount of data to move along with the struct. */
305 static struct memory_handle *move_handle(struct memory_handle *h,
306 size_t *delta, size_t data_size)
308 if (*delta < 4) {
309 /* aligning backwards would yield a negative result,
310 and moving the handle of such a small amount is a waste
311 of time anyway. */
312 return NULL;
314 /* make sure delta is 32-bit aligned so that the handle struct is. */
315 *delta = (*delta - 3) & ~3;
317 size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
319 struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
321 /* Invalidate the cache to prevent it from keeping the old location of h */
322 if (h == cached_handle)
323 cached_handle = NULL;
325 /* the cur_handle pointer might need updating */
326 if (h == cur_handle) {
327 cur_handle = dest;
330 if (h == first_handle) {
331 first_handle = dest;
332 buf_ridx = newpos;
333 } else {
334 struct memory_handle *m = first_handle;
335 while (m && m->next != h) {
336 m = m->next;
338 if (h && m && m->next == h) {
339 m->next = dest;
340 } else {
341 return NULL;
345 memmove(dest, h, sizeof(struct memory_handle) + data_size);
347 return dest;
352 BUFFER SPACE MANAGEMENT
353 =======================
355 yield_codec : Used by buffer_handle to know if it should interrupt buffering
356 buffer_handle : Buffer data for a handle
357 reset_handle : Reset writing position and data buffer of a handle to its
358 current offset
359 rebuffer_handle : Seek to a nonbuffered part of a handle by rebuffering the data
360 shrink_handle : Free buffer space by moving a handle
361 fill_buffer : Call buffer_handle for all handles that have data to buffer
362 can_add_handle : Indicate whether it's safe to add a handle
363 data_rem : Total amount of data needing to be buffered
364 wasted_space : Total amount of space available for freeing
365 buffered_data : Total amount of data currently in the buffer
367 These functions are used by the buffering thread to manage buffer space.
370 static bool filebuf_is_lowdata(void)
372 return BUF_USED < AUDIO_FILEBUF_CRITICAL;
375 /* Yield to the codec thread for as long as possible if it is in need of data.
376 Return true if the caller should break to let the buffering thread process
377 new queue events */
378 static bool yield_codec(void)
380 yield();
382 if (!queue_empty(&buffering_queue))
383 return true;
385 while (pcmbuf_is_lowdata() && !filebuf_is_lowdata())
387 sleep(2);
389 if (!queue_empty(&buffering_queue))
390 return true;
393 return false;
396 /* Buffer data for the given handle. Return the amount of data buffered
397 or -1 if the handle wasn't found */
398 static ssize_t buffer_handle(int handle_id)
400 DEBUGF("buffer_handle(%d)\n", handle_id);
401 struct memory_handle *h = find_handle(handle_id);
402 if (!h)
403 return -1;
405 if (h->filerem == 0) {
406 /* nothing left to buffer */
407 return 0;
410 if (h->fd < 0) /* file closed, reopen */
412 if (*h->path)
413 h->fd = open(h->path, O_RDONLY);
414 else
415 return -1;
417 if (h->fd < 0)
418 return -1;
420 if (h->offset)
421 lseek(h->fd, h->offset, SEEK_SET);
424 trigger_cpu_boost();
426 ssize_t ret = 0;
427 while (h->filerem > 0)
429 /* max amount to copy */
430 size_t copy_n = MIN( MIN(h->filerem, conf_filechunk),
431 buffer_len - h->widx);
433 /* stop copying if it would overwrite the reading position
434 or the next handle */
435 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0 || (h->next &&
436 RINGBUF_ADD_CROSS(h->widx, copy_n, (unsigned)
437 ((void *)h->next - (void *)buffer)) > 0))
438 break;
440 /* rc is the actual amount read */
441 int rc = read(h->fd, &buffer[h->widx], copy_n);
443 if (rc < 0)
445 if (h->type == TYPE_CODEC) {
446 DEBUGF("Partial codec\n");
447 break;
450 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
451 h->filesize -= h->filerem;
452 h->filerem = 0;
453 break;
456 /* Advance buffer */
457 h->widx = RINGBUF_ADD(h->widx, rc);
458 if (h == cur_handle)
459 buf_widx = h->widx;
460 h->available += rc;
461 ret += rc;
462 h->filerem -= rc;
464 /* DEBUGF("buffer_handle(%d): buffered %ld bytes. done: %ld. remaining: %ld.\n",
465 h->id, rc, h->available, h->filerem); */
467 /* Stop buffering if new queue events have arrived */
468 if (yield_codec())
469 break;
472 if (h->filerem == 0) {
473 /* finished buffering the file */
474 close(h->fd);
475 h->fd = -1;
478 DEBUGF("buffer_handle(%d): buffered %ld bytes (%ld of %ld available, "
479 "rem: %ld, off: %ld)\n",
480 handle_id, (long)ret, (long)h->available, (long)h->filesize,
481 (long)h->filerem, (long)h->offset);
483 return ret;
486 void request_buffer_handle(int handle_id)
488 LOGFQUEUE("buffering >| buffering Q_BUFFER_HANDLE");
489 queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
492 /* Reset writing position and data buffer of a handle to its current offset.
493 Use this after having set the new offset to use.
494 Returns 0 for success or -1 if the handle wasn't found. */
495 static void reset_handle(int handle_id)
497 DEBUGF("reset_handle(%d)\n", handle_id);
499 struct memory_handle *h = find_handle(handle_id);
500 if (!h)
501 return;
503 h->widx = h->data;
504 if (h == cur_handle)
505 buf_widx = h->widx;
506 h->available = 0;
507 h->filerem = h->filesize - h->offset;
509 if (h->fd >= 0) {
510 lseek(h->fd, h->offset, SEEK_SET);
514 /* Seek to a nonbuffered part of a handle by rebuffering the data. */
515 static void rebuffer_handle(int handle_id, size_t newpos)
517 struct memory_handle *h = find_handle(handle_id);
518 if (!h)
519 return;
521 DEBUGF("rebuffer_handle: resetting the handle to offset %ld\n", (long)newpos);
522 h->offset = newpos;
524 LOGFQUEUE("? >| buffering Q_RESET_HANDLE");
525 queue_send(&buffering_queue, Q_RESET_HANDLE, handle_id);
527 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
528 queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
530 h->ridx = h->data;
533 /* Free buffer space by moving the handle struct right before the useful
534 part of its data buffer or by moving all the data. */
535 static void shrink_handle(int handle_id)
537 struct memory_handle *h = find_handle(handle_id);
538 if (!h)
539 return;
541 size_t delta;
542 /* The value of delta might change for alignment reasons */
544 if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
545 h->type == TYPE_IMAGE) && h->filerem == 0 )
547 /* metadata handle: we can move all of it */
548 delta = RINGBUF_SUB( (unsigned)((void *)h->next - (void *)buffer),
549 h->data) - h->available;
550 h = move_handle(h, &delta, h->available);
551 if (!h) return;
552 h->data = RINGBUF_ADD(h->data, delta);
553 h->ridx = RINGBUF_ADD(h->ridx, delta);
554 h->widx = RINGBUF_ADD(h->widx, delta);
556 /* when moving a struct mp3entry we need to readjust its pointers. */
557 if (h->type == TYPE_ID3 && h->filesize == sizeof(struct mp3entry)) {
558 adjust_mp3entry((struct mp3entry *)&buffer[h->data],
559 (void *)&buffer[h->data],
560 (void *)&buffer[RINGBUF_SUB(h->data, delta)]);
563 DEBUGF("shrink_handle(%d): metadata, moved by %ld bytes\n",
564 handle_id, (long)delta);
566 else
568 /* only move the handle struct */
569 delta = RINGBUF_SUB(h->ridx, h->data);
570 h = move_handle(h, &delta, 0);
571 if (!h) return;
572 h->data = RINGBUF_ADD(h->data, delta);
573 h->available -= delta;
574 h->offset += delta;
575 DEBUGF("shrink_handle(%d): audio, %ld bytes freed\n",
576 handle_id, (long)delta);
580 /* Fill the buffer by buffering as much data as possible for handles that still
581 have data left to buffer */
582 static void fill_buffer(void)
584 DEBUGF("fill buffer()\n");
585 struct memory_handle *m = first_handle;
586 while (m) {
587 if (m->filerem > 0) {
588 buffer_handle(m->id);
590 m = m->next;
594 /* Check whether it's safe to add a new handle and reserve space to let the
595 current one finish buffering its data. Used by bufopen and bufalloc as
596 a preliminary check before even trying to physically add the handle.
597 Returns true if it's ok to add a new handle, false if not.
599 static bool can_add_handle(void)
601 if (cur_handle && cur_handle->filerem > 0) {
602 /* the current handle hasn't finished buffering. We can only add
603 a new one if there is already enough free space to finish
604 the buffering. */
605 if (cur_handle->filerem < (buffer_len - BUF_USED)) {
606 /* Before adding the new handle we reserve some space for the
607 current one to finish buffering its data. */
608 buf_widx = RINGBUF_ADD(buf_widx, cur_handle->filerem);
609 } else {
610 return false;
614 return true;
617 /* Return the total amount of data left to be buffered for all the handles */
618 static size_t data_rem(void)
620 size_t ret = 0;
622 struct memory_handle *m = first_handle;
623 while (m) {
624 ret += m->filerem;
625 m = m->next;
628 return ret;
631 /* Return the amount of data we have but don't need anymore. This data can be
632 safely erased to reclaim buffer space. */
633 static size_t wasted_space(void)
635 size_t ret = 0;
637 struct memory_handle *m = first_handle;
638 while (m) {
639 ret += RINGBUF_SUB(m->ridx, m->data);
640 m = m->next;
643 return ret;
646 static size_t buffered_data(void)
648 size_t ret = 0;
649 struct memory_handle *m = first_handle;
650 while (m) {
651 ret += m->available;
652 m = m->next;
654 return ret;
659 BUFFERING API FUNCTIONS
660 =======================
662 bufopen : Request the opening of a new handle for a file
663 bufalloc : Open a new handle for data other than a file.
664 bufclose : Close an open handle
665 bufseek : Set the read pointer in a handle
666 bufadvance : Move the read pointer in a handle
667 bufread : Copy data from a handle into a given buffer
668 bufgetdata : Give a pointer to the handle's data
669 bufused : Return the amount of buffer space used
671 These functions are exported, to allow interaction with the buffer.
672 They take care of the content of the structs, and rely on the linked list
673 management functions for all the actual handle management work.
677 /* Reserve space in the buffer for a file.
678 filename: name of the file to open
679 offset: offset at which to start buffering the file, useful when the first
680 (offset-1) bytes of the file aren't needed.
681 return value: <0 if the file cannot be opened, or one file already
682 queued to be opened, otherwise the handle for the file in the buffer
684 int bufopen(char *file, size_t offset, enum data_type type)
686 if (!can_add_handle())
687 return -2;
689 int fd = open(file, O_RDONLY);
690 if (fd < 0)
691 return -1;
693 size_t size = filesize(fd) - offset;
695 if (type != TYPE_AUDIO &&
696 size + sizeof(struct memory_handle) > buffer_len - buf_widx)
698 /* for types other than audio, the data can't wrap, so we force it */
699 buf_widx = 0;
702 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
703 file, (long)offset, (long)size);
705 struct memory_handle *h = add_handle(&size);
706 if (!h)
708 DEBUGF("bufopen: failed to add handle\n");
709 close(fd);
710 return -2;
713 strncpy(h->path, file, MAX_PATH);
714 h->fd = -1;
715 h->filesize = filesize(fd);
716 h->filerem = h->filesize - offset;
717 h->offset = offset;
718 h->ridx = buf_widx;
719 h->widx = buf_widx;
720 h->data = buf_widx;
721 h->available = 0;
722 h->type = type;
724 close(fd);
726 DEBUGF("bufopen: allocated %ld bytes. ID: %d\n", (long)size, h->id);
728 if (type == TYPE_CODEC || type == TYPE_CUESHEET || type == TYPE_IMAGE) {
729 /* Immediately buffer those */
730 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
731 queue_send(&buffering_queue, Q_BUFFER_HANDLE, h->id);
734 DEBUGF("bufopen: opened handle %d\n", h->id);
735 return h->id;
738 /* Open a new handle from data that needs to be copied from memory.
739 src is the source buffer from which to copy data. It can be NULL to simply
740 reserve buffer space.
741 size is the requested size. The call will only be successful if the
742 requested amount of data can entirely fit in the buffer without wrapping.
743 Return value is the handle id for success or <0 for failure.
745 int bufalloc(void *src, size_t size, enum data_type type)
747 if (!can_add_handle())
748 return -2;
750 if (size + sizeof(struct memory_handle) > buffer_len - buf_widx) {
751 /* The data would need to wrap. */
752 DEBUGF("bufalloc: data wrap\n");
753 return -2;
756 size_t allocsize = size;
757 struct memory_handle *h = add_handle(&allocsize);
759 if (!h || allocsize != size)
760 return -2;
762 if (src) {
763 if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) {
764 DEBUGF("bufalloc: allocating metadata\n");
765 /* specially take care of struct mp3entry */
766 copy_mp3entry((struct mp3entry *)&buffer[buf_widx],
767 (struct mp3entry *)src);
768 } else {
769 memcpy(&buffer[buf_widx], src, size);
773 h->fd = -1;
774 *h->path = 0;
775 h->filesize = size;
776 h->filerem = 0;
777 h->offset = 0;
778 h->ridx = buf_widx;
779 h->widx = buf_widx;
780 h->data = buf_widx;
781 h->available = size;
782 h->type = type;
784 buf_widx = RINGBUF_ADD(buf_widx, size);
786 DEBUGF("bufalloc: opened handle %d\n", h->id);
787 return h->id;
790 /* Close the handle. Return 0 for success and < 0 for failure */
791 int bufclose(int handle_id)
793 DEBUGF("bufclose(%d)\n", handle_id);
794 struct memory_handle *h = find_handle(handle_id);
795 if (!h)
796 return -1;
798 if (h->fd >= 0) {
799 close(h->fd);
800 h->fd = -1;
803 rm_handle(h);
804 return 0;
807 /* Set reading index in handle (relatively to the start of the file).
808 Access before the available data will trigger a rebuffer.
809 Return 0 for success and < 0 for failure:
810 -1 if the handle wasn't found
811 -2 if the new requested position was beyond the end of the file
813 int bufseek(int handle_id, size_t newpos)
815 struct memory_handle *h = find_handle(handle_id);
816 if (!h)
817 return -1;
819 if (newpos > h->filesize) {
820 /* access beyond the end of the file */
821 return -3;
823 else if (newpos < h->offset || h->offset + h->available < newpos) {
824 /* access before or after buffered data. A rebuffer is needed. */
825 rebuffer_handle(handle_id, newpos);
827 else {
828 h->ridx = RINGBUF_ADD(h->data, newpos - h->offset);
830 return 0;
833 /* Advance the reading index in a handle (relatively to its current position).
834 Return 0 for success and < 0 for failure */
835 int bufadvance(int handle_id, off_t offset)
837 struct memory_handle *h = find_handle(handle_id);
838 if (!h)
839 return -1;
841 size_t newpos = h->offset + RINGBUF_SUB(h->ridx, h->data) + offset;
843 return bufseek(handle_id, newpos);
846 /* Copy data from the given handle to the dest buffer.
847 Return the number of bytes copied or < 0 for failure. */
848 ssize_t bufread(int handle_id, size_t size, void *dest)
850 struct memory_handle *h = find_handle(handle_id);
851 size_t buffered_data;
852 if (!h)
853 return -1;
855 if (size == 0 && h->filerem > 0 &&
856 h->available - RINGBUF_SUB(h->ridx, h->data) == 0)
857 /* Data isn't ready */
858 return -2;
860 if (h->available - RINGBUF_SUB(h->ridx, h->data) < size && h->filerem > 0)
861 /* Data isn't ready */
862 return -2;
864 if (h->available - RINGBUF_SUB(h->ridx, h->data) == 0 && h->filerem == 0)
865 /* File is finished reading */
866 return 0;
868 buffered_data = MIN(size, h->available - RINGBUF_SUB(h->ridx, h->data));
870 if (h->ridx + buffered_data > buffer_len)
872 /* the data wraps around the end of the buffer */
873 size_t read = buffer_len - h->ridx;
874 memcpy(dest, &buffer[h->ridx], read);
875 memcpy(dest+read, buffer, buffered_data - read);
877 else memcpy(dest, &buffer[h->ridx], buffered_data);
879 return buffered_data;
882 /* Update the "data" pointer to make the handle's data available to the caller.
883 Return the length of the available linear data or < 0 for failure.
884 size is the amount of linear data requested. it can be 0 to get as
885 much as possible.
886 The guard buffer may be used to provide the requested size */
887 ssize_t bufgetdata(int handle_id, size_t size, void **data)
889 struct memory_handle *h = find_handle(handle_id);
890 if (!h)
891 return -1;
893 if (size == 0 && h->filerem > 0 &&
894 h->available - RINGBUF_SUB(h->ridx, h->data) == 0)
895 /* Data isn't ready */
896 return -2;
898 if (h->available - RINGBUF_SUB(h->ridx, h->data) < size && h->filerem > 0)
899 /* Data isn't ready */
900 return -2;
902 if (h->available - RINGBUF_SUB(h->ridx, h->data) == 0 && h->filerem == 0)
903 /* File is finished reading */
904 return 0;
906 ssize_t ret;
908 if (h->ridx + size > buffer_len &&
909 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
911 /* the data wraps around the end of the buffer :
912 use the guard buffer to provide the requested amount of data. */
913 size_t copy_n = MIN(h->ridx + size - buffer_len, GUARD_BUFSIZE);
914 memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
915 ret = buffer_len - h->ridx + copy_n;
916 DEBUGF("used the guard buffer to complete\n");
918 else
920 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
921 buffer_len - h->ridx);
924 *data = &buffer[h->ridx];
926 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
927 (long)h->ridx, ret); */
928 return ret;
931 /* Return the amount of buffer space used */
932 size_t bufused(void)
934 return BUF_USED;
937 /* Initialise the buffering subsystem */
938 bool buffering_init(char *filebuf, size_t filebuflen)
940 if (!filebuf || !filebuflen)
941 return false;
943 buffer = filebuf;
944 buffer_len = filebuflen;
945 guard_buffer = buffer + buffer_len;
947 buf_widx = 0;
948 buf_ridx = 0;
950 first_handle = NULL;
951 num_handles = 0;
953 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
954 conf_watermark = AUDIO_DEFAULT_WATERMARK;
956 /* Set the high watermark as 75% full...or 25% empty :) */
957 #if MEM > 8
958 high_watermark = 3*filebuflen / 4;
959 #endif
961 buffering_thread_p = create_thread( buffering_thread, buffering_stack,
962 sizeof(buffering_stack), 0,
963 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING)
964 IF_COP(, CPU));
966 queue_init(&buffering_queue, true);
967 queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list);
969 return true;
972 #if MEM > 8
973 /* we dont want this rebuffering on targets with little ram
974 because the disk may never spin down */
975 static bool ata_fillbuffer_callback(void)
977 queue_post(&buffering_queue, Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA, 0);
978 return true;
980 #endif
982 void buffering_thread(void)
984 struct queue_event ev;
986 while (true)
988 queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
990 #if MEM > 8
991 if ((ev.id == SYS_TIMEOUT) && (buffered_data() < high_watermark))
992 register_ata_idle_func(ata_fillbuffer_callback);
993 #endif
995 switch (ev.id)
997 case Q_BUFFER_HANDLE:
998 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
999 queue_reply(&buffering_queue, 1);
1000 buffer_handle((int)ev.data);
1001 break;
1003 case Q_RESET_HANDLE:
1004 LOGFQUEUE("buffering < Q_RESET_HANDLE");
1005 queue_reply(&buffering_queue, 1);
1006 reset_handle((int)ev.data);
1007 break;
1010 #if MEM > 8
1011 case Q_BUFFERING_FILL_BUFFER_IF_ACTIVE_ATA:
1012 /* only fill if the disk is still spining */
1013 #ifndef SIMULATOR
1014 if (!ata_disk_is_active())
1015 break;
1016 #endif
1017 if (num_handles > 0 && data_rem() > 0)
1018 fill_buffer();
1019 break;
1020 #endif /* MEM > 8 */
1022 #ifndef SIMULATOR
1023 case SYS_USB_CONNECTED:
1024 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
1025 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1026 usb_wait_for_disconnect(&buffering_queue);
1027 break;
1028 #endif
1030 case SYS_TIMEOUT:
1031 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1032 break;
1035 if (queue_empty(&buffering_queue) &&
1036 data_rem() > 0 && wasted_space() > buffered_data()/2) {
1037 DEBUGF("there is %ld bytes of wasted space\n", (long)wasted_space());
1039 /* free buffer from outdated audio data */
1040 struct memory_handle *m = first_handle;
1041 while (m) {
1042 if (m->type == TYPE_AUDIO)
1043 shrink_handle(m->id);
1044 m = m->next;
1047 /* free buffer by moving metadata */
1048 m = first_handle;
1049 while (m) {
1050 if (m->type != TYPE_AUDIO)
1051 shrink_handle(m->id);
1052 m = m->next;
1057 if (queue_empty(&buffering_queue) &&
1058 data_rem() > 0 && buffered_data() < conf_watermark)
1060 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
1061 (long)data_rem());
1062 fill_buffer();
1067 /* Get a buffer offset from a pointer */
1068 ssize_t get_offset(int handle_id, void *ptr)
1070 struct memory_handle *h = find_handle(handle_id);
1071 if (!h)
1072 return -1;
1074 return (size_t)ptr - (size_t)&buffer[h->ridx];
1077 void buffering_get_debugdata(struct buffering_debug *dbgdata)
1079 dbgdata->num_handles = num_handles;
1080 dbgdata->data_rem = data_rem();
1081 dbgdata->wasted_space = wasted_space();
1082 dbgdata->buffered_data = buffered_data();