2 ===================================================================
3 --- apps/codecs.c (revision 13913)
4 +++ apps/codecs.c (working copy)
15 hdr = sim_codec_load_ram(codecptr, size, ptr2, bufwrap, &pd);
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 */
32 +static int current_handle;
33 +size_t codec_read_filebuf(void *ptr, size_t size)
37 + while ((read = bufread(current_handle, size, &data)) == -2) /* wait for data */
39 + DEBUGF("%d\n", read);
40 + bufadvance(current_handle, read);
41 + memcpy(ptr, data, 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);
53 +static void codec_thread(void)
59 + queue_wait(&codec_queue, &ev);
62 + case CODEC_LOAD_HANDLE:
63 + DEBUGF("codec < CODEC_LOAD_HANDLE %d\n", ev.data);
68 + read = bufgetdata(ev.data,CODEC_SIZE-rc, &data);
76 + bufadvance(ev.data, read);
77 + DEBUGF("%d %d\n", rc, read);
82 + current_handle = track_handle;
83 + codec_load_ram(codecbuf, (size_t)rc, NULL, 0, &ci);
86 + memcpy(&codecbuf[rc], data, read);
88 + bufadvance(ev.data, read);
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);
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));
117 ===================================================================
118 --- apps/codecs.h (revision 13913)
119 +++ apps/codecs.h (working copy)
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);
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
137 /* Create the threads late now that we shouldn't be yielding again before
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));
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);
152 audio_set_buffer_margin(global_settings.buffer_margin);
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);
160 + ci.id3 = &tracks[0].id3;
161 + ci.id3->offset = 0;
163 + ci.taginfo_ready = 1;
164 + track_handle = bufopen("/a.wav",0);
166 + codec_load_handle(codec_handle);
170 ===================================================================
171 --- apps/SOURCES (revision 13913)
172 +++ apps/SOURCES (working copy)
174 #if INPUT_SRC_CAPS != 0
176 #endif /* INPUT_SRC_CAPS != 0 */
181 Index: apps/buffering.c
182 ===================================================================
183 --- apps/buffering.c (revision 0)
184 +++ apps/buffering.c (revision 0)
191 +#include "buffering.h"
205 +#include "sprintf.h"
206 +#include "settings.h"
210 +#include "mp3_playback.h"
214 +#include "screens.h"
215 +#include "playlist.h"
216 +#include "playback.h"
220 +#define ata_disk_is_active() 1
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
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];
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;
318 + if (len < sizeof(struct memory_handle)) {
319 + DEBUGF("no space to add the handle\n");
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;
334 + cur_handle->next = new_handle;
337 + cur_handle = new_handle;
338 + cur_handle->id = cur_handle_id++;
339 + cur_handle->next = NULL;
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 */
354 + buf_ridx = buf_widx;
356 + buf_ridx = (void *)first_handle - (void *)buffer;
359 + struct memory_handle *m = first_handle;
360 + while (m && m->next != h) {
363 + if (h && m && m->next == h) {
365 + if (h == cur_handle) {
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 */
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) {
407 + cached_handle_id = handle_id;
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) {
432 + if (h == first_handle) {
433 + first_handle = dest;
436 + struct memory_handle *m = first_handle;
437 + while (m && m->next != h) {
440 + if (h && m && m->next == h) {
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);
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);
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);
471 + if (h->fd < 0) /* file closed, reopen */
474 + h->fd = open(h->path, O_RDONLY);
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;
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 */
498 + h->state = STATE_WRITING;
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))
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),
515 + RINGBUF_ADD(h->data, h->ridx)
517 + INT_RINGBUF_ADD_CROSS(h, h->widx, copy_n, h->ridx)
520 + /* stop copying if it would overwrite the reading position */
521 + if (RINGBUF_ADD_CROSS( RINGBUF_ADD(h->data, h->widx),
523 + RINGBUF_ADD(h->data, h->ridx)
527 + /* rc is the actual amount read */
528 + int rc = read(h->fd, &buffer[RINGBUF_ADD(h->data, h->widx)], copy_n);
532 + DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
533 + h->filesize -= h->filerem;
538 + /* Advance buffer */
539 + h->widx = INT_RINGBUF_ADD(h, h->widx, rc);
540 + h->available += 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 */
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);
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);
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 */
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;
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;
600 + if (m->filerem > 0) {
601 + buffer_handle(m->id);
608 +static size_t data_rem(void)
612 + struct memory_handle *m = first_handle;
621 +static size_t wasted_space(void)
625 + struct memory_handle *m = first_handle;
627 + ret += m->data_len - INT_BUF_USED(m);
634 +static size_t used_space(void)
638 + struct memory_handle *m = first_handle;
640 + ret += INT_BUF_USED(m);
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);
657 + struct memory_handle *h = add_handle(NULL);
660 + DEBUGF("failed to add handle\n");
663 + strncpy(h->path, file, MAX_PATH);
665 + h->offset = offset;
669 + h->state = STATE_UNKNOWN;
671 + if (!ata_disk_is_active())
674 + fd = open(file, O_RDONLY);
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);
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);
704 + h->state = STATE_CLOSED;
705 + /*rm_handle(h); will be removed later */
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);
717 + if (offset > h->available || offset > h->data_len)
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);
732 + /* DEBUGF("bufadvance(%ld): h->ridx: %ld, h->widx: %ld\n",
733 + offset, h->ridx, h->widx); */
737 + /* check for access beyond what's available */
738 + if ((size_t)offset > (h->available - h->ridx))
741 + h->ridx = INT_RINGBUF_ADD(h, h->ridx, offset);
745 + /* check for access before what's available */
746 + if ((size_t)(-offset) > h->ridx)
749 + h->ridx = INT_RINGBUF_SUB(h, h->ridx, (size_t)(-offset));
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;
764 + if (h->available == 0 && h->filerem > 0)
767 + if (h->available == 0 && h->filerem == 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);
793 + DEBUGF("bufgetdata: %d %d\n", h->available, h->filerem);
794 + if (h->available == 0 && h->filerem > 0)
796 + if (h->available == 0 && h->filerem == 0)
798 + DEBUGF("sadlkfjhasldkhflasd\n");
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);
819 + memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
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);
831 + DEBUGF("used the guard buffer for a whole piece\n");
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;
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);
850 +static long buffer_stack[DEFAULT_STACK_SIZE/sizeof(long)];
851 +static void buffer_thread(void)
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)
869 + // let playback know we want another file
876 +void buffering_enable(bool enable)
878 + keep_buffering = enable;
881 +bool buffering_init(void)
883 + keep_buffering = false;
885 + buffer_len = (audiobufend - audiobuf) - GUARD_SIZE;
886 + guard_buffer = buffer + buffer_len;
891 + first_handle = NULL;
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);
903 Index: apps/buffering.h
904 ===================================================================
905 --- apps/buffering.h (revision 0)
906 +++ apps/buffering.h (revision 0)
908 +/***************************************************************************
909 + * __________ __ ___.
910 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___
911 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
912 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
913 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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"
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 */
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.
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);
986 Index: apps/codecs/wav.c
987 ===================================================================
988 --- apps/codecs/wav.c (revision 13913)
989 +++ apps/codecs/wav.c (working copy)
993 while (!*ci->taginfo_ready && !ci->stop_codec)
999 codec_set_replaygain(ci->id3);
1002 ===================================================================
1003 --- apps/main.c (revision 13913)
1004 +++ apps/main.c (working copy)
1009 +#include "buffering.h"
1011 #include "mp3_playback.h"
1019 #ifdef HAVE_REMOTE_LCD
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)
1035 bool ata_disk_is_active(void)
1041 void ata_sleep(void)