Apply the previous change to buffering.c with a bugfix. There needs to be more change...
[Rockbox-MoB.git] / testplugin.c
blob530cae2b207a819284f735451045ac3d3f9eca65
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 ****************************************************************************/
21 #include "plugin.h"
23 PLUGIN_HEADER
25 struct plugin_api* rb;
27 #define GUARD_SIZE (32*1024)
29 /* amount of data to read in one read() call */
30 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
32 /* Ring buffer helper macros */
33 /* Buffer pointer (p) plus value (v), wrapped if necessary */
34 #define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
35 /* Buffer pointer (p) minus value (v), wrapped if necessary */
36 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
37 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
38 #define RINGBUF_ADD_CROSS(p1,v,p2) \
39 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
40 /* Bytes available in the buffer */
41 #define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
43 #ifdef ROCKBOX_HAS_LOGF
44 #define DEBUGF rb->logf
45 #endif
47 struct memory_handle {
48 int id; /* A unique ID for the handle */
49 //enum data_type type;
50 //enum data_state state;
51 char path[MAX_PATH];
52 int fd;
53 size_t data; /* Start index of the handle's data buffer */
54 size_t data_len; /* Length of the data buffer for the handle */
55 size_t ridx; /* Current read pointer, relative to the main buffer */
56 size_t widx; /* Current write pointer */
57 size_t filesize; /* File total length */
58 size_t filerem; /* Remaining bytes of file NOT in buffer */
59 size_t available; /* Available bytes to read from buffer */
60 size_t offset; /* Offset at which we started reading the file */
61 struct memory_handle *next;
64 enum {
65 Q_BUFOPEN,
66 Q_BUFCLOSE,
67 Q_BUFSEEK,
68 Q_BUFADVANCE,
69 Q_BUFREAD,
70 Q_BUFGETDATA
73 struct bufopen_data {
74 char *file;
75 size_t offset;
78 struct bufseek_data {
79 int handle_id;
80 size_t offset;
83 struct bufadvance_data {
84 int handle_id;
85 ssize_t offset;
88 struct bufread_data {
89 int handle_id;
90 size_t size;
91 char *dest;
94 struct bufgetdata_data {
95 int handle_id;
96 size_t size;
97 unsigned char **data;
101 static char *buffer;
102 static char *guard_buffer;
104 static size_t buffer_len;
105 static size_t buf_widx;
106 static size_t buf_ridx;
108 static size_t conf_filechunk;
110 /* current memory handle in the linked list. NULL when the list is empty. */
111 static struct memory_handle *cur_handle;
112 /* first memory handle in the linked list. NULL when the list is empty. */
113 static struct memory_handle *first_handle;
114 static int num_handles;
116 static void graph_view(int width);
118 /* exported API functions (will be present in the header file) */
119 int bufopen(char *file, size_t offset);
120 void bufclose(int handle_id);
121 void bufseek(int handle_id, size_t offset);
122 void bufadvance(int handle_id, ssize_t offset);
123 int bufread(int handle_id, size_t size, char *dest);
124 int bufgetdata(int handle_id, size_t size, unsigned char **data);
127 /* add a new handle to the linked list and return it. It will have become the
128 new current handle. The handle will reserve "data_size" bytes or if that's
129 not possible, decrease "data_size" to allow adding the handle. */
130 static struct memory_handle *add_handle(int *data_size)
132 /* this will give each handle a unique id */
133 static int cur_handle_id = 0;
135 int len = (data_size ? *data_size : 0) + sizeof(struct memory_handle);
137 /* check that we actually can add the handle and its data */
138 int overlap = RINGBUF_ADD_CROSS(buf_widx, len + 3, buf_ridx);
139 if (overlap >= 0) {
140 *data_size -= overlap;
141 len -= overlap;
143 if (len < sizeof(struct memory_handle)) {
144 return NULL;
147 /* make sure buf_widx is 32-bit aligned so that the handle struct is. */
148 buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
150 struct memory_handle *new_handle = (struct memory_handle *)(buffer + buf_widx);
152 /* only advance the buffer write index of the size of the struct */
153 buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
155 if (!first_handle) {
156 /* the new handle is the first one */
157 first_handle = new_handle;
160 if (cur_handle) {
161 cur_handle->next = new_handle;
164 cur_handle = new_handle;
165 cur_handle->id = cur_handle_id++;
166 cur_handle->next = NULL;
167 num_handles++;
168 return cur_handle;
171 /* delete a given memory handle from the linked list
172 and return true for success. Nothing is actually erased from memory. */
173 static bool rm_handle(struct memory_handle *h)
175 if (h == first_handle) {
176 first_handle = h->next;
177 if (h == cur_handle) {
178 DEBUGF("removing the first and last handle\n");
179 /* h was the first and last handle */
180 cur_handle = NULL;
181 buf_ridx = buf_widx;
182 } else {
183 buf_ridx = (void *)first_handle - (void *)buffer;
185 } else {
186 struct memory_handle *m = first_handle;
187 while (m && m->next != h) {
188 m = m->next;
190 if (h && m && m->next == h) {
191 m->next = h->next;
192 if (h == cur_handle) {
193 cur_handle = m;
195 } else {
196 return false;
200 num_handles--;
201 return true;
204 /* these are unfortunalty needed to be global
205 so move_handle can invalidate them */
206 static int cached_handle_id = -1;
207 static struct memory_handle *cached_handle = NULL;
209 /* Return a pointer to the memory handle of given ID.
210 NULL if the handle wasn't found */
211 static struct memory_handle *find_handle(int handle_id)
213 /* simple caching because most of the time the requested handle
214 will either be the same as the last, or the one after the last */
215 if (cached_handle)
217 if (cached_handle_id == handle_id && cached_handle_id == cached_handle->id)
218 return cached_handle;
219 else if (cached_handle->next && (cached_handle->next->id == handle_id))
221 /* JD's quick testing showd this block was only entered
222 2/1971 calls to find_handle.
223 8/1971 calls to find_handle resulted in a cache miss */
224 cached_handle = cached_handle->next;
225 cached_handle_id = handle_id;
226 return cached_handle;
230 struct memory_handle *m = first_handle;
231 while (m && m->id != handle_id) {
232 m = m->next;
234 cached_handle_id = handle_id;
235 cached_handle = m;
236 return (m && m->id == handle_id) ? m : NULL;
239 /* Move a memory handle to newpos.
240 Return a pointer to the new location of the handle */
241 static struct memory_handle *move_handle(size_t newpos, struct memory_handle *h)
243 /* make sure newpos is 32-bit aligned so that the handle struct is. */
244 newpos = (RINGBUF_ADD(newpos, 3)) & ~3;
246 DEBUGF("move_handle\n");
247 struct memory_handle *dest = (struct memory_handle *)(buffer + newpos);
249 /* Invalidate the cache to prevent it from keeping the old location of h */
250 if (h == cached_handle)
251 cached_handle = NULL;
253 /* the cur_handle pointer might need updating */
254 if (h == cur_handle) {
255 cur_handle = dest;
258 if (h == first_handle) {
259 first_handle = dest;
260 buf_ridx = newpos;
261 } else {
262 struct memory_handle *m = first_handle;
263 while (m && m->next != h) {
264 m = m->next;
266 if (h && m && m->next == h) {
267 m->next = dest;
268 } else {
269 return NULL;
273 DEBUGF("h: %lx", (long)h);
274 DEBUGF("h->id: %d", h->id);
275 DEBUGF("dest: %lx", (long)dest);
276 DEBUGF("dest->id: %d", dest->id);
277 DEBUGF("memmove");
279 rb->memmove(dest, h, sizeof(struct memory_handle));
281 DEBUGF("h: %lx", (long)h);
282 DEBUGF("dest: %lx", (long)dest);
283 DEBUGF("dest->id: %d", dest->id);
285 return dest;
287 /* Buffer data for the given handle. Return the amount of data buffered
288 or -1 if the handle wasn't found */
289 static int buffer_handle(int handle_id)
291 DEBUGF("buffer_handle(%d)", handle_id);
292 struct memory_handle *h = find_handle(handle_id);
293 if (!h)
294 return -1;
296 if (h->filerem == 0) {
297 /* nothing left to buffer */
298 return 0;
301 if (h->fd < 0) /* file closed, reopen */
303 if (*h->path)
304 h->fd = rb->open(h->path, O_RDONLY);
305 else
306 return -1;
308 if (h->fd < 0)
309 return -1;
311 if (h->offset)
312 rb->lseek(h->fd, h->offset, SEEK_SET);
315 int ret = 0;
316 while (h->filerem > 0)
318 //DEBUGF("h: %d\n", (void *)h - (void *)buffer);
319 //DEBUGF("buf_widx: %ld\n", (long)buf_widx);
320 /* max amount to copy */
321 size_t copy_n = MIN(conf_filechunk, buffer_len - buf_widx);
323 /* stop copying if it would overwrite the reading position */
324 if (RINGBUF_ADD_CROSS(buf_widx, copy_n, buf_ridx) >= 0)
325 break;
327 /* rc is the actual amount read */
328 int rc = rb->read(h->fd, &buffer[buf_widx], copy_n);
330 if (rc < 0)
332 //DEBUGF("failed on fd %d at buf_widx = %ld for handle %d\n", h->fd, (long)buf_widx, h->id);
333 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
334 h->filesize -= h->filerem;
335 h->filerem = 0;
336 break;
339 /* Advance buffer */
340 h->widx = RINGBUF_ADD(h->widx, rc);
341 if (h == cur_handle)
342 buf_widx = h->widx;
343 h->available += rc;
344 ret += rc;
345 h->filerem -= rc;
348 if (h->filerem == 0) {
349 /* finished buffering the file */
350 rb->close(h->fd);
353 DEBUGF("buffered %d bytes (%d of %d available, remaining: %d)\n",
354 ret, h->available, h->filesize, h->filerem);
355 return ret;
358 /* Free buffer space by moving the first handle struct right before the useful
359 part of its data buffer */
360 static void free_buffer(int handle_id)
362 DEBUGF("free_buffer(%d)\n", handle_id);
363 struct memory_handle *h = find_handle(handle_id);
364 if (!h)
365 return;
367 size_t delta = RINGBUF_SUB(h->ridx, h->data);
368 size_t dest = RINGBUF_ADD((void *)h - (void *)buffer, delta);
369 //DEBUGF("buf_ridx: %ld, buf_widx: %ld\n", (long)buf_ridx, (long)buf_widx);
370 //DEBUGF("dest: %ld, delta: %ld\n", (long)dest, (long)delta);
371 h = move_handle(dest, h);
372 h->data = RINGBUF_ADD(h->data, delta);
373 h->ridx = h->data;
374 h->available -= delta;
375 #ifndef ROCKBOX_HAS_LOGF
376 graph_view(100);
377 #endif
380 /* Request a file be buffered
381 filename: name of the file t open
382 offset: starting offset to buffer from the file
383 RETURNS: <0 if the file cannot be opened, or one file already
384 queued to be opened, otherwise the handle for the file in the buffer
386 static int buffering_bufopen(char *file, size_t offset)
388 DEBUGF("bufopen: %s (offset: %d)\n", file, offset);
390 int fd = rb->open(file, O_RDONLY);
391 if (fd < 0)
392 return -1;
394 if (offset)
395 rb->lseek(fd, offset, SEEK_SET);
397 int size = rb->filesize(fd) - offset;
398 struct memory_handle *h = add_handle(&size);
399 if (!h)
401 DEBUGF("failed to add handle\n");
402 return -1;
405 rb->strncpy(h->path, file, MAX_PATH);
406 h->fd = fd;
407 h->filesize = rb->filesize(fd);
408 h->filerem = h->filesize - offset;
409 h->offset = offset;
410 h->ridx = buf_widx;
411 h->widx = buf_widx;
412 h->data = buf_widx;
413 h->data_len = size;
414 h->available = 0;
416 DEBUGF("added handle : %d\n", h->id);
417 return h->id;
420 /* Close the handle. Return 0 for success and < 0 for failure */
421 static int buffering_bufclose(int handle_id)
423 DEBUGF("bufclose(%d)\n", handle_id);
424 struct memory_handle *h = find_handle(handle_id);
425 if (!h)
426 return -1;
428 rm_handle(h);
429 return 0;
432 /* Set the reading index in a handle (relatively to the start of the handle data).
433 Return 0 for success and < 0 for failure */
434 static int buffering_bufseek(int handle_id, size_t offset)
436 struct memory_handle *h = find_handle(handle_id);
437 if (!h)
438 return -1;
440 if (offset > h->available)
441 return -2;
443 h->ridx = RINGBUF_ADD(h->data, offset);
444 return 0;
447 /* Advance the reading index in a handle (relatively to its current position).
448 Return 0 for success and < 0 for failure */
449 static int buffering_bufadvance(int handle_id, ssize_t offset)
451 struct memory_handle *h = find_handle(handle_id);
452 if (!h)
453 return -1;
455 if (offset >= 0)
457 if (offset > h->available - RINGBUF_SUB(h->ridx, h->data))
458 return -2;
460 h->ridx = RINGBUF_ADD(h->ridx, offset);
462 else
464 if (-offset > RINGBUF_SUB(h->ridx, h->data))
465 return -2;
467 h->ridx = RINGBUF_SUB(h->ridx, -offset);
470 return 0;
473 /* Copy data from the given handle to the dest buffer.
474 Return the number of bytes copied or -1 for failure. */
475 static int buffering_bufread(int handle_id, size_t size, char *dest)
477 struct memory_handle *h = find_handle(handle_id);
478 size_t buffered_data;
479 if (!h)
480 return -1;
481 if (h->available == 0)
482 return 0;
483 buffered_data = MIN(size, h->available);
485 if (h->ridx + buffered_data > buffer_len)
487 size_t read = buffer_len - h->ridx;
488 rb->memcpy(dest, &buffer[h->ridx], read);
489 rb->memcpy(dest+read, buffer, buffered_data - read);
491 else rb->memcpy(dest, &buffer[h->ridx], buffered_data);
493 h->ridx = RINGBUF_ADD(h->ridx, buffered_data);
494 h->available -= buffered_data;
495 return buffered_data;
498 /* Update the "data" pointer to make the handle's data available to the caller.
499 Return the length of the available linear data or -1 for failure. */
500 static long buffering_bufgetdata(int handle_id, size_t size, unsigned char **data)
502 struct memory_handle *h = find_handle(handle_id);
503 if (!h)
504 return -1;
506 long ret;
508 if (h->ridx + size > buffer_len &&
509 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
511 /* use the guard buffer to provide what was requested. */
512 int copy_n = h->ridx + size - buffer_len;
513 rb->memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
514 ret = size;
516 else
518 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
519 buffer_len - h->ridx);
522 *data = (unsigned char *)(buffer + h->ridx);
524 //DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);
525 return ret;
528 bool test_ll(void)
530 struct memory_handle *m1, *m2, *m3, *m4;
532 if (cur_handle != NULL || first_handle != NULL)
533 return false;
535 m1 = add_handle(NULL);
537 if (cur_handle != m1 || first_handle != m1 || m1->next != NULL)
538 return false;
540 m2 = add_handle(NULL);
542 if (cur_handle != m2 || first_handle != m1 || m1->next != m2 || m2->next != NULL)
543 return false;
545 m3 = add_handle(NULL);
547 if (cur_handle != m3 || first_handle != m1 || m2->next != m3 || m3->next != NULL)
548 return false;
550 rm_handle(m2);
552 if (cur_handle != m3 || first_handle != m1 || m1->next != m3)
553 return false;
555 rm_handle(m3);
557 if (cur_handle != m1 || first_handle != m1 || m1->next != NULL)
558 return false;
560 m4 = add_handle(NULL);
562 if (cur_handle != m4 || first_handle != m1 || m1->next != m4 || m4->next != NULL)
563 return false;
565 rm_handle(m1);
567 if (cur_handle != m4 || first_handle != m4)
568 return false;
570 rm_handle(m4);
572 if (cur_handle != NULL || first_handle != NULL)
573 return false;
575 m1 = add_handle(NULL);
576 m2 = add_handle(NULL);
577 m3 = add_handle(NULL);
578 m4 = add_handle(NULL);
580 if (cur_handle != m4 || first_handle != m1)
581 return false;
583 m2 = move_handle(RINGBUF_ADD(m2->data, 1024*100), m2);
585 if (cur_handle != m4 || first_handle != m1 || m1->next != m2 || m2->next != m3)
586 return false;
588 m1 = move_handle(RINGBUF_ADD(m1->data, 1024*100*3), m1);
590 if (cur_handle != m4 || first_handle != m1 || m1->next != m2)
591 return false;
593 rm_handle(m1);
594 rm_handle(m2);
595 rm_handle(m3);
596 rm_handle(m4);
598 if (cur_handle != NULL || first_handle != NULL)
599 return false;
601 return true;
604 #if 0
605 static void list_handles(void)
607 struct memory_handle *m = first_handle;
608 while (m) {
609 DEBUGF("%02d - %d\n", m->id, (void *)m-(void *)buffer);
610 m = m->next;
613 #endif
615 #ifndef ROCKBOX_HAS_LOGF
616 /* display a nice graphical view of the ringbuffer. */
617 static void graph_view(int width)
619 int i, r_pos, w_pos;
620 r_pos = buf_ridx * width / buffer_len;
621 w_pos = buf_widx * width / buffer_len;
623 DEBUGF("|");
624 for (i=0; i <= width; i++)
626 if (i != r_pos && i != w_pos)
628 if (buf_ridx <= buf_widx)
630 if (i > r_pos && i < w_pos) {
631 DEBUGF(">");
632 } else {
633 DEBUGF("-");
636 else
638 if (i > r_pos || i < w_pos) {
639 DEBUGF(">");
640 } else {
641 DEBUGF("-");
645 else
647 if (i == r_pos && i == w_pos)
649 if (buf_ridx <= buf_widx) {
650 DEBUGF("RW");
651 } else {
652 DEBUGF("WR");
654 } else if (i == r_pos) {
655 DEBUGF("R");
656 } else if (i == w_pos) {
657 DEBUGF("W");
661 DEBUGF("|");
662 DEBUGF("\n");
664 #endif
666 bool buffer_init(void)
668 buffer = rb->plugin_get_audio_buffer(&buffer_len);
669 if (!buffer)
671 DEBUGF("couldn't allocate buffer\n");
672 return false;
674 buffer_len -= GUARD_SIZE;
675 guard_buffer = buffer + buffer_len;
677 buf_widx = 0;
678 buf_ridx = 0;
680 first_handle = NULL;
681 num_handles = 0;
683 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
685 return true;
688 /* returns true if the file still has some on disk unread */
689 bool handle_has_data(int handle)
691 struct memory_handle *m = find_handle(handle);
692 if (m)
694 return m->filerem != 0;
696 return false;
699 bool need_rebuffer(void)
701 size_t free, wasted;
702 wasted = first_handle? RINGBUF_SUB(first_handle->ridx, first_handle->data) : 0;
703 while (wasted > buffer_len / 2)
705 free_buffer(first_handle->id);
706 wasted = first_handle? RINGBUF_SUB(first_handle->ridx, first_handle->data) : 0;
708 free = buffer_len - BUF_USED;
709 return ((free >= buffer_len/4));
712 bool disk_is_spinning(void)
714 return true;
719 static long playback_stack[DEFAULT_STACK_SIZE/sizeof(long)];
720 static struct thread_entry* playbackthread_id;
722 /* Events */
723 static struct event_queue buffering_queue;
724 static struct queue_sender_list buffering_queue_sender_list;
726 bool done_buffering = false;
727 bool done_playing = false;
730 #define MAX_HANDLES 64
731 static int handle_order[MAX_HANDLES];
732 static int last_handle = -1;
734 void playback_thread(void)
736 int reading_handle = 0;
737 int fd = -1; /* used to write the files out as they are read */
738 unsigned char *data;
740 /* "Playback thread" section */
741 while (1)
743 DEBUGF("reading handle: %d\n", handle_order[reading_handle]);
744 long read;
745 long total = 0;
746 char file[MAX_PATH];
747 if (reading_handle >= last_handle
748 && !handle_has_data(handle_order[reading_handle]))
749 done_playing = true;
751 if (fd < 0)
753 rb->snprintf(file, MAX_PATH, "/file%d.mp3", reading_handle);
754 fd = rb->open(file, O_CREAT|O_TRUNC|O_WRONLY);
755 if (fd < 0)
757 DEBUGF("ERROROROROR\n");
758 rb->splash(HZ, "couldn't create file");
763 //read = bufread(handle_order[reading_handle], GUARD_SIZE,read_buffer);
764 //write(fd, read_buffer, read);
765 read = bufgetdata(handle_order[reading_handle], GUARD_SIZE, &data);
766 read = MIN(read, GUARD_SIZE);
767 rb->write(fd, data, read);
768 total += read;
769 bufadvance(handle_order[reading_handle], read);
770 rb->sleep(HZ/5);
772 while (read > 0);
774 DEBUGF("read %ld bytes from handle %d\n", total, handle_order[reading_handle]);
776 /* close the fd/handle if there is no more data or an error */
777 if (read < 0 || handle_has_data(handle_order[reading_handle]) == false)
779 DEBUGF("finished reading %d\n",handle_order[reading_handle]);
780 bufclose(handle_order[reading_handle]);
781 rb->close(fd);
782 reading_handle++;
783 fd = -1;
785 else
787 DEBUGF("there is data left to buffer for %d\n", handle_order[reading_handle]);
793 /* this is the plugin entry point */
794 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
796 (void)parameter;
797 rb = api;
799 int argc = 6;
800 char *argv[] = { NULL,
801 "/070623 - David Vendetta.mp3",
802 "/africanism all stars feat the hard boys - hard (bob sinclair remix).mp3",
803 "/alan_braxe__kris_menace_-_lumberjack.mp3",
804 "/Ame - Rej (A Hundred Birds Remix).mp3",
805 "/Antena - Camino del Sol (Joakim Remix).mp3" };
807 int next_file = 1;
808 int current_handle = -1;
809 struct memory_handle *m = NULL;
811 struct event ev;
813 buffer_init();
815 if (!test_ll())
817 DEBUGF("linked list test failed\n");
818 rb->splash(HZ, "linked list test failed");
819 return PLUGIN_ERROR;
822 /* Msg queue init - no need for queue_remove since it's not a registered
823 queue */
824 rb->queue_init( &buffering_queue, false );
826 playbackthread_id = rb->create_thread(playback_thread,
827 playback_stack,
828 sizeof(playback_stack),
829 "playback"
830 IF_PRIO(,PRIORITY_PLAYBACK)
831 IF_COP(, CPU, false));
833 if (!playbackthread_id)
835 rb->splash(HZ, "failed to create playback thread");
836 return PLUGIN_ERROR;
838 else
841 int result;
843 while (!done_buffering || !done_playing)
846 DEBUGF("buffer usage: %d handles_used: %d\n", BUF_USED, num_handles);
847 #ifndef ROCKBOX_HAS_LOGF
848 graph_view(100);
849 #endif*/
851 rb->queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
852 result = 0;
854 switch (ev.id)
856 case Q_BUFOPEN:
858 struct bufopen_data *data;
859 data = (struct bufopen *)ev.data;
860 buffering_bufopen(data->file, data->offset);
861 break;
864 case Q_BUFCLOSE:
866 buffering_bufclose((int)ev.data);
867 break;
870 case Q_BUFSEEK:
872 struct bufseek_data *data;
873 data = (struct bufseek_data *)ev.data;
874 buffering_bufseek(data->handle_id, data->offset);
875 break;
878 case Q_BUFADVANCE:
880 struct bufadvance_data *data;
881 data = (struct bufadvance_data *)ev.data;
882 buffering_bufadvance(data->handle_id, data->offset);
883 break;
886 case Q_BUFREAD:
888 struct bufread_data *data;
889 data = (struct bufread_data *)ev.data;
890 buffering_bufread(data->handle_id, data->size, data->dest);
891 break;
894 case Q_BUFGETDATA:
896 struct bufgetdata_data *data;
897 data = (struct bufgetdata_data *)ev.data;
898 buffering_bufgetdata(data->handle_id, data->size, data->data);
899 break;
903 if (result)
904 rb->queue_reply(&buffering_queue, result);
906 /* "Buffering thread" section */
907 if (!done_buffering && need_rebuffer() && disk_is_spinning())
909 m = find_handle(current_handle);
910 if ( !m || ((m->filerem == 0) && (m->next == NULL)))
912 int h = bufopen(argv[next_file], 0);
913 m = find_handle(h);
914 if (h >= 0)
916 next_file++;
917 //DEBUGF("new handle %d\n",h);
918 last_handle++;
919 handle_order[last_handle] = h;
920 buffer_handle(m->id);
922 else
924 DEBUGF("error\n");
926 current_handle = h;
928 else
930 if (m->filerem == 0)
932 m = m->next;
933 current_handle = m?m->id:-1;
935 if (m)
937 DEBUGF("buffering handle %d\n",m->id);
938 buffer_handle(m->id);
942 if (next_file == argc && m->filerem == 0)
943 done_buffering = true;
945 else
947 rb->sleep(HZ/10);
951 DEBUGF("buffer usage: %d handles_used: %d\n", BUF_USED,num_handles);
952 #ifndef ROCKBOX_HAS_LOGF
953 graph_view(100);
954 #endif*/
957 return PLUGIN_OK;
961 int bufopen(char *file, size_t offset)
963 static struct bufopen_data data;
964 data.file = file;
965 data.offset = offset;
967 return rb->queue_send(&buffering_queue, Q_BUFOPEN, &data);
970 void bufclose(int handle_id)
972 rb->queue_post(&buffering_queue, Q_BUFCLOSE, handle_id);
975 void bufseek(int handle_id, size_t offset)
977 static struct bufseek_data data;
978 data.handle_id = handle_id;
979 data.offset = offset;
981 rb->queue_post(&buffering_queue, Q_BUFSEEK, &data);
984 void bufadvance(int handle_id, ssize_t offset)
986 static struct bufadvance_data data;
987 data.handle_id = handle_id;
988 data.offset = offset;
990 rb->queue_post(&buffering_queue, Q_BUFADVANCE, &data);
993 int bufread(int handle_id, size_t size, char *dest)
995 static struct bufread_data data;
996 data.handle_id = handle_id;
997 data.size = size;
998 data.dest = dest;
1000 return rb->queue_send(&buffering_queue, Q_BUFREAD, &data);
1003 int bufgetdata(int handle_id, size_t size, unsigned char **data)
1005 static struct bufgetdata_data argdata;
1006 argdata.handle_id = handle_id;
1007 argdata.size = size;
1008 argdata.data = data;
1010 return rb->queue_send(&buffering_queue, Q_BUFGETDATA, &argdata);