First commit of buffering.[ch], based on testplugin.c
[Rockbox-MoB.git] / buffering.c
blob7971002554f70a0f7d29f31e6bde45aecb6b8d21
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 #define GUARD_SIZE (32*1024)
59 /* amount of data to read in one read() call */
60 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
62 /* Ring buffer helper macros */
63 /* Buffer pointer (p) plus value (v), wrapped if necessary */
64 #define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
65 /* Buffer pointer (p) minus value (v), wrapped if necessary */
66 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
67 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
68 #define RINGBUF_ADD_CROSS(p1,v,p2) \
69 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
70 /* Bytes available in the buffer */
71 #define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
73 struct memory_handle {
74 int id; /* A unique ID for the handle */
75 enum data_type type;
76 char path[MAX_PATH];
77 int fd;
78 size_t data; /* Start index of the handle's data buffer */
79 size_t ridx; /* Current read pointer, relative to the main buffer */
80 size_t widx; /* Current write pointer */
81 size_t filesize; /* File total length */
82 size_t filerem; /* Remaining bytes of file NOT in buffer */
83 size_t available; /* Available bytes to read from buffer */
84 size_t offset; /* Offset at which we started reading the file */
85 struct memory_handle *next;
87 /* at all times, we have: filesize == offset + available + filerem */
90 static char *buffer;
91 static char *guard_buffer;
93 static size_t buffer_len;
95 static size_t buf_widx; /* current writing position */
96 static size_t buf_ridx; /* current reading position */
97 /* buf_*idx are values relative to the buffer, not real pointers. */
99 static size_t conf_filechunk;
101 /* current memory handle in the linked list. NULL when the list is empty. */
102 static struct memory_handle *cur_handle;
103 /* first memory handle in the linked list. NULL when the list is empty. */
104 static struct memory_handle *first_handle;
106 static int num_handles; /* number of handles in the list */
108 /* Handle cache (makes find_handle faster).
109 These need to be global so that move_handle can invalidate them. */
110 static int cached_handle_id = -1;
111 static struct memory_handle *cached_handle = NULL;
115 LINKED LIST MANAGEMENT
116 ======================
118 add_handle : Add a handle to the list
119 rm_handle : Remove a handle from the list
120 find_handle : Get a handle pointer from an ID
121 move_handle : Move a handle in the buffer (with or without its data)
123 These functions only handle the linked list structure. They don't touch the
124 contents of the struct memory_handle headers. They also change the buf_*idx
125 pointers when necessary and manage the handle IDs.
127 The first and current (== last) handle are kept track of.
128 A new handle is added at buf_widx and becomes the current one.
129 buf_widx always points to the current writing position for the current handle
130 buf_ridx always points to the location of the first handle.
131 buf_ridx == buf_widx means the buffer is empty.
135 /* Add a new handle to the linked list and return it. It will have become the
136 new current handle. The handle will reserve "data_size" bytes or if that's
137 not possible, decrease "data_size" to allow adding the handle. */
138 static struct memory_handle *add_handle(size_t *data_size)
140 /* this will give each handle a unique id */
141 static int cur_handle_id = 1;
143 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
144 but before that we check we can actually align. */
145 if (RINGBUF_ADD_CROSS(buf_widx, 3, buf_ridx) >= 0) {
146 return NULL;
148 buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
150 size_t len = (data_size ? *data_size : 0)
151 + sizeof(struct memory_handle);
153 /* check that we actually can add the handle and its data */
154 int overlap = RINGBUF_ADD_CROSS(buf_widx, len, buf_ridx);
155 if (overlap >= 0) {
156 *data_size -= overlap;
157 len -= overlap;
159 if (len < sizeof(struct memory_handle)) {
160 /* There isn't even enough space to write the struct */
161 return NULL;
164 struct memory_handle *new_handle =
165 (struct memory_handle *)(&buffer[buf_widx]);
167 /* only advance the buffer write index of the size of the struct */
168 buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
170 if (!first_handle) {
171 /* the new handle is the first one */
172 first_handle = new_handle;
175 if (cur_handle) {
176 cur_handle->next = new_handle;
179 cur_handle = new_handle;
180 cur_handle->id = cur_handle_id++;
181 cur_handle->next = NULL;
182 num_handles++;
183 return cur_handle;
186 /* Delete a given memory handle from the linked list
187 and return true for success. Nothing is actually erased from memory. */
188 static bool rm_handle(struct memory_handle *h)
190 if (h == first_handle) {
191 first_handle = h->next;
192 if (h == cur_handle) {
193 /* h was the first and last handle: the buffer is now empty */
194 cur_handle = NULL;
195 buf_ridx = buf_widx;
196 } else {
197 /* update buf_ridx to point to the new first handle */
198 buf_ridx = (void *)first_handle - (void *)buffer;
200 } else {
201 struct memory_handle *m = first_handle;
202 while (m && m->next != h) {
203 m = m->next;
205 if (h && m && m->next == h) {
206 m->next = h->next;
207 if (h == cur_handle) {
208 cur_handle = m;
210 } else {
211 return false;
215 num_handles--;
216 return true;
219 /* Return a pointer to the memory handle of given ID.
220 NULL if the handle wasn't found */
221 static struct memory_handle *find_handle(int handle_id)
223 /* simple caching because most of the time the requested handle
224 will either be the same as the last, or the one after the last */
225 if (cached_handle)
227 if (cached_handle_id == handle_id &&
228 cached_handle_id == cached_handle->id)
229 return cached_handle;
230 else if (cached_handle->next && (cached_handle->next->id == handle_id))
232 /* JD's quick testing showd this block was only entered
233 2/1971 calls to find_handle.
234 8/1971 calls to find_handle resulted in a cache miss */
235 cached_handle = cached_handle->next;
236 cached_handle_id = handle_id;
237 return cached_handle;
241 struct memory_handle *m = first_handle;
242 while (m && m->id != handle_id) {
243 m = m->next;
245 cached_handle_id = handle_id;
246 cached_handle = m;
247 return (m && m->id == handle_id) ? m : NULL;
250 /* Move a memory handle and data_size of its data of delta.
251 Return a pointer to the new location of the handle.
252 delta is the value of which to move the struct data.
253 data_size is the amount of data to move along with the struct. */
254 static struct memory_handle *move_handle(struct memory_handle *h,
255 size_t *delta, size_t data_size)
257 if (*delta < 4) {
258 /* aligning backwards would yield a negative result,
259 and moving the handle of such a small amount is a waste
260 of time anyway. */
261 return NULL;
263 /* make sure delta is 32-bit aligned so that the handle struct is. */
264 *delta = (*delta - 3) & ~3;
266 size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
268 struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
270 /* Invalidate the cache to prevent it from keeping the old location of h */
271 if (h == cached_handle)
272 cached_handle = NULL;
274 /* the cur_handle pointer might need updating */
275 if (h == cur_handle) {
276 cur_handle = dest;
279 if (h == first_handle) {
280 first_handle = dest;
281 buf_ridx = newpos;
282 } else {
283 struct memory_handle *m = first_handle;
284 while (m && m->next != h) {
285 m = m->next;
287 if (h && m && m->next == h) {
288 m->next = dest;
289 } else {
290 return NULL;
294 memmove(dest, h, sizeof(struct memory_handle) + data_size);
296 return dest;
301 BUFFER SPACE MANAGEMENT
302 =======================
304 buffer_handle : Buffer data for a handle
305 free_buffer : Free buffer space by moving a handle
306 fill_buffer : Call buffer_handle for all handles that have data to buffer
307 can_add_handle : Indicate whether it's safe to add a handle.
308 data_rem : Total amount of data needing to be buffered
309 wasted_space : Total amount of space available for freeing
311 These functions are used by the buffering thread to manage buffer space.
314 /* Buffer data for the given handle. Return the amount of data buffered
315 or -1 if the handle wasn't found */
316 static ssize_t buffer_handle(int handle_id)
318 DEBUGF("buffer_handle(%d)\n", handle_id);
319 struct memory_handle *h = find_handle(handle_id);
320 if (!h)
321 return -1;
323 if (h->filerem == 0) {
324 /* nothing left to buffer */
325 return 0;
328 if (h->fd < 0) /* file closed, reopen */
330 if (*h->path)
331 h->fd = open(h->path, O_RDONLY);
332 else
333 return -1;
335 if (h->fd < 0)
336 return -1;
338 if (h->offset)
339 lseek(h->fd, h->offset, SEEK_SET);
342 ssize_t ret = 0;
343 while (h->filerem > 0)
345 /* max amount to copy */
346 size_t copy_n = MIN( MIN(h->filerem, conf_filechunk),
347 buffer_len - h->widx);
349 /* stop copying if it would overwrite the reading position
350 or the next handle */
351 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0 || (h->next &&
352 RINGBUF_ADD_CROSS(h->widx, copy_n, (unsigned)
353 ((void *)h->next - (void *)buffer)) > 0))
354 break;
356 /* rc is the actual amount read */
357 int rc = read(h->fd, &buffer[h->widx], copy_n);
359 if (rc < 0)
361 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
362 h->filesize -= h->filerem;
363 h->filerem = 0;
364 break;
367 /* Advance buffer */
368 h->widx = RINGBUF_ADD(h->widx, rc);
369 if (h == cur_handle)
370 buf_widx = h->widx;
371 h->available += rc;
372 ret += rc;
373 h->filerem -= rc;
376 if (h->filerem == 0) {
377 /* finished buffering the file */
378 close(h->fd);
379 h->fd = -1;
382 DEBUGF("buffered %ld bytes (%ld of %ld available, rem: %ld, off: %ld)\n",
383 ret, h->available, h->filesize, h->filerem, h->offset);
385 return ret;
388 /* Free buffer space by moving the handle struct right before the useful
389 part of its data buffer or by moving all the data. */
390 static void free_buffer(int handle_id)
392 struct memory_handle *h = find_handle(handle_id);
393 if (!h)
394 return;
396 size_t delta;
397 /* The value of delta might change for alignment reasons */
399 if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
400 h->type == TYPE_IMAGE) && h->filerem == 0 )
402 /* metadata handle: we can move all of it */
403 delta = RINGBUF_SUB( (unsigned)((void *)h->next - (void *)buffer),
404 h->data) - h->available;
405 h = move_handle(h, &delta, h->available);
406 if (!h) return;
407 h->data = RINGBUF_ADD(h->data, delta);
408 h->ridx = RINGBUF_ADD(h->ridx, delta);
409 h->widx = RINGBUF_ADD(h->widx, delta);
411 /* when moving a struct mp3entry we need to readjust its pointers. */
412 if (h->type == TYPE_ID3 && h->filesize == sizeof(struct mp3entry)) {
413 adjust_mp3entry((struct mp3entry *)&buffer[h->data],
414 (void *)&buffer[h->data],
415 (void *)&buffer[RINGBUF_SUB(h->data, delta)]);
418 DEBUGF("free_buffer(%d): metadata, moved by %ld bytes\n",
419 handle_id, delta);
421 else
423 /* only move the handle struct */
424 delta = RINGBUF_SUB(h->ridx, h->data);
425 h = move_handle(h, &delta, 0);
426 if (!h) return;
427 h->data = RINGBUF_ADD(h->data, delta);
428 h->available -= delta;
429 h->offset += delta;
430 DEBUGF("free_buffer(%d): audio, %ld bytes freed\n", handle_id, delta);
434 /* Fill the buffer by buffering as much data as possible for handles that still
435 have data left to buffer */
436 static void fill_buffer(void)
438 DEBUGF("fill buffer()\n");
439 struct memory_handle *m = first_handle;
440 while (m) {
441 if (m->filerem > 0) {
442 buffer_handle(m->id);
444 m = m->next;
448 /* Check whether it's safe to add a new handle and reserve space to let the
449 current one finish buffering its data. Used by bufopen and bufgetdata as
450 a preliminary check before even trying to physically add the handle.
451 Returns true if it's ok to add a new handle, false if not.
453 static bool can_add_handle(void)
455 if (cur_handle && cur_handle->filerem > 0) {
456 /* the current handle hasn't finished buffering. We can only add
457 a new one if there is already enough free space to finish
458 the buffering. */
459 if (cur_handle->filerem < (buffer_len - BUF_USED)) {
460 /* Before adding the new handle we reserve some space for the
461 current one to finish buffering its data. */
462 buf_widx = RINGBUF_ADD(buf_widx, cur_handle->filerem);
463 } else {
464 return false;
468 return true;
471 /* Return the total amount of data left to be buffered for all the handles */
472 static size_t data_rem(void)
474 size_t ret = 0;
476 struct memory_handle *m = first_handle;
477 while (m) {
478 ret += m->filerem;
479 m = m->next;
482 return ret;
485 /* Return the amount of data we have but don't need anymore. This data can be
486 safely erased to reclaim buffer space. */
487 static size_t wasted_space(void)
489 size_t ret = 0;
491 struct memory_handle *m = first_handle;
492 while (m) {
493 ret += RINGBUF_SUB(m->ridx, m->data);
494 m = m->next;
497 return ret;
502 BUFFERING API FUNCTIONS
503 =======================
505 bufopen : Request the opening of a new handle for a file
506 bufalloc : Open a new handle for data other than a file.
507 bufclose : Close an open handle
508 bufseek : Set the read pointer in a handle
509 bufadvance : Move the read pointer in a handle
510 bufread : Copy data from a handle into a given buffer
511 bufgetdata : Give a pointer to the handle's data
513 These functions are exported, to allow interaction with the buffer.
514 They take care of the content of the structs, and rely on the linked list
515 management functions for all the actual handle management work.
519 /* Request a file be buffered
520 filename: name of the file to open
521 offset: offset at which to start buffering the file, useful when the first
522 (offset-1) bytes of the file aren't needed.
523 return value: <0 if the file cannot be opened, or one file already
524 queued to be opened, otherwise the handle for the file in the buffer
526 int bufopen(char *file, size_t offset, enum data_type type)
528 if (!can_add_handle())
529 return -2;
531 int fd = open(file, O_RDONLY);
532 if (fd < 0)
533 return -1;
535 size_t size = filesize(fd) - offset;
537 if (type != TYPE_AUDIO &&
538 size + sizeof(struct memory_handle) > buffer_len - buf_widx)
540 /* for types other than audio, the data can't wrap */
541 return -2;
544 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
545 file, offset, size);
547 struct memory_handle *h = add_handle(&size);
548 if (!h)
550 DEBUGF("failed to add handle\n");
551 close(fd);
552 return -2;
555 if (offset) lseek(fd, offset, SEEK_SET);
556 strncpy(h->path, file, MAX_PATH);
557 h->fd = fd;
558 h->filesize = filesize(fd);
559 h->filerem = h->filesize - offset;
560 h->offset = offset;
561 h->ridx = buf_widx;
562 h->widx = buf_widx;
563 h->data = buf_widx;
564 h->available = 0;
565 h->type = type;
567 DEBUGF("allocated %ld bytes. ID: %d\n", size, h->id);
568 return h->id;
571 /* Open a new handle from data that isn't in a file.
572 src is the source buffer from which to copy data. It can be NULL to simply
573 reserve buffer space.
574 size is the requested size. The call will only be successful if the
575 requested amount of data can entirely fit in the buffer without wrapping.
576 Return value is the handle id for success or <0 for failure.
578 int bufalloc(void *src, size_t size, enum data_type type)
580 if (!can_add_handle())
581 return -2;
583 if (size + sizeof(struct memory_handle) > buffer_len - buf_widx)
584 /* The data would need to wrap. */
585 return -2;
587 size_t allocsize = size;
588 struct memory_handle *h = add_handle(&allocsize);
590 if (!h || allocsize != size)
591 return -2;
593 if (src) {
594 if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) {
595 /* specially take care of struct mp3entry */
596 copy_mp3entry((struct mp3entry *)&buffer[buf_widx],
597 (struct mp3entry *)src);
598 } else {
599 memcpy(&buffer[buf_widx], src, size);
603 h->fd = -1;
604 *h->path = 0;
605 h->filesize = size;
606 h->filerem = 0;
607 h->offset = 0;
608 h->ridx = buf_widx;
609 h->widx = buf_widx;
610 h->data = buf_widx;
611 h->available = size;
612 h->type = type;
614 buf_widx = RINGBUF_ADD(buf_widx, size);
616 return h->id;
619 /* Close the handle. Return 0 for success and < 0 for failure */
620 int bufclose(int handle_id)
622 DEBUGF("bufclose(%d)\n", handle_id);
623 struct memory_handle *h = find_handle(handle_id);
624 if (!h)
625 return -1;
627 rm_handle(h);
628 return 0;
631 /* Set reading index in handle (relatively to the start of the file).
632 Access before the available data will trigger a rebuffer.
633 TODO: Test this
634 TODO: Maybe force an immediate rebuffer by calling buffer_handle() ?
635 Return 0 for success and < 0 for failure:
636 -1 if the handle wasn't found
637 -2 if there is no data available at the new position
638 (the reading index is still moved)
639 -3 if the new requested position was beyond the end of the file
641 int bufseek(int handle_id, size_t newpos)
643 int ret = 0;
644 struct memory_handle *h = find_handle(handle_id);
645 if (!h)
646 return -1;
648 if (newpos > h->filesize) {
649 /* access beyond the end of the file */
650 return -3;
653 else if (newpos < h->offset) {
654 /* access before what we currently have. A rebuffer is needed. */
655 h->offset = newpos;
656 h->available = 0;
657 h->filerem = h->filesize - newpos;
658 /* having changed filerem should be enough to trigger the rebuffer. */
659 h->widx = h->data;
660 ret = -2;
663 else if (newpos > h->offset + h->available) {
664 /* data isn't available yet. */
665 ret = -2;
668 h->ridx = RINGBUF_ADD(h->data, newpos);
669 return ret;
672 /* Advance the reading index in a handle (relatively to its current position).
673 Return 0 for success and < 0 for failure
674 TODO: Add some rebuffering like in bufseek */
675 int bufadvance(int handle_id, off_t offset)
677 struct memory_handle *h = find_handle(handle_id);
678 if (!h)
679 return -1;
681 if (offset >= 0)
683 /* check for access beyond what's available */
684 if ((size_t)offset > (h->available - RINGBUF_SUB(h->ridx, h->data)))
685 return -2;
687 h->ridx = RINGBUF_ADD(h->ridx, offset);
689 else
691 /* check for access before what's available */
692 if ((size_t)(-offset) > RINGBUF_SUB(h->ridx, h->data))
693 return -2;
695 h->ridx = RINGBUF_SUB(h->ridx, (size_t)(-offset));
698 return 0;
701 /* Copy data from the given handle to the dest buffer.
702 Return the number of bytes copied or < 0 for failure. */
703 ssize_t bufread(int handle_id, size_t size, char *dest)
705 struct memory_handle *h = find_handle(handle_id);
706 size_t buffered_data;
707 if (!h)
708 return -1;
710 if (h->available < size && h->filerem > 0) /* Data isn't ready */
711 return -2;
713 if (h->available == 0 && h->filerem == 0) /* File is finished reading */
714 return 0;
716 buffered_data = MIN(size, h->available - RINGBUF_SUB(h->ridx, h->data));
718 if (h->ridx + buffered_data > buffer_len)
720 /* the data wraps around the end of the buffer */
721 size_t read = buffer_len - h->ridx;
722 memcpy(dest, &buffer[h->ridx], read);
723 memcpy(dest+read, buffer, buffered_data - read);
725 else memcpy(dest, &buffer[h->ridx], buffered_data);
727 return buffered_data;
730 /* Update the "data" pointer to make the handle's data available to the caller.
731 Return the length of the available linear data or < 0 for failure.
732 size is the amount of linear data requested. it can be 0 to get as
733 much as possible.
734 The guard buffer may be used to provide the requested size */
735 ssize_t bufgetdata(int handle_id, size_t size, unsigned char **data)
737 struct memory_handle *h = find_handle(handle_id);
738 if (!h)
739 return -1;
741 if (h->available < size && h->filerem > 0) /* Data isn't ready */
742 return -2;
744 if (h->available == 0 && h->filerem == 0) /* File is finished reading */
745 return 0;
747 ssize_t ret;
749 if (h->ridx + size > buffer_len &&
750 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
752 /* the data wraps around the end of the buffer :
753 use the guard buffer to provide the requested amount of data. */
754 size_t copy_n = MIN(h->ridx + size - buffer_len, GUARD_SIZE);
755 memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
756 ret = buffer_len - h->ridx + copy_n;
757 DEBUGF("used the guard buffer to complete\n");
759 else
761 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
762 buffer_len - h->ridx);
765 *data = (unsigned char *)&buffer[h->ridx];
767 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
768 (long)h->ridx, ret); */
769 return ret;
773 void buffering_thread(void)
775 while (true)
777 if (data_rem() > 0 && wasted_space() > buffer_len/5) {
778 DEBUGF("there is %ld bytes of wasted space\n", wasted_space());
780 /* free buffer from outdated audio data */
781 struct memory_handle *m = first_handle;
782 while (m) {
783 if (m->type == TYPE_AUDIO)
784 free_buffer(m->id);
785 m = m->next;
788 /* free buffer by moving metadata */
789 m = first_handle;
790 while (m) {
791 if (m->type != TYPE_AUDIO)
792 free_buffer(m->id);
793 m = m->next;
798 if (data_rem() > 0 && BUF_USED < 3*buffer_len/4 &&
799 ata_disk_is_active())
801 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
802 data_rem());
803 fill_buffer();
804 } else {
805 sleep(HZ/2);