Initial implementation of buffer extending. Debug output reduced.
[Rockbox-MoB.git] / merge.patch
blob1e02ae94a04e05a1d8cdfbc87e81fc96d020220f
1 Index: apps/codecs.c
2 ===================================================================
3 --- apps/codecs.c (revision 13913)
4 +++ apps/codecs.c (working copy)
5 @@ -47,6 +47,7 @@
6 #include "mp3data.h"
7 #include "powermgmt.h"
8 #include "system.h"
9 +#include "thread.h"
10 #include "sound.h"
11 #include "splash.h"
12 #include "general.h"
13 @@ -202,7 +203,7 @@
15 hdr = sim_codec_load_ram(codecptr, size, ptr2, bufwrap, &pd);
16 api->discard_codec();
18 +debugf("%x\n", api);
19 if (pd == NULL)
20 return CODEC_ERROR;
22 @@ -253,3 +254,93 @@
24 return codec_load_ram(codecbuf, (size_t)rc, NULL, 0, api);
27 +/****** CODEC thread stuff ********/
28 +enum codec_thread_messages {
29 + CODEC_LOAD_HANDLE, /* data == handle of the file */
30 +};
32 +static int current_handle;
33 +size_t codec_read_filebuf(void *ptr, size_t size)
35 + char *data;
36 + int read;
37 + while ((read = bufread(current_handle, size, &data)) == -2) /* wait for data */
38 + yield();
39 + DEBUGF("%d\n", read);
40 + bufadvance(current_handle, read);
41 + memcpy(ptr, data, read);
42 + return read;
45 +static struct event_queue codec_queue;// NOCACHEBSS_ATTR;
46 +static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)];// IBSS_ATTR;
47 +static const char codec_thread_name[] = "codec";
48 +void codec_load_handle(int handle)
50 + queue_post(&codec_queue, CODEC_LOAD_HANDLE, handle);
52 +int track_handle;
53 +static void codec_thread(void)
55 + struct event ev;
56 + int rc;
57 + while (1)
58 + {
59 + queue_wait(&codec_queue, &ev);
61 + switch (ev.id) {
62 + case CODEC_LOAD_HANDLE:
63 + DEBUGF("codec < CODEC_LOAD_HANDLE %d\n", ev.data);
64 + rc = 0;
65 + ssize_t read;
66 + do {
67 + char *data;
68 + read = bufgetdata(ev.data,CODEC_SIZE-rc, &data);
69 + if (read == -2)
70 + {
71 + yield();
72 + continue;
73 + }
74 + else
75 + {
76 + bufadvance(ev.data, read);
77 + DEBUGF("%d %d\n", rc, read);
78 + if (read == 0)
79 + {
80 + DEBUGF("blaa\n");
81 + bufclose(ev.data);
82 + current_handle = track_handle;
83 + codec_load_ram(codecbuf, (size_t)rc, NULL, 0, &ci);
84 + break;
85 + }
86 + memcpy(&codecbuf[rc], data, read);
87 + rc += read;
88 + bufadvance(ev.data, read);
89 + }
90 + } while (1);
91 + /* else error */
92 + break;
94 +#ifndef SIMULATOR
95 + case SYS_USB_CONNECTED:
96 + DEBUGF("codec < SYS_USB_CONNECTED");
97 + queue_clear(&codec_queue);
98 + usb_acknowledge(SYS_USB_CONNECTED_ACK);
99 + usb_wait_for_disconnect(&codec_queue);
100 + break;
101 +#endif
103 + default:
104 + DEBUGF("codec < default");
109 +void codec_thread_init(void)
111 + ci.read_filebuf = codec_read_filebuf;
112 + create_thread( codec_thread, codec_stack, sizeof(codec_stack),
113 + codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
114 + IF_COP(, CPU, true));
116 Index: apps/codecs.h
117 ===================================================================
118 --- apps/codecs.h (revision 13913)
119 +++ apps/codecs.h (working copy)
120 @@ -286,4 +286,6 @@
121 /* defined by the codec */
122 enum codec_status codec_start(struct codec_api* rockbox);
124 +void codec_thread_init(void);
125 +void codec_load_handle(int handle);
126 #endif
127 Index: apps/playback.c
128 ===================================================================
129 --- apps/playback.c (revision 13913)
130 +++ apps/playback.c (working copy)
131 @@ -3802,14 +3802,15 @@
132 /* audio_reset_buffer must to know the size of voice buffer so init
133 talk first */
134 talk_init();
136 +#if 0
137 /* Create the threads late now that we shouldn't be yielding again before
138 returning */
139 codec_thread_p = create_thread(
140 codec_thread, codec_stack, sizeof(codec_stack),
141 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
142 IF_COP(, CPU, true));
144 +#endif
145 + codec_thread_init();
146 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
147 audio_thread_name IF_PRIO(, PRIORITY_BUFFERING)
148 IF_COP(, CPU, false));
149 @@ -3840,4 +3841,19 @@
150 eq_hw_enable(global_settings.eq_hw_enabled);
151 #endif
152 audio_set_buffer_margin(global_settings.buffer_margin);
154 + /* test time! */
155 + int codec_handle = bufopen(CODECS_DIR "/wav.codec", 0);
156 + extern int track_handle;
157 + int fd = open("/a.wav", O_RDONLY);
158 + get_metadata(&tracks[0],fd,"/a.wav",v1first);
159 + close(fd);
160 + ci.id3 = &tracks[0].id3;
161 + ci.id3->offset = 0;
162 + ci.stop_codec = 0;
163 + ci.taginfo_ready = 1;
164 + track_handle = bufopen("/a.wav",0);
165 + yield();
166 + codec_load_handle(codec_handle);
168 } /* audio_init */
169 Index: apps/SOURCES
170 ===================================================================
171 --- apps/SOURCES (revision 13913)
172 +++ apps/SOURCES (working copy)
173 @@ -89,6 +89,7 @@
174 #if INPUT_SRC_CAPS != 0
175 audio_path.c
176 #endif /* INPUT_SRC_CAPS != 0 */
177 +buffering.c
178 pcmbuf.c
179 playback.c
180 codecs.c
181 Index: apps/buffering.c
182 ===================================================================
183 --- apps/buffering.c (revision 0)
184 +++ apps/buffering.c (revision 0)
185 @@ -0,0 +1,717 @@
186 +#include "config.h"
187 +#include <stdio.h>
188 +#include <string.h>
189 +#include <stdlib.h>
190 +#include <ctype.h>
191 +#include "buffering.h"
193 +#include "ata.h"
194 +#include "system.h"
195 +#include "thread.h"
196 +#include "file.h"
197 +#include "panic.h"
198 +#include "memory.h"
199 +#include "lcd.h"
200 +#include "font.h"
201 +#include "button.h"
202 +#include "kernel.h"
203 +#include "tree.h"
204 +#include "debug.h"
205 +#include "sprintf.h"
206 +#include "settings.h"
207 +#include "codecs.h"
208 +#include "audio.h"
209 +#include "logf.h"
210 +#include "mp3_playback.h"
211 +#include "usb.h"
212 +#include "status.h"
213 +#include "ata.h"
214 +#include "screens.h"
215 +#include "playlist.h"
216 +#include "playback.h"
217 +#include "pcmbuf.h"
218 +#include "buffer.h"
219 +#ifdef SIMULATOR
220 +#define ata_disk_is_active() 1
221 +#endif
222 +#define GUARD_SIZE (32*1024)
224 +/* amount of data to read in one read() call */
225 +#define AUDIO_DEFAULT_FILECHUNK (1024*32)
227 +/* Ring buffer helper macros */
228 +/* Buffer pointer (p) plus value (v), wrapped if necessary */
229 +#define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
230 +/* Buffer pointer (p) minus value (v), wrapped if necessary */
231 +#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
232 +/* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
233 +#define RINGBUF_ADD_CROSS(p1,v,p2) \
234 +((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
235 +/* Bytes available in the buffer */
236 +#define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
238 +/* Internal ring buffer helper macros */
239 +/* Buffer pointer (p) plus value (v), wrapped if necessary */
240 +#define INT_RINGBUF_ADD(h,p,v) ((p+v) < h->data_len ? p+v : p+v - h->data_len)
241 +/* Buffer pointer (p) minus value (v), wrapped if necessary */
242 +#define INT_RINGBUF_SUB(h,p,v) ((p>=v) ? p-v : p + h->data_len - v)
243 +/* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
244 +#define INT_RINGBUF_ADD_CROSS(h,p1,v,p2) \
245 +((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)h->data_len)
246 +/* Bytes available in the buffer */
247 +#define INT_BUF_USED(h) ((h->state == STATE_WRITING) ? \
248 + h->data_len : INT_RINGBUF_SUB(h, h->widx, h->ridx))
250 +#ifdef ROCKBOX_HAS_LOGF
251 +#define DEBUGF logf
252 +#endif
254 +int num_files = 5;
255 +char *files[] = {
256 + "/a.mp3",
257 + "/b.mp3",
258 + "/c.mp3",
259 + "/d.mp3",
260 + "/e.mp3" };
262 +struct memory_handle {
263 + int id; /* A unique ID for the handle */
264 + enum data_type type;
265 + enum data_state state;
266 + char path[MAX_PATH];
267 + int fd;
268 + size_t data; /* Start index of the handle's data buffer */
269 + size_t data_len; /* Length of the data buffer for the handle */
270 + size_t ridx; /* Current read pointer, relative to the data buffer */
271 + size_t widx; /* Current write pointer */
272 + size_t filesize; /* File total length */
273 + size_t filerem; /* Remaining bytes of file NOT in buffer */
274 + size_t available; /* Available bytes to read from buffer */
275 + size_t offset; /* Offset at which we started reading the file */
276 + struct memory_handle *next;
280 +static char *buffer;
281 +static char *guard_buffer;
283 +static size_t buffer_len;
284 +static size_t buf_widx;
285 +static size_t buf_ridx;
287 +static size_t conf_filechunk;
289 +/* current memory handle in the linked list. NULL when the list is empty. */
290 +static struct memory_handle *cur_handle;
291 +/* first memory handle in the linked list. NULL when the list is empty. */
292 +static struct memory_handle *first_handle;
293 +static int num_handles;
295 +static bool keep_buffering;
298 +/* add a new handle to the linked list and return it. It will have become the
299 + new current handle. The handle will reserve "data_size" bytes or if that's
300 + not possible, decrease "data_size" to allow adding the handle. */
301 +static struct memory_handle *add_handle(size_t *data_size)
303 + /* this will give each handle a unique id */
304 + static int cur_handle_id = 1;
306 + /* make sure buf_widx is 32-bit aligned so that the handle struct is. */
307 + buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
309 + size_t len = (data_size ? *data_size : 0)
310 + + sizeof(struct memory_handle);
312 + /* check that we actually can add the handle and its data */
313 + int overlap = RINGBUF_ADD_CROSS(buf_widx, len, buf_ridx);
314 + if (overlap >= 0) {
315 + *data_size -= overlap;
316 + len -= overlap;
318 + if (len < sizeof(struct memory_handle)) {
319 + DEBUGF("no space to add the handle\n");
320 + return NULL;
323 + struct memory_handle *new_handle = (struct memory_handle *)(&buffer[buf_widx]);
325 + /* only advance the buffer write index of the size of the struct */
326 + buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
328 + if (!first_handle) {
329 + /* the new handle is the first one */
330 + first_handle = new_handle;
333 + if (cur_handle) {
334 + cur_handle->next = new_handle;
337 + cur_handle = new_handle;
338 + cur_handle->id = cur_handle_id++;
339 + cur_handle->next = NULL;
340 + num_handles++;
341 + return cur_handle;
344 +/* delete a given memory handle from the linked list
345 + and return true for success. Nothing is actually erased from memory. */
346 +static bool rm_handle(struct memory_handle *h)
348 + if (h == first_handle) {
349 + first_handle = h->next;
350 + if (h == cur_handle) {
351 + DEBUGF("removing the first and last handle\n");
352 + /* h was the first and last handle */
353 + cur_handle = NULL;
354 + buf_ridx = buf_widx;
355 + } else {
356 + buf_ridx = (void *)first_handle - (void *)buffer;
358 + } else {
359 + struct memory_handle *m = first_handle;
360 + while (m && m->next != h) {
361 + m = m->next;
363 + if (h && m && m->next == h) {
364 + m->next = h->next;
365 + if (h == cur_handle) {
366 + cur_handle = m;
368 + } else {
369 + return false;
373 + num_handles--;
374 + return true;
377 +/* these are unfortunalty needed to be global
378 + so move_handle can invalidate them */
379 +static int cached_handle_id = -1;
380 +static struct memory_handle *cached_handle = NULL;
382 +/* Return a pointer to the memory handle of given ID.
383 + NULL if the handle wasn't found */
384 +static struct memory_handle *find_handle(int handle_id)
386 + /* simple caching because most of the time the requested handle
387 + will either be the same as the last, or the one after the last */
388 + if (cached_handle)
390 + if (cached_handle_id == handle_id && cached_handle_id == cached_handle->id)
391 + return cached_handle;
392 + else if (cached_handle->next && (cached_handle->next->id == handle_id))
394 + /* JD's quick testing showd this block was only entered
395 + 2/1971 calls to find_handle.
396 + 8/1971 calls to find_handle resulted in a cache miss */
397 + cached_handle = cached_handle->next;
398 + cached_handle_id = handle_id;
399 + return cached_handle;
403 + struct memory_handle *m = first_handle;
404 + while (m && m->id != handle_id) {
405 + m = m->next;
407 + cached_handle_id = handle_id;
408 + cached_handle = m;
409 + return (m && m->id == handle_id) ? m : NULL;
412 +/* Move a memory handle to newpos.
413 + Return a pointer to the new location of the handle */
414 +static struct memory_handle *move_handle(size_t *delta, struct memory_handle *h)
416 + /* make sure delta is 32-bit aligned so that the handle struct is. */
417 + *delta = (RINGBUF_ADD(*delta, 3)) & ~3;
419 + size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
421 + struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
423 + /* Invalidate the cache to prevent it from keeping the old location of h */
424 + if (h == cached_handle)
425 + cached_handle = NULL;
427 + /* the cur_handle pointer might need updating */
428 + if (h == cur_handle) {
429 + cur_handle = dest;
432 + if (h == first_handle) {
433 + first_handle = dest;
434 + buf_ridx = newpos;
435 + } else {
436 + struct memory_handle *m = first_handle;
437 + while (m && m->next != h) {
438 + m = m->next;
440 + if (h && m && m->next == h) {
441 + m->next = dest;
442 + } else {
443 + return NULL;
447 + DEBUGF("h: %lx", (long)h);
448 + DEBUGF("h->id: %d", h->id);
449 + DEBUGF("dest: %lx", (long)dest);
450 + DEBUGF("dest->id: %d", dest->id);
451 + DEBUGF("memmove");
453 + memmove(dest, h, sizeof(struct memory_handle));
455 + DEBUGF("h: %lx", (long)h);
456 + DEBUGF("dest: %lx", (long)dest);
457 + DEBUGF("dest->id: %d", dest->id);
459 + return dest;
461 +/* Buffer data for the given handle. Return the amount of data buffered
462 + or -1 if the handle wasn't found */
463 +static ssize_t buffer_handle(int handle_id)
465 + DEBUGF("buffer_handle(%d)\n", handle_id);
466 + struct memory_handle *h = find_handle(handle_id);
467 + if (!h)
468 + return -1;
471 + if (h->fd < 0) /* file closed, reopen */
473 + if (*h->path)
474 + h->fd = open(h->path, O_RDONLY);
475 + else
476 + return -1;
478 + if (h->fd < 0)
479 + return -1;
481 + if (h->offset)
482 + lseek(h->fd, h->offset, SEEK_SET);
483 + h->filesize = filesize(h->fd);
484 + h->filerem = h->filesize - h->offset;
485 + h->data = buf_widx;
486 + h->data_len = h->filerem;
487 + h->available = 0;
488 + h->state = STATE_UNKNOWN;
490 + buf_widx = RINGBUF_ADD(buf_widx, h->filerem); /* is this line correct? */
493 + if (h->filerem == 0) {
494 + /* nothing left to buffer */
495 + return 0;
498 + h->state = STATE_WRITING;
500 + ssize_t ret = 0;
501 + while (h->filerem > 0)
503 + /* max amount to copy */
504 + size_t copy_n = MIN(conf_filechunk,
505 + MIN(h->data_len - h->widx,
506 + buffer_len - RINGBUF_ADD(h->data, h->widx))
507 + );
509 + DEBUGF("widx: %ld, ridx: %ld copy_n: %d, writepos: %ld,"
510 + "readpos: %ld, add_cross: %ld, int_add_cross: %ld\n",
511 + h->widx, h->ridx, copy_n, RINGBUF_ADD(h->data, h->widx),
512 + RINGBUF_ADD(h->data, h->ridx),
513 + RINGBUF_ADD_CROSS( RINGBUF_ADD(h->data, h->widx),
514 + copy_n,
515 + RINGBUF_ADD(h->data, h->ridx)
516 + ),
517 + INT_RINGBUF_ADD_CROSS(h, h->widx, copy_n, h->ridx)
518 + );*/
520 + /* stop copying if it would overwrite the reading position */
521 + if (RINGBUF_ADD_CROSS( RINGBUF_ADD(h->data, h->widx),
522 + copy_n,
523 + RINGBUF_ADD(h->data, h->ridx)
524 + ) >= 0 )
525 + break;
527 + /* rc is the actual amount read */
528 + int rc = read(h->fd, &buffer[RINGBUF_ADD(h->data, h->widx)], copy_n);
530 + if (rc < 0)
532 + DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
533 + h->filesize -= h->filerem;
534 + h->filerem = 0;
535 + break;
538 + /* Advance buffer */
539 + h->widx = INT_RINGBUF_ADD(h, h->widx, rc);
540 + h->available += rc;
541 + ret += rc;
542 + h->filerem -= rc;
544 + if (h->widx == h->ridx) /* internal ring buffer is full */
545 + break; /* for short files, this will be equivalent
546 + to h->filerem == 0 */
549 + if (h->filerem == 0) {
550 + /* finished buffering the file */
551 + close(h->fd);
554 + if (h == cur_handle)
555 + buf_widx = RINGBUF_ADD(h->data, h->data_len);
557 + DEBUGF("buffered %ld bytes (%ld of %ld available, remaining: %ld)\n",
558 + ret, h->available, h->filesize, h->filerem);
560 + return ret;
563 +/* Free buffer space by moving the handle struct right before the useful
564 + part of its data buffer */
565 +static void free_buffer(int handle_id)
567 + DEBUGF("free_buffer(%d)\n", handle_id);
568 + struct memory_handle *h = find_handle(handle_id);
569 + if (!h)
570 + return;
572 + DEBUGF("old state: data: %ld, data_len: %ld, avail: %ld, ridx: %ld, widx: %ld\n",
573 + h->data, h->data_len, h->available, h->ridx, h->widx);
575 + if (h->widx != 0 && h->ridx > h->widx) {
576 + /* We don't want to overwrite a useful part of the buffer */
577 + return;
580 + size_t delta = h->ridx;
581 + h = move_handle(&delta, h);
582 + /* The value of delta might change for alignment reasons */
583 + h->data = RINGBUF_ADD(h->data, delta);
584 + h->data_len -= delta;
585 + h->ridx -= delta;
586 + if (h->widx >= delta) h->widx -= delta;
587 + h->available -= delta;
588 + h->state = STATE_WRITING;
590 + DEBUGF("new state: data: %ld, data_len: %ld, avail: %ld, ridx: %ld, widx: %ld\n",
591 + h->data, h->data_len, h->available, h->ridx, h->widx);
595 +static void fill_buffer(void)
597 + DEBUGF("fill buffer()\n");
598 + struct memory_handle *m = first_handle;
599 + while (m) {
600 + if (m->filerem > 0) {
601 + buffer_handle(m->id);
602 + //yield(); maybe?
604 + m = m->next;
608 +static size_t data_rem(void)
610 + size_t ret = 0;
612 + struct memory_handle *m = first_handle;
613 + while (m) {
614 + ret += m->filerem;
615 + m = m->next;
618 + return ret;
621 +static size_t wasted_space(void)
623 + size_t ret = 0;
625 + struct memory_handle *m = first_handle;
626 + while (m) {
627 + ret += m->data_len - INT_BUF_USED(m);
628 + m = m->next;
631 + return ret;
634 +static size_t used_space(void)
636 + size_t ret = 0;
638 + struct memory_handle *m = first_handle;
639 + while (m) {
640 + ret += INT_BUF_USED(m);
641 + m = m->next;
644 + return ret;
647 +/* Request a file be buffered
648 + filename: name of the file t open
649 + offset: starting offset to buffer from the file
650 + RETURNS: <0 if the file cannot be opened, or one file already
651 + queued to be opened, otherwise the handle for the file in the buffer
653 +int bufopen(char *file, size_t offset)
655 + DEBUGF("bufopen: %s (offset: %ld)\n", file, offset);
656 + int fd = -1;
657 + struct memory_handle *h = add_handle(NULL);
658 + if (!h)
660 + DEBUGF("failed to add handle\n");
661 + return -1;
663 + strncpy(h->path, file, MAX_PATH);
664 + h->fd = fd;
665 + h->offset = offset;
666 + h->ridx = 0;
667 + h->widx = 0;
668 + h->available = 0;
669 + h->state = STATE_UNKNOWN;
671 + if (!ata_disk_is_active())
672 + return h->id;
674 + fd = open(file, O_RDONLY);
675 + if (fd < 0)
676 + return -1;
678 + if (offset)
679 + lseek(fd, offset, SEEK_SET);
680 + size_t size = filesize(fd) - offset;
681 + h->filesize = filesize(fd);
682 + h->filerem = h->filesize - offset;
684 + DEBUGF("we want to allocate %ld bytes\n", size);
685 + DEBUGF("allocated %ld bytes\n", size);
687 + h->data = buf_widx;
688 + h->data_len = size;
690 + buf_widx = RINGBUF_ADD(buf_widx, size);
692 + DEBUGF("added handle : %d\n", h->id);
693 + buffer_handle(h);
694 + return h->id;
697 +/* Close the handle. Return 0 for success and < 0 for failure */
698 +int bufclose(int handle_id)
700 + DEBUGF("bufclose(%d)\n", handle_id);
701 + struct memory_handle *h = find_handle(handle_id);
702 + if (!h)
703 + return -1;
704 + h->state = STATE_CLOSED;
705 + /*rm_handle(h); will be removed later */
706 + return 0;
709 +/* Set the reading index in a handle (relatively to the start of the handle data).
710 + Return 0 for success and < 0 for failure */
711 +int bufseek(int handle_id, size_t offset)
713 + struct memory_handle *h = find_handle(handle_id);
714 + if (!h)
715 + return -1;
717 + if (offset > h->available || offset > h->data_len)
718 + return -2;
720 + h->ridx = offset;
721 + return 0;
724 +/* Advance the reading index in a handle (relatively to its current position).
725 + Return 0 for success and < 0 for failure */
726 +int bufadvance(int handle_id, off_t offset)
728 + struct memory_handle *h = find_handle(handle_id);
729 + if (!h)
730 + return -1;
732 + /* DEBUGF("bufadvance(%ld): h->ridx: %ld, h->widx: %ld\n",
733 + offset, h->ridx, h->widx); */
735 + if (offset >= 0)
737 + /* check for access beyond what's available */
738 + if ((size_t)offset > (h->available - h->ridx))
739 + return -2;
741 + h->ridx = INT_RINGBUF_ADD(h, h->ridx, offset);
743 + else
745 + /* check for access before what's available */
746 + if ((size_t)(-offset) > h->ridx)
747 + return -2;
749 + h->ridx = INT_RINGBUF_SUB(h, h->ridx, (size_t)(-offset));
752 + return 0;
755 +/* Copy data from the given handle to the dest buffer.
756 + Return the number of bytes copied or < 0 for failure. */
757 +ssize_t bufread(int handle_id, size_t size, char *dest)
759 + struct memory_handle *h = find_handle(handle_id);
760 + size_t buffered_data;
761 + if (!h)
762 + return -1;
764 + if (h->available == 0 && h->filerem > 0)
765 + return -2;
767 + if (h->available == 0 && h->filerem == 0)
768 + return 0;
770 + buffered_data = MIN(size, h->available);
772 + if (h->data + h->ridx + buffered_data > buffer_len)
774 + size_t read = buffer_len - (h->data + h->ridx);
775 + memcpy(dest, &buffer[h->data + h->ridx], read);
776 + memcpy(dest+read, buffer, buffered_data - read);
778 + else memcpy(dest, &buffer[h->data + h->ridx], buffered_data);
780 + h->ridx += buffered_data;
781 + h->available -= buffered_data;
782 + return buffered_data;
785 +/* Update the "data" pointer to make the handle's data available to the caller.
786 + Return the length of the available linear data or < 0 for failure. */
787 +ssize_t bufgetdata(int handle_id, size_t size, unsigned char **data)
789 + struct memory_handle *h = find_handle(handle_id);
790 + if (!h)
791 + return -1;
793 + DEBUGF("bufgetdata: %d %d\n", h->available, h->filerem);
794 + if (h->available == 0 && h->filerem > 0)
795 + return -2;
796 + if (h->available == 0 && h->filerem == 0)
798 + DEBUGF("sadlkfjhasldkhflasd\n");
799 + return 0;
802 + ssize_t ret;
804 + if (buffer_len - (h->data + h->ridx) > 0 &&
805 + buffer_len - (h->data + h->ridx) < size &&
806 + h->available - h->ridx >= size)
808 + /* use the guard buffer to provide what was requested. */
809 + size_t copy_n = h->data + h->ridx + size - buffer_len;
811 + if (h->ridx + size > h->data_len) {
812 + size_t copy_1 = h->data_len - (h->ridx + size - copy_n);
813 + size_t copy_2 = copy_n - copy_1;
814 + memcpy(guard_buffer,
815 + (unsigned char *)buffer, copy_1);
816 + memcpy(guard_buffer + copy_1,
817 + (unsigned char *)&buffer[h->data], copy_2);
818 + } else {
819 + memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
822 + ret = size;
823 + DEBUGF("used the guard buffer to complete\n");
825 + else if (h->ridx + size > h->data_len &&
826 + h->available - h->ridx >= size &&
827 + size <= GUARD_SIZE)
829 + memcpy(guard_buffer, (unsigned char *)&buffer[h->data], size);
830 + ret = size;
831 + DEBUGF("used the guard buffer for a whole piece\n");
833 + else
835 + ret = MIN(h->available - h->ridx,
836 + buffer_len - (h->data + h->ridx));
837 + if (h->state == STATE_WRITING) {
838 + h->state = STATE_READING;
839 + } else {
840 + ret = MIN(ret, INT_BUF_USED(h));
844 + *data = (unsigned char *)&buffer[RINGBUF_ADD(h->data, h->ridx)];
846 + //DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);
847 + return ret;
850 +static long buffer_stack[DEFAULT_STACK_SIZE/sizeof(long)];
851 +static void buffer_thread(void)
853 + struct event ev;
854 + while (1)
856 + if (keep_buffering)
858 + if (ata_disk_is_active() ||
859 + wasted_space() > (buffer_len/4))
861 + struct memory_handle *n, *h = first_handle;
862 + while (h && h->state == STATE_CLOSED)
864 + n = h->next;
865 + rm_handle(h);
866 + h = n;
868 + fill_buffer();
869 + // let playback know we want another file
872 + sleep(HZ);
876 +void buffering_enable(bool enable)
878 + keep_buffering = enable;
881 +bool buffering_init(void)
883 + keep_buffering = false;
884 + buffer = audiobuf;
885 + buffer_len = (audiobufend - audiobuf) - GUARD_SIZE;
886 + guard_buffer = buffer + buffer_len;
888 + buf_widx = 0;
889 + buf_ridx = 0;
891 + first_handle = NULL;
892 + num_handles = 0;
894 + conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
896 + create_thread( buffer_thread, buffer_stack,
897 + sizeof(buffer_stack), "buffering"
898 + IF_PRIO(,PRIORITY_PLAYBACK)
899 + IF_COP(, CPU, false));
900 + buffering_enable(true);
901 + return true;
903 Index: apps/buffering.h
904 ===================================================================
905 --- apps/buffering.h (revision 0)
906 +++ apps/buffering.h (revision 0)
907 @@ -0,0 +1,78 @@
908 +/***************************************************************************
909 + * __________ __ ___.
910 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___
911 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
912 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
913 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
914 + * \/ \/ \/ \/ \/
915 + * $Id$
917 + * Copyright (C) 2007 Nicolas Pennequin
919 + * All files in this archive are subject to the GNU General Public License.
920 + * See the file COPYING in the source tree root for full license agreement.
922 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
923 + * KIND, either express or implied.
925 + ****************************************************************************/
927 +#ifndef _BUFFERING_H_
928 +#define _BUFFERING_H_
929 +#include "stdbool.h"
930 +#include <ctype.h>
931 +#include <sys/types.h>
932 +/* Memory allocation should happen in the following order for each track:
933 +TYPE_CODEC, TYPE_(>AUDIO), TYPE_AUDIO.
934 +TYPE_CODEC will be released as soon as it has been closed.
935 +TYPE_(>AUDIO) (the metadata types) will stay valid as long as the
936 + audio buffer straight after them is kept open.
937 +TYPE_AUDIO will be released as needed */
939 +#if 0
940 +JdGordon's thinking aloud...
942 +The way this all should work is that if first_handle->data_type > TYPE_AUDIO
943 +the LL will be searched for the first TYPE_AUDIO item.
944 +if that item is closed then all the handles between first_handle and the found audio track
945 +will be closed and dumped (or maybe they have to wait for playback to close them...),
946 +either way, they will never be dumped unless the audio item is closed.
948 +Now, when reading/wiritng the buffer... if (m->next && m->next->id == -1 && m->next->data_type == TYPE_AUDIO (might not need this extra check)) then it is a continuation of m. the guard fuffer will most likely be needed when the buffer is read.. but thats ok.
950 +Unless im wrong it should only be possible that we have one of these "safe" sections at any one time.
952 +The only problem with this system is that the MoB has to be allocated before the audio is read.
953 +the id3 data should be a constant size which is ok, cuesheet will be known. image and buffer will not be known, which is where it might get tricky.
955 +/end babbling
956 +#endif
959 +enum data_type {
960 + TYPE_CODEC,
961 + TYPE_AUDIO,
962 + TYPE_ID3,
963 + TYPE_CUESHEET,
964 + TYPE_IMAGE,
965 + TYPE_BUFFER,
966 + TYPE_UNKNOWN,
969 +enum data_state {
970 + STATE_UNKNOWN,
971 + STATE_WRITING,
972 + STATE_READING,
973 + STATE_CLOSED,
976 +bool buffering_init(void);
977 +int bufopen(char *file, size_t offset);
978 +int bufclose(int handle_id);
979 +int bufseek(int handle_id, size_t offset);
980 +int bufadvance(int handle_id, ssize_t offset);
981 +ssize_t bufread(int handle_id, size_t size, char *dest);
982 +long bufgetdata(int handle_id, size_t size, unsigned char **data);
983 +void buffering_enable(bool enable);
985 +#endif
986 Index: apps/codecs/wav.c
987 ===================================================================
988 --- apps/codecs/wav.c (revision 13913)
989 +++ apps/codecs/wav.c (working copy)
990 @@ -236,7 +236,10 @@
993 while (!*ci->taginfo_ready && !ci->stop_codec)
995 + DEBUGF("sleep\n");
996 ci->sleep(1);
999 codec_set_replaygain(ci->id3);
1001 Index: apps/main.c
1002 ===================================================================
1003 --- apps/main.c (revision 13913)
1004 +++ apps/main.c (working copy)
1005 @@ -40,6 +40,7 @@
1006 #ifndef DEBUG
1007 #include "serial.h"
1008 #endif
1009 +#include "buffering.h"
1010 #include "audio.h"
1011 #include "mp3_playback.h"
1012 #include "thread.h"
1013 @@ -248,6 +249,7 @@
1015 init_threads();
1016 buffer_init();
1017 + buffering_init();
1018 lcd_init();
1019 #ifdef HAVE_REMOTE_LCD
1020 lcd_remote_init();
1021 @@ -329,6 +331,7 @@
1022 #endif
1024 buffer_init();
1025 + buffering_init();
1027 settings_reset();
1029 Index: firmware/target/arm/sandisk/sansa-e200/ata-e200.c
1030 ===================================================================
1031 --- firmware/target/arm/sandisk/sansa-e200/ata-e200.c (revision 13913)
1032 +++ firmware/target/arm/sandisk/sansa-e200/ata-e200.c (working copy)
1033 @@ -825,7 +825,7 @@
1035 bool ata_disk_is_active(void)
1037 - return 0;
1038 + return 1;
1041 void ata_sleep(void)