1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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 /* Internal ring buffer helper macros */
44 /* Buffer pointer (p) plus value (v), wrapped if necessary */
45 #define INT_RINGBUF_ADD(h,p,v) ((p+v) < h->data_len ? p+v : p+v - h->data_len)
46 /* Buffer pointer (p) minus value (v), wrapped if necessary */
47 #define INT_RINGBUF_SUB(h,p,v) ((p>=v) ? p-v : p + h->data_len - v)
48 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
49 #define INT_RINGBUF_ADD_CROSS(h,p1,v,p2) \
50 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)h->data_len)
51 /* Bytes available in the buffer */
52 #define INT_BUF_USED(h) (INT_RINGBUF_SUB(h, h->widx, h->ridx))
54 #ifdef ROCKBOX_HAS_LOGF
55 #define DEBUGF rb->logf
76 struct memory_handle
{
77 int id
; /* A unique ID for the handle */
81 size_t data
; /* Start index of the handle's data buffer */
82 size_t data_len
; /* Length of the data buffer for the handle */
83 size_t ridx
; /* Current read pointer, relative to the data buffer */
84 size_t widx
; /* Current write pointer */
85 size_t filesize
; /* File total length */
86 size_t filerem
; /* Remaining bytes of file NOT in buffer */
87 size_t available
; /* Available bytes to read from buffer */
88 size_t offset
; /* Offset at which we started reading the file */
89 struct memory_handle
*next
;
94 static char *guard_buffer
;
96 static size_t buffer_len
;
97 static size_t buf_widx
;
98 static size_t buf_ridx
;
100 static size_t conf_filechunk
;
102 /* current memory handle in the linked list. NULL when the list is empty. */
103 static struct memory_handle
*cur_handle
;
104 /* first memory handle in the linked list. NULL when the list is empty. */
105 static struct memory_handle
*first_handle
;
106 static int num_handles
;
108 static void graph_view(int width
);
111 /* add a new handle to the linked list and return it. It will have become the
112 new current handle. The handle will reserve "data_size" bytes or if that's
113 not possible, decrease "data_size" to allow adding the handle. */
114 static struct memory_handle
*add_handle(size_t *data_size
)
116 /* this will give each handle a unique id */
117 static int cur_handle_id
= 1;
119 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
120 but before that we check we can actually align. */
121 if (RINGBUF_ADD_CROSS(buf_widx
, 3, buf_ridx
) >= 0) {
124 buf_widx
= (RINGBUF_ADD(buf_widx
, 3)) & ~3;
126 size_t len
= (data_size
? *data_size
: 0)
127 + sizeof(struct memory_handle
);
129 /* check that we actually can add the handle and its data */
130 int overlap
= RINGBUF_ADD_CROSS(buf_widx
, len
, buf_ridx
);
132 *data_size
-= overlap
+ 1;
135 if (len
< sizeof(struct memory_handle
)) {
139 struct memory_handle
*new_handle
= (struct memory_handle
*)(&buffer
[buf_widx
]);
141 /* only advance the buffer write index of the size of the struct */
142 buf_widx
= RINGBUF_ADD(buf_widx
, sizeof(struct memory_handle
));
145 /* the new handle is the first one */
146 first_handle
= new_handle
;
150 cur_handle
->next
= new_handle
;
153 cur_handle
= new_handle
;
154 cur_handle
->id
= cur_handle_id
++;
155 cur_handle
->next
= NULL
;
160 /* delete a given memory handle from the linked list
161 and return true for success. Nothing is actually erased from memory. */
162 static bool rm_handle(struct memory_handle
*h
)
164 if (h
== first_handle
) {
165 first_handle
= h
->next
;
166 if (h
== cur_handle
) {
167 DEBUGF("removing the first and last handle\n");
168 /* h was the first and last handle */
172 buf_ridx
= (void *)first_handle
- (void *)buffer
;
175 struct memory_handle
*m
= first_handle
;
176 while (m
&& m
->next
!= h
) {
179 if (h
&& m
&& m
->next
== h
) {
181 if (h
== cur_handle
) {
193 /* these are unfortunalty needed to be global
194 so move_handle can invalidate them */
195 static int cached_handle_id
= -1;
196 static struct memory_handle
*cached_handle
= NULL
;
198 /* Return a pointer to the memory handle of given ID.
199 NULL if the handle wasn't found */
200 static struct memory_handle
*find_handle(int handle_id
)
202 /* simple caching because most of the time the requested handle
203 will either be the same as the last, or the one after the last */
206 if (cached_handle_id
== handle_id
&& cached_handle_id
== cached_handle
->id
)
207 return cached_handle
;
208 else if (cached_handle
->next
&& (cached_handle
->next
->id
== handle_id
))
210 /* JD's quick testing showd this block was only entered
211 2/1971 calls to find_handle.
212 8/1971 calls to find_handle resulted in a cache miss */
213 cached_handle
= cached_handle
->next
;
214 cached_handle_id
= handle_id
;
215 return cached_handle
;
219 struct memory_handle
*m
= first_handle
;
220 while (m
&& m
->id
!= handle_id
) {
223 cached_handle_id
= handle_id
;
225 return (m
&& m
->id
== handle_id
) ? m
: NULL
;
228 /* Move a memory handle to newpos.
229 Return a pointer to the new location of the handle */
230 static struct memory_handle
*move_handle(size_t *delta
, struct memory_handle
*h
)
233 /* aligning backwards would yield a negative result,
234 and moving the handle of such a small amount is a waste
238 /* make sure delta is 32-bit aligned so that the handle struct is. */
239 *delta
= (*delta
- 3) & ~3;
241 size_t newpos
= RINGBUF_ADD((void *)h
- (void *)buffer
, *delta
);
243 struct memory_handle
*dest
= (struct memory_handle
*)(&buffer
[newpos
]);
245 /* Invalidate the cache to prevent it from keeping the old location of h */
246 if (h
== cached_handle
)
247 cached_handle
= NULL
;
249 /* the cur_handle pointer might need updating */
250 if (h
== cur_handle
) {
254 if (h
== first_handle
) {
258 struct memory_handle
*m
= first_handle
;
259 while (m
&& m
->next
!= h
) {
262 if (h
&& m
&& m
->next
== h
) {
269 rb
->memmove(dest
, h
, sizeof(struct memory_handle
));
273 /* Buffer data for the given handle. Return the amount of data buffered
274 or -1 if the handle wasn't found */
275 static ssize_t
buffer_handle(int handle_id
)
277 DEBUGF("buffer_handle(%d)\n", handle_id
);
278 struct memory_handle
*h
= find_handle(handle_id
);
282 if (h
->filerem
== 0) {
283 /* nothing left to buffer */
287 if (h
->fd
< 0) /* file closed, reopen */
290 h
->fd
= rb
->open(h
->path
, O_RDONLY
);
298 rb
->lseek(h
->fd
, h
->offset
, SEEK_SET
);
302 while (h
->filerem
> 0)
304 /* max amount to copy */
305 size_t copy_n
= MIN(MIN(conf_filechunk
, h
->filerem
),
306 MIN(h
->data_len
- h
->widx
,
307 buffer_len
- RINGBUF_ADD(h
->data
, h
->widx
))
311 DEBUGF("widx: %ld, ridx: %ld copy_n: %ld, writepos: %ld,"
312 "readpos: %ld, add_cross: %d, int_add_cross: %d\n",
313 h
->widx
, h
->ridx
, copy_n
, RINGBUF_ADD(h
->data
, h
->widx
),
314 RINGBUF_ADD(h
->data
, h
->ridx
),
315 RINGBUF_ADD_CROSS( RINGBUF_ADD(h
->data
, h
->widx
),
317 RINGBUF_ADD(h
->data
, h
->ridx
)
319 INT_RINGBUF_ADD_CROSS(h
, h
->widx
, copy_n
, h
->ridx
)
323 /* stop copying if it would overwrite the reading position.
324 buf_widx == buf_ridx is defined as buffer empty, not buffer full.
325 same goes with h->widx == h->ridx. */
326 if (RINGBUF_ADD_CROSS( RINGBUF_ADD(h
->data
, h
->widx
),
328 RINGBUF_ADD(h
->data
, h
->ridx
)
330 INT_RINGBUF_ADD_CROSS(h
, h
->widx
, copy_n
, h
->ridx
) >= 0 )
333 /* rc is the actual amount read */
334 int rc
= rb
->read(h
->fd
, &buffer
[RINGBUF_ADD(h
->data
,h
->widx
)], copy_n
);
338 DEBUGF("File ended %ld bytes early\n", (long)h
->filerem
);
339 h
->filesize
-= h
->filerem
;
345 h
->widx
= INT_RINGBUF_ADD(h
, h
->widx
, rc
);
350 if (h
->ridx
<= h
->widx
&& h
->data_len
< h
->filerem
) {
351 /* Check whether we can extend the buffer to avoid unnecessary
353 size_t extend_by
= 0;
354 if (h
== cur_handle
) {
355 extend_by
= RINGBUF_SUB(buf_ridx
, buf_widx
) - 1;
357 extend_by
= RINGBUF_SUB((size_t)((void*)h
->next
-(void*)buffer
),
358 RINGBUF_ADD(h
->data
, h
->data_len
));
361 h
->data_len
+= extend_by
;
363 DEBUGF("extended the handle data buffer by %ld bytes\n",
369 if (h
->filerem
== 0) {
370 /* finished buffering the file */
375 buf_widx
= RINGBUF_ADD(h
->data
, h
->data_len
);
377 DEBUGF("buffered %ld bytes (%ld of %ld available, remaining: %ld)\n",
378 ret
, h
->available
, h
->filesize
, h
->filerem
);
385 /* Free buffer space by moving the handle struct right before the useful
386 part of its data buffer */
387 static void free_buffer(int handle_id
)
389 DEBUGF("free_buffer(%d)\n", handle_id
);
390 struct memory_handle
*h
= find_handle(handle_id
);
394 DEBUGF("old state: data: %ld, data_len: %ld, avail: %ld, ridx: %ld, widx: %ld\n",
395 h
->data
, h
->data_len
, h
->available
, h
->ridx
, h
->widx
);
397 if (h
->ridx
> h
->widx
) {
398 /* We don't want to overwrite a useful part of the buffer */
402 size_t delta
= h
->ridx
;
403 h
= move_handle(&delta
, h
);
405 /* The value of delta might change for alignment reasons */
406 h
->data
= RINGBUF_ADD(h
->data
, delta
);
407 h
->data_len
-= delta
;
409 if (h
->widx
>= delta
) h
->widx
-= delta
;
410 h
->available
-= delta
;
412 DEBUGF("new state: data: %ld, data_len: %ld, avail: %ld, ridx: %ld, widx: %ld\n",
413 h
->data
, h
->data_len
, h
->available
, h
->ridx
, h
->widx
);
418 static void fill_buffer(void)
420 DEBUGF("fill buffer()\n");
421 struct memory_handle
*m
= first_handle
;
423 if (m
->filerem
> 0) {
424 buffer_handle(m
->id
);
431 static size_t data_rem(void)
435 struct memory_handle
*m
= first_handle
;
444 static size_t wasted_space(void)
448 struct memory_handle
*m
= first_handle
;
450 ret
+= (m
->ridx
<= m
->widx
) ? m
->ridx
: 0;
457 static size_t used_space(void)
461 struct memory_handle
*m
= first_handle
;
463 ret
+= INT_BUF_USED(m
);
470 /* Request a file be buffered
471 filename: name of the file t open
472 offset: starting offset to buffer from the file
473 RETURNS: <0 if the file cannot be opened, or one file already
474 queued to be opened, otherwise the handle for the file in the buffer
476 int bufopen(char *file
, size_t offset
)
478 int fd
= rb
->open(file
, O_RDONLY
);
482 size_t size
= rb
->filesize(fd
) - offset
+ 1;
483 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)... ",
486 struct memory_handle
*h
= add_handle(&size
);
489 DEBUGF("failed to add handle\n");
494 if (offset
) rb
->lseek(fd
, offset
, SEEK_SET
);
495 rb
->strncpy(h
->path
, file
, MAX_PATH
);
497 h
->filesize
= rb
->filesize(fd
);
498 h
->filerem
= h
->filesize
- offset
;
506 buf_widx
= RINGBUF_ADD(buf_widx
, size
);
508 DEBUGF("allocated %ld bytes. ID: %d\n", size
, h
->id
);
512 /* Close the handle. Return 0 for success and < 0 for failure */
513 int bufclose(int handle_id
)
515 DEBUGF("bufclose(%d)\n", handle_id
);
516 struct memory_handle
*h
= find_handle(handle_id
);
524 /* Set the reading index in a handle (relatively to the start of the handle data).
525 Return 0 for success and < 0 for failure */
526 int bufseek(int handle_id
, size_t offset
)
528 struct memory_handle
*h
= find_handle(handle_id
);
532 if (offset
> h
->available
|| offset
> h
->data_len
)
539 /* Advance the reading index in a handle (relatively to its current position).
540 Return 0 for success and < 0 for failure */
541 int bufadvance(int handle_id
, off_t offset
)
543 struct memory_handle
*h
= find_handle(handle_id
);
547 /* DEBUGF("bufadvance(%ld): h->ridx: %ld, h->widx: %ld\n",
548 offset, h->ridx, h->widx); */
552 /* check for access beyond what's available */
553 if ((size_t)offset
> (h
->available
- h
->ridx
))
556 h
->ridx
= INT_RINGBUF_ADD(h
, h
->ridx
, offset
);
560 /* check for access before what's available */
561 if ((size_t)(-offset
) > h
->ridx
)
564 h
->ridx
= INT_RINGBUF_SUB(h
, h
->ridx
, (size_t)(-offset
));
570 /* Copy data from the given handle to the dest buffer.
571 Return the number of bytes copied or < 0 for failure. */
572 ssize_t
bufread(int handle_id
, size_t size
, char *dest
)
574 struct memory_handle
*h
= find_handle(handle_id
);
575 size_t buffered_data
;
579 if (h
->available
== 0 && h
->filerem
> 0)
582 if (h
->available
== 0 && h
->filerem
== 0)
585 buffered_data
= MIN(size
, h
->available
);
587 if (h
->data
+ h
->ridx
+ buffered_data
> buffer_len
)
589 size_t read
= buffer_len
- (h
->data
+ h
->ridx
);
590 rb
->memcpy(dest
, &buffer
[h
->data
+ h
->ridx
], read
);
591 rb
->memcpy(dest
+read
, buffer
, buffered_data
- read
);
593 else rb
->memcpy(dest
, &buffer
[h
->data
+ h
->ridx
], buffered_data
);
595 h
->ridx
+= buffered_data
;
596 h
->available
-= buffered_data
;
597 return buffered_data
;
600 /* Update the "data" pointer to make the handle's data available to the caller.
601 Return the length of the available linear data or < 0 for failure. */
602 ssize_t
bufgetdata(int handle_id
, size_t size
, unsigned char **data
)
604 struct memory_handle
*h
= find_handle(handle_id
);
608 if (h
->available
== 0 && h
->filerem
> 0)
611 if (h
->available
== 0 && h
->filerem
== 0)
616 *data
= (unsigned char *)&buffer
[RINGBUF_ADD(h
->data
, h
->ridx
)];
618 if (buffer_len
- (h
->data
+ h
->ridx
) > 0 &&
619 buffer_len
- (h
->data
+ h
->ridx
) < size
&&
620 h
->available
- h
->ridx
>= size
)
622 /* use the guard buffer to provide what was requested. */
623 size_t copy_n
= h
->data
+ h
->ridx
+ size
- buffer_len
;
625 if (h
->ridx
+ size
> h
->data_len
) {
626 size_t copy_1
= h
->data_len
- (h
->ridx
+ size
- copy_n
);
627 size_t copy_2
= copy_n
- copy_1
;
628 rb
->memcpy(guard_buffer
,
629 (unsigned char *)buffer
, copy_1
);
630 rb
->memcpy(guard_buffer
+ copy_1
,
631 (unsigned char *)&buffer
[h
->data
], copy_2
);
633 rb
->memcpy(guard_buffer
, (unsigned char *)buffer
, copy_n
);
637 DEBUGF("used the guard buffer to complete\n");
639 else if (h
->ridx
+ size
> h
->data_len
&&
640 h
->available
- h
->ridx
>= size
&&
643 size_t copy_1
= h
->data_len
- h
->ridx
;
644 size_t copy_2
= size
- copy_1
;
645 rb
->memcpy(guard_buffer
,
646 (unsigned char *)&buffer
[RINGBUF_ADD(h
->data
, h
->ridx
)],
648 rb
->memcpy(guard_buffer
+ copy_1
,
649 (unsigned char *)&buffer
[h
->data
], copy_2
);
650 *data
= guard_buffer
;
652 DEBUGF("used the guard buffer for a whole piece\n");
656 ret
= MIN(MIN(h
->available
- h
->ridx
,
658 buffer_len
- (h
->data
+ h
->ridx
));
661 //DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);
667 struct memory_handle
*m1
, *m2
, *m3
, *m4
;
669 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
672 m1
= add_handle(NULL
);
674 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
677 m2
= add_handle(NULL
);
679 if (cur_handle
!= m2
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= NULL
)
682 m3
= add_handle(NULL
);
684 if (cur_handle
!= m3
|| first_handle
!= m1
|| m2
->next
!= m3
|| m3
->next
!= NULL
)
689 if (cur_handle
!= m3
|| first_handle
!= m1
|| m1
->next
!= m3
)
694 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
697 m4
= add_handle(NULL
);
699 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m4
|| m4
->next
!= NULL
)
704 if (cur_handle
!= m4
|| first_handle
!= m4
)
709 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
712 m1
= add_handle(NULL
);
713 m2
= add_handle(NULL
);
714 m3
= add_handle(NULL
);
715 m4
= add_handle(NULL
);
717 if (cur_handle
!= m4
|| first_handle
!= m1
)
720 size_t delta
= 1024*100;
721 m2
= move_handle(&delta
, m2
);
723 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= m3
)
727 m1
= move_handle(&delta
, m1
);
729 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m2
)
737 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
743 /* display a nice graphical view of the ringbuffer. */
744 static void graph_view(int width
)
746 #ifndef ROCKBOX_HAS_LOGF
748 r_pos
= buf_ridx
* width
/ buffer_len
;
749 w_pos
= buf_widx
* width
/ buffer_len
;
752 for (i
=0; i
<= width
; i
++)
754 if (i
!= r_pos
&& i
!= w_pos
)
756 if (buf_ridx
<= buf_widx
)
758 if (i
> r_pos
&& i
< w_pos
) {
766 if (i
> r_pos
|| i
< w_pos
) {
775 if (i
== r_pos
&& i
== w_pos
)
777 if (buf_ridx
<= buf_widx
) {
782 } else if (i
== r_pos
) {
784 } else if (i
== w_pos
) {
796 void print_progress(size_t amount
, int file
, int numfiles
)
799 rb
->lcd_clear_display();
800 rb
->snprintf(buf
, sizeof(buf
), "file %d of %d", file
, numfiles
);
801 rb
->lcd_puts(0, 0, buf
);
802 rb
->snprintf(buf
, sizeof(buf
), "read: %ld", amount
);
803 rb
->lcd_puts(0, 1, buf
);
807 bool buffer_init(void)
809 buffer
= rb
->plugin_get_audio_buffer(&buffer_len
);
812 DEBUGF("couldn't allocate buffer\n");
815 buffer_len
-= GUARD_SIZE
;
816 guard_buffer
= buffer
+ buffer_len
;
824 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
829 bool disk_is_spinning(void)
835 static long codec_stack
[4*DEFAULT_STACK_SIZE
/sizeof(long)];
836 static struct thread_entry
* codecthread_id
;
838 static long bufopen_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
839 static struct thread_entry
* bufopenthread_id
;
841 bool done_playing
= false;
843 #define MAX_HANDLES 16
845 int handles
[MAX_HANDLES
];
847 void codec_thread(void)
850 int fd
= -1; /* used to write the files out as they are read */
852 char outfile
[MAX_PATH
];
853 long read
, total
= 0;
859 if (handles
[idx
] > 0) {
862 rb
->snprintf(outfile
, MAX_PATH
, "/file%d.mp3", idx
);
863 fd
= rb
->open(outfile
, O_CREAT
|O_TRUNC
|O_WRONLY
);
865 DEBUGF("couldn't create file\n");
866 rb
->splash(HZ
, "couldn't create file");
871 read
= bufgetdata(handles
[idx
], GUARD_SIZE
, &data
);
873 read
= MIN(read
, GUARD_SIZE
);
874 rb
->write(fd
, data
, read
);
876 bufadvance(handles
[idx
], read
);
877 print_progress(total
, idx
+1, num_files
);
882 if (read
>= 0 && total
>= 0) {
883 DEBUGF("read %ld bytes from handle %d\n", total
, handles
[idx
]);
887 DEBUGF("data for handle %d isn't ready\n", handles
[idx
]);
888 } else if (read
== -1) {
889 DEBUGF("couldn't find handle %d\n", handles
[idx
]);
890 } else if (read
== 0) {
891 DEBUGF("finished reading handle %d\n", handles
[idx
]);
892 bufclose(handles
[idx
]);
898 if (idx
>= num_files
) {
909 DEBUGF("removing the codec thread\n");
910 rb
->remove_thread(NULL
);
913 void bufopen_thread(void)
916 while (idx
< num_files
)
918 ret
= bufopen(files
[idx
], 0);
920 handles
[idx
++] = ret
;
925 DEBUGF("bufopen thread finished\n");
926 rb
->remove_thread(NULL
);
930 /* this is the plugin entry point */
931 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
940 DEBUGF("linked list test failed\n");
941 rb
->splash(HZ
, "linked list test failed");
945 codecthread_id
= rb
->create_thread(codec_thread
,
949 IF_PRIO(,PRIORITY_PLAYBACK
)
950 IF_COP(, CPU
, false));
952 bufopenthread_id
= rb
->create_thread(bufopen_thread
,
954 sizeof(bufopen_stack
),
956 IF_PRIO(,PRIORITY_BACKGROUND
)
957 IF_COP(, CPU
, false));
961 rb
->splash(HZ
, "failed to create codec thread");
964 else if (!bufopenthread_id
)
966 rb
->splash(HZ
, "failed to create bufopen thread");
972 while (!done_playing
)
974 struct memory_handle
*m
= first_handle
;
976 if (m
->filerem
> 0 &&
977 m
->data_len
- INT_BUF_USED(m
) > m
->data_len
/4)
979 /* there is free space to rebuffer */
980 DEBUGF("handle %d has %ld bytes available to rebuffer\n",
981 m
->id
, m
->data_len
- INT_BUF_USED(m
));
982 buffer_handle(m
->id
);
987 if (wasted_space() > buffer_len
/4) {
988 DEBUGF("there is %ld bytes of wasted space\n", wasted_space());
989 struct memory_handle
*m
= first_handle
;
991 if (m
->filerem
== 0) {
998 if (data_rem() > 0 &&
999 used_space() < buffer_len
/4 &&
1002 DEBUGF("%ld bytes left to buffer and the buffer is running low\n",
1009 DEBUGF("done playing\n");
1014 DEBUGF("end of plugin\n");