* Add a size argument to add_handle() so that it can reserve space.
[Rockbox-MoB.git] / testplugin.c
bloba666c53ea36e8691a3814ddbcd98486ac170fb8e
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);
151 buf_widx = RINGBUF_ADD(buf_widx, len);
153 if (!first_handle) {
154 /* the new handle is the first one */
155 first_handle = new_handle;
158 if (cur_handle) {
159 cur_handle->next = new_handle;
162 cur_handle = new_handle;
163 cur_handle->id = cur_handle_id++;
164 cur_handle->next = NULL;
165 num_handles++;
166 return cur_handle;
169 /* delete a given memory handle from the linked list
170 and return true for success. Nothing is actually erased from memory. */
171 static bool rm_handle(struct memory_handle *h)
173 if (h == first_handle) {
174 first_handle = h->next;
175 if (h == cur_handle) {
176 DEBUGF("removing the first and last handle\n");
177 /* h was the first and last handle */
178 cur_handle = NULL;
179 buf_ridx = buf_widx;
180 } else {
181 buf_ridx = (void *)first_handle - (void *)buffer;
183 } else {
184 struct memory_handle *m = first_handle;
185 while (m && m->next != h) {
186 m = m->next;
188 if (h && m && m->next == h) {
189 m->next = h->next;
190 if (h == cur_handle) {
191 cur_handle = m;
193 } else {
194 return false;
198 num_handles--;
199 return true;
202 /* these are unfortunalty needed to be global
203 so move_handle can invalidate them */
204 static int cached_handle_id = -1;
205 static struct memory_handle *cached_handle = NULL;
207 /* Return a pointer to the memory handle of given ID.
208 NULL if the handle wasn't found */
209 static struct memory_handle *find_handle(int handle_id)
211 /* simple caching because most of the time the requested handle
212 will either be the same as the last, or the one after the last */
213 if (cached_handle)
215 if (cached_handle_id == handle_id && cached_handle_id == cached_handle->id)
216 return cached_handle;
217 else if (cached_handle->next && (cached_handle->next->id == handle_id))
219 /* JD's quick testing showd this block was only entered
220 2/1971 calls to find_handle.
221 8/1971 calls to find_handle resulted in a cache miss */
222 cached_handle = cached_handle->next;
223 cached_handle_id = handle_id;
224 return cached_handle;
228 struct memory_handle *m = first_handle;
229 while (m && m->id != handle_id) {
230 m = m->next;
232 cached_handle_id = handle_id;
233 cached_handle = m;
234 return (m && m->id == handle_id) ? m : NULL;
237 /* Move a memory handle to newpos.
238 Return a pointer to the new location of the handle */
239 static struct memory_handle *move_handle(size_t newpos, struct memory_handle *h)
241 /* make sure newpos is 32-bit aligned so that the handle struct is. */
242 newpos = (RINGBUF_ADD(newpos, 3)) & ~3;
244 DEBUGF("move_handle\n");
245 struct memory_handle *dest = (struct memory_handle *)(buffer + newpos);
247 /* Invalidate the cache to prevent it from keeping the old location of h */
248 if (h == cached_handle)
249 cached_handle = NULL;
251 /* the cur_handle pointer might need updating */
252 if (h == cur_handle) {
253 cur_handle = dest;
256 if (h == first_handle) {
257 first_handle = dest;
258 buf_ridx = newpos;
259 } else {
260 struct memory_handle *m = first_handle;
261 while (m && m->next != h) {
262 m = m->next;
264 if (h && m && m->next == h) {
265 m->next = dest;
266 } else {
267 return NULL;
271 DEBUGF("h: %lx", (long)h);
272 DEBUGF("h->id: %d", h->id);
273 DEBUGF("dest: %lx", (long)dest);
274 DEBUGF("dest->id: %d", dest->id);
275 DEBUGF("memmove");
277 rb->memmove(dest, h, sizeof(struct memory_handle));
279 DEBUGF("h: %lx", (long)h);
280 DEBUGF("dest: %lx", (long)dest);
281 DEBUGF("dest->id: %d", dest->id);
283 return dest;
285 /* Buffer data for the given handle. Return the amount of data buffered
286 or -1 if the handle wasn't found */
287 static int buffer_handle(int handle_id)
289 DEBUGF("buffer_handle(%d)", handle_id);
290 struct memory_handle *h = find_handle(handle_id);
291 if (!h)
292 return -1;
294 if (h->filerem == 0) {
295 /* nothing left to buffer */
296 return 0;
299 if (h->fd < 0) /* file closed, reopen */
301 if (*h->path)
302 h->fd = rb->open(h->path, O_RDONLY);
303 else
304 return -1;
306 if (h->fd < 0)
307 return -1;
309 if (h->offset)
310 rb->lseek(h->fd, h->offset, SEEK_SET);
313 int ret = 0;
314 while (h->filerem > 0)
316 //DEBUGF("h: %d\n", (void *)h - (void *)buffer);
317 //DEBUGF("buf_widx: %ld\n", (long)buf_widx);
318 /* max amount to copy */
319 size_t copy_n = MIN(conf_filechunk, buffer_len - buf_widx);
321 /* stop copying if it would overwrite the reading position */
322 if (RINGBUF_ADD_CROSS(buf_widx, copy_n, buf_ridx) >= 0)
323 break;
325 /* rc is the actual amount read */
326 int rc = rb->read(h->fd, &buffer[buf_widx], copy_n);
328 if (rc < 0)
330 //DEBUGF("failed on fd %d at buf_widx = %ld for handle %d\n", h->fd, (long)buf_widx, h->id);
331 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
332 h->filesize -= h->filerem;
333 h->filerem = 0;
334 break;
337 /* Advance buffer */
338 h->widx = RINGBUF_ADD(h->widx, rc);
339 if (h == cur_handle)
340 buf_widx = h->widx;
341 h->available += rc;
342 ret += rc;
343 h->filerem -= rc;
346 if (h->filerem == 0) {
347 /* finished buffering the file */
348 rb->close(h->fd);
351 DEBUGF("buffered %d bytes (%d of %d available, remaining: %d)\n",
352 ret, h->available, h->filesize, h->filerem);
353 return ret;
356 /* Free buffer space by moving the first handle struct right before the useful
357 part of its data buffer */
358 static void free_buffer(int handle_id)
360 DEBUGF("free_buffer(%d)\n", handle_id);
361 struct memory_handle *h = find_handle(handle_id);
362 if (!h)
363 return;
365 size_t delta = RINGBUF_SUB(h->ridx, h->data);
366 size_t dest = RINGBUF_ADD((void *)h - (void *)buffer, delta);
367 //DEBUGF("buf_ridx: %ld, buf_widx: %ld\n", (long)buf_ridx, (long)buf_widx);
368 //DEBUGF("dest: %ld, delta: %ld\n", (long)dest, (long)delta);
369 h = move_handle(dest, h);
370 h->data = RINGBUF_ADD(h->data, delta);
371 h->ridx = h->data;
372 h->available -= delta;
373 #ifndef ROCKBOX_HAS_LOGF
374 graph_view(100);
375 #endif
378 /* Request a file be buffered
379 filename: name of the file t open
380 offset: starting offset to buffer from the file
381 RETURNS: <0 if the file cannot be opened, or one file already
382 queued to be opened, otherwise the handle for the file in the buffer
384 static int buffering_bufopen(char *file, size_t offset)
386 DEBUGF("bufopen: %s (offset: %d)\n", file, offset);
388 int fd = rb->open(file, O_RDONLY);
389 if (fd < 0)
390 return -1;
392 if (offset)
393 rb->lseek(fd, offset, SEEK_SET);
395 int size = rb->filesize(fd) - offset;
396 struct memory_handle *h = add_handle(&size);
397 if (!h)
399 DEBUGF("failed to add handle\n");
400 return -1;
403 rb->strncpy(h->path, file, MAX_PATH);
404 h->fd = fd;
405 h->filesize = rb->filesize(fd);
406 h->filerem = h->filesize - offset;
407 h->offset = offset;
408 h->ridx = buf_widx;
409 h->widx = buf_widx;
410 h->data = buf_widx;
411 h->data_len = size;
412 h->available = 0;
414 DEBUGF("added handle : %d\n", h->id);
415 return h->id;
418 /* Close the handle. Return 0 for success and < 0 for failure */
419 static int buffering_bufclose(int handle_id)
421 DEBUGF("bufclose(%d)\n", handle_id);
422 struct memory_handle *h = find_handle(handle_id);
423 if (!h)
424 return -1;
426 rm_handle(h);
427 return 0;
430 /* Set the reading index in a handle (relatively to the start of the handle data).
431 Return 0 for success and < 0 for failure */
432 static int buffering_bufseek(int handle_id, size_t offset)
434 struct memory_handle *h = find_handle(handle_id);
435 if (!h)
436 return -1;
438 if (offset > h->available)
439 return -2;
441 h->ridx = RINGBUF_ADD(h->data, offset);
442 return 0;
445 /* Advance the reading index in a handle (relatively to its current position).
446 Return 0 for success and < 0 for failure */
447 static int buffering_bufadvance(int handle_id, ssize_t offset)
449 struct memory_handle *h = find_handle(handle_id);
450 if (!h)
451 return -1;
453 if (offset >= 0)
455 if (offset > h->available - RINGBUF_SUB(h->ridx, h->data))
456 return -2;
458 h->ridx = RINGBUF_ADD(h->ridx, offset);
460 else
462 if (-offset > RINGBUF_SUB(h->ridx, h->data))
463 return -2;
465 h->ridx = RINGBUF_SUB(h->ridx, -offset);
468 return 0;
471 /* Copy data from the given handle to the dest buffer.
472 Return the number of bytes copied or -1 for failure. */
473 static int buffering_bufread(int handle_id, size_t size, char *dest)
475 struct memory_handle *h = find_handle(handle_id);
476 size_t buffered_data;
477 if (!h)
478 return -1;
479 if (h->available == 0)
480 return 0;
481 buffered_data = MIN(size, h->available);
483 if (h->ridx + buffered_data > buffer_len)
485 size_t read = buffer_len - h->ridx;
486 rb->memcpy(dest, &buffer[h->ridx], read);
487 rb->memcpy(dest+read, buffer, buffered_data - read);
489 else rb->memcpy(dest, &buffer[h->ridx], buffered_data);
491 h->ridx = RINGBUF_ADD(h->ridx, buffered_data);
492 h->available -= buffered_data;
493 return buffered_data;
496 /* Update the "data" pointer to make the handle's data available to the caller.
497 Return the length of the available linear data or -1 for failure. */
498 static long buffering_bufgetdata(int handle_id, size_t size, unsigned char **data)
500 struct memory_handle *h = find_handle(handle_id);
501 if (!h)
502 return -1;
504 long ret;
506 if (h->ridx + size > buffer_len &&
507 h->available - RINGBUF_SUB(h->ridx, h->data) >= size)
509 /* use the guard buffer to provide what was requested. */
510 int copy_n = h->ridx + size - buffer_len;
511 rb->memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
512 ret = size;
514 else
516 ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),
517 buffer_len - h->ridx);
520 *data = (unsigned char *)(buffer + h->ridx);
522 //DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);
523 return ret;
526 bool test_ll(void)
528 struct memory_handle *m1, *m2, *m3, *m4;
530 if (cur_handle != NULL || first_handle != NULL)
531 return false;
533 m1 = add_handle(NULL);
535 if (cur_handle != m1 || first_handle != m1 || m1->next != NULL)
536 return false;
538 m2 = add_handle(NULL);
540 if (cur_handle != m2 || first_handle != m1 || m1->next != m2 || m2->next != NULL)
541 return false;
543 m3 = add_handle(NULL);
545 if (cur_handle != m3 || first_handle != m1 || m2->next != m3 || m3->next != NULL)
546 return false;
548 rm_handle(m2);
550 if (cur_handle != m3 || first_handle != m1 || m1->next != m3)
551 return false;
553 rm_handle(m3);
555 if (cur_handle != m1 || first_handle != m1 || m1->next != NULL)
556 return false;
558 m4 = add_handle(NULL);
560 if (cur_handle != m4 || first_handle != m1 || m1->next != m4 || m4->next != NULL)
561 return false;
563 rm_handle(m1);
565 if (cur_handle != m4 || first_handle != m4)
566 return false;
568 rm_handle(m4);
570 if (cur_handle != NULL || first_handle != NULL)
571 return false;
573 m1 = add_handle(NULL);
574 m2 = add_handle(NULL);
575 m3 = add_handle(NULL);
576 m4 = add_handle(NULL);
578 if (cur_handle != m4 || first_handle != m1)
579 return false;
581 m2 = move_handle(RINGBUF_ADD(m2->data, 1024*100), m2);
583 if (cur_handle != m4 || first_handle != m1 || m1->next != m2 || m2->next != m3)
584 return false;
586 m1 = move_handle(RINGBUF_ADD(m1->data, 1024*100*3), m1);
588 if (cur_handle != m4 || first_handle != m1 || m1->next != m2)
589 return false;
591 rm_handle(m1);
592 rm_handle(m2);
593 rm_handle(m3);
594 rm_handle(m4);
596 if (cur_handle != NULL || first_handle != NULL)
597 return false;
599 return true;
602 #if 0
603 static void list_handles(void)
605 struct memory_handle *m = first_handle;
606 while (m) {
607 DEBUGF("%02d - %d\n", m->id, (void *)m-(void *)buffer);
608 m = m->next;
611 #endif
613 #ifndef ROCKBOX_HAS_LOGF
614 /* display a nice graphical view of the ringbuffer. */
615 static void graph_view(int width)
617 int i, r_pos, w_pos;
618 r_pos = buf_ridx * width / buffer_len;
619 w_pos = buf_widx * width / buffer_len;
621 DEBUGF("|");
622 for (i=0; i <= width; i++)
624 if (i != r_pos && i != w_pos)
626 if (buf_ridx <= buf_widx)
628 if (i > r_pos && i < w_pos) {
629 DEBUGF(">");
630 } else {
631 DEBUGF("-");
634 else
636 if (i > r_pos || i < w_pos) {
637 DEBUGF(">");
638 } else {
639 DEBUGF("-");
643 else
645 if (i == r_pos && i == w_pos)
647 if (buf_ridx <= buf_widx) {
648 DEBUGF("RW");
649 } else {
650 DEBUGF("WR");
652 } else if (i == r_pos) {
653 DEBUGF("R");
654 } else if (i == w_pos) {
655 DEBUGF("W");
659 DEBUGF("|");
660 DEBUGF("\n");
662 #endif
664 bool buffer_init(void)
666 buffer = rb->plugin_get_audio_buffer(&buffer_len);
667 if (!buffer)
669 DEBUGF("couldn't allocate buffer\n");
670 return false;
672 buffer_len -= GUARD_SIZE;
673 guard_buffer = buffer + buffer_len;
675 buf_widx = 0;
676 buf_ridx = 0;
678 first_handle = NULL;
679 num_handles = 0;
681 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
683 return true;
686 /* returns true if the file still has some on disk unread */
687 bool handle_has_data(int handle)
689 struct memory_handle *m = find_handle(handle);
690 if (m)
692 return m->filerem != 0;
694 return false;
697 bool need_rebuffer(void)
699 size_t free, wasted;
700 wasted = first_handle? RINGBUF_SUB(first_handle->ridx, first_handle->data) : 0;
701 while (wasted > buffer_len / 2)
703 free_buffer(first_handle->id);
704 wasted = first_handle? RINGBUF_SUB(first_handle->ridx, first_handle->data) : 0;
706 free = buffer_len - BUF_USED;
707 return ((free >= buffer_len/4));
710 bool disk_is_spinning(void)
712 return true;
717 static long playback_stack[DEFAULT_STACK_SIZE/sizeof(long)];
718 static struct thread_entry* playbackthread_id;
720 /* Events */
721 static struct event_queue buffering_queue;
722 static struct queue_sender_list buffering_queue_sender_list;
724 bool done_buffering = false;
725 bool done_playing = false;
728 #define MAX_HANDLES 64
729 static int handle_order[MAX_HANDLES];
730 static int last_handle = -1;
732 void playback_thread(void)
734 int reading_handle = 0;
735 int fd = -1; /* used to write the files out as they are read */
736 unsigned char *data;
738 /* "Playback thread" section */
739 while (1)
741 DEBUGF("reading handle: %d\n", handle_order[reading_handle]);
742 long read;
743 long total = 0;
744 char file[MAX_PATH];
745 if (reading_handle >= last_handle
746 && !handle_has_data(handle_order[reading_handle]))
747 done_playing = true;
749 if (fd < 0)
751 rb->snprintf(file, MAX_PATH, "/file%d.mp3", reading_handle);
752 fd = rb->open(file, O_CREAT|O_TRUNC|O_WRONLY);
753 if (fd < 0)
755 DEBUGF("ERROROROROR\n");
756 rb->splash(HZ, "couldn't create file");
761 //read = bufread(handle_order[reading_handle], GUARD_SIZE,read_buffer);
762 //write(fd, read_buffer, read);
763 read = bufgetdata(handle_order[reading_handle], GUARD_SIZE, &data);
764 read = MIN(read, GUARD_SIZE);
765 rb->write(fd, data, read);
766 total += read;
767 bufadvance(handle_order[reading_handle], read);
768 rb->sleep(HZ/5);
770 while (read > 0);
772 DEBUGF("read %ld bytes from handle %d\n", total, handle_order[reading_handle]);
774 /* close the fd/handle if there is no more data or an error */
775 if (read < 0 || handle_has_data(handle_order[reading_handle]) == false)
777 DEBUGF("finished reading %d\n",handle_order[reading_handle]);
778 bufclose(handle_order[reading_handle]);
779 rb->close(fd);
780 reading_handle++;
781 fd = -1;
783 else
785 DEBUGF("there is data left to buffer for %d\n", handle_order[reading_handle]);
791 /* this is the plugin entry point */
792 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
794 (void)parameter;
795 rb = api;
797 int argc = 6;
798 char *argv[] = { NULL,
799 "/070623 - David Vendetta.mp3",
800 "/africanism all stars feat the hard boys - hard (bob sinclair remix).mp3",
801 "/alan_braxe__kris_menace_-_lumberjack.mp3",
802 "/Ame - Rej (A Hundred Birds Remix).mp3",
803 "/Antena - Camino del Sol (Joakim Remix).mp3" };
805 int next_file = 1;
806 int current_handle = -1;
807 struct memory_handle *m = NULL;
809 struct event ev;
811 buffer_init();
813 if (!test_ll())
815 DEBUGF("linked list test failed\n");
816 rb->splash(HZ, "linked list test failed");
817 return PLUGIN_ERROR;
820 /* Msg queue init - no need for queue_remove since it's not a registered
821 queue */
822 rb->queue_init( &buffering_queue, false );
824 playbackthread_id = rb->create_thread(playback_thread,
825 playback_stack,
826 sizeof(playback_stack),
827 "playback"
828 IF_PRIO(,PRIORITY_PLAYBACK)
829 IF_COP(, CPU, false));
831 if (!playbackthread_id)
833 rb->splash(HZ, "failed to create playback thread");
834 return PLUGIN_ERROR;
836 else
839 int result;
841 while (!done_buffering || !done_playing)
844 DEBUGF("buffer usage: %d handles_used: %d\n", BUF_USED, num_handles);
845 #ifndef ROCKBOX_HAS_LOGF
846 graph_view(100);
847 #endif*/
849 rb->queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
850 result = 0;
852 switch (ev.id)
854 case Q_BUFOPEN:
856 struct bufopen_data *data;
857 data = (struct bufopen *)ev.data;
858 buffering_bufopen(data->file, data->offset);
859 break;
862 case Q_BUFCLOSE:
864 buffering_bufclose((int)ev.data);
865 break;
868 case Q_BUFSEEK:
870 struct bufseek_data *data;
871 data = (struct bufseek_data *)ev.data;
872 buffering_bufseek(data->handle_id, data->offset);
873 break;
876 case Q_BUFADVANCE:
878 struct bufadvance_data *data;
879 data = (struct bufadvance_data *)ev.data;
880 buffering_bufadvance(data->handle_id, data->offset);
881 break;
884 case Q_BUFREAD:
886 struct bufread_data *data;
887 data = (struct bufread_data *)ev.data;
888 buffering_bufread(data->handle_id, data->size, data->dest);
889 break;
892 case Q_BUFGETDATA:
894 struct bufgetdata_data *data;
895 data = (struct bufgetdata_data *)ev.data;
896 buffering_bufgetdata(data->handle_id, data->size, data->data);
897 break;
901 if (result)
902 rb->queue_reply(&buffering_queue, result);
904 /* "Buffering thread" section */
905 if (!done_buffering && need_rebuffer() && disk_is_spinning())
907 m = find_handle(current_handle);
908 if ( !m || ((m->filerem == 0) && (m->next == NULL)))
910 int h = bufopen(argv[next_file], 0);
911 m = find_handle(h);
912 if (h >= 0)
914 next_file++;
915 //DEBUGF("new handle %d\n",h);
916 last_handle++;
917 handle_order[last_handle] = h;
918 buffer_handle(m->id);
920 else
922 DEBUGF("error\n");
924 current_handle = h;
926 else
928 if (m->filerem == 0)
930 m = m->next;
931 current_handle = m?m->id:-1;
933 if (m)
935 DEBUGF("buffering handle %d\n",m->id);
936 buffer_handle(m->id);
940 if (next_file == argc && m->filerem == 0)
941 done_buffering = true;
943 else
945 rb->sleep(HZ/10);
949 DEBUGF("buffer usage: %d handles_used: %d\n", BUF_USED,num_handles);
950 #ifndef ROCKBOX_HAS_LOGF
951 graph_view(100);
952 #endif*/
955 return PLUGIN_OK;
959 int bufopen(char *file, size_t offset)
961 static struct bufopen_data data;
962 data.file = file;
963 data.offset = offset;
965 return rb->queue_send(&buffering_queue, Q_BUFOPEN, &data);
968 void bufclose(int handle_id)
970 rb->queue_post(&buffering_queue, Q_BUFCLOSE, handle_id);
973 void bufseek(int handle_id, size_t offset)
975 static struct bufseek_data data;
976 data.handle_id = handle_id;
977 data.offset = offset;
979 rb->queue_post(&buffering_queue, Q_BUFSEEK, &data);
982 void bufadvance(int handle_id, ssize_t offset)
984 static struct bufadvance_data data;
985 data.handle_id = handle_id;
986 data.offset = offset;
988 rb->queue_post(&buffering_queue, Q_BUFADVANCE, &data);
991 int bufread(int handle_id, size_t size, char *dest)
993 static struct bufread_data data;
994 data.handle_id = handle_id;
995 data.size = size;
996 data.dest = dest;
998 return rb->queue_send(&buffering_queue, Q_BUFREAD, &data);
1001 int bufgetdata(int handle_id, size_t size, unsigned char **data)
1003 static struct bufgetdata_data argdata;
1004 argdata.handle_id = handle_id;
1005 argdata.size = size;
1006 argdata.data = data;
1008 return rb->queue_send(&buffering_queue, Q_BUFGETDATA, &argdata);