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 #ifdef ROCKBOX_HAS_LOGF
44 #define DEBUGF rb->logf
55 static void graph_view(int width
);
67 struct memory_handle
{
68 int id
; /* A unique ID for the handle */
72 size_t data
; /* Start index of the handle's data buffer */
73 size_t ridx
; /* Current read pointer, relative to the main buffer */
74 size_t widx
; /* Current write pointer */
75 size_t filesize
; /* File total length */
76 size_t filerem
; /* Remaining bytes of file NOT in buffer */
77 size_t available
; /* Available bytes to read from buffer */
78 size_t offset
; /* Offset at which we started reading the file */
79 struct memory_handle
*next
;
84 static char *guard_buffer
;
86 static size_t buffer_len
;
88 static size_t buf_widx
; /* current writing position */
89 static size_t buf_ridx
; /* current reading position */
90 /* buf_*idx are values relative to the buffer, not real pointers. */
92 static size_t conf_filechunk
;
94 /* current memory handle in the linked list. NULL when the list is empty. */
95 static struct memory_handle
*cur_handle
;
96 /* first memory handle in the linked list. NULL when the list is empty. */
97 static struct memory_handle
*first_handle
;
99 static int num_handles
; /* number of handles in the list */
101 /* Handle cache (makes find_handle faster).
102 These need to be global so that move_handle can invalidate them. */
103 static int cached_handle_id
= -1;
104 static struct memory_handle
*cached_handle
= NULL
;
108 LINKED LIST MANAGEMENT
109 ======================
111 add_handle : Add a handle to the list
112 rm_handle : Remove a handle from the list
113 find_handle : Get a handle pointer from an ID
114 move_handle : Move a handle in the buffer (with or without its data)
116 These functions only handle the linked list structure. They don't touch the
117 contents of the struct memory_handle headers. They also change the buf_*idx
118 pointers when necessary and manage the handle IDs.
120 The first and current (== last) handle are kept track of.
121 A new handle is added at buf_widx and becomes the current one.
122 buf_widx always points to the current writing position for the current handle
123 buf_ridx always points to the location of the first handle.
124 buf_ridx == buf_widx means the buffer is empty.
128 /* Add a new handle to the linked list and return it. It will have become the
129 new current handle. The handle will reserve "data_size" bytes or if that's
130 not possible, decrease "data_size" to allow adding the handle. */
131 static struct memory_handle
*add_handle(size_t *data_size
)
133 /* this will give each handle a unique id */
134 static int cur_handle_id
= 1;
136 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
137 but before that we check we can actually align. */
138 if (RINGBUF_ADD_CROSS(buf_widx
, 3, buf_ridx
) >= 0) {
141 buf_widx
= (RINGBUF_ADD(buf_widx
, 3)) & ~3;
143 size_t len
= (data_size
? *data_size
: 0)
144 + sizeof(struct memory_handle
);
146 /* check that we actually can add the handle and its data */
147 int overlap
= RINGBUF_ADD_CROSS(buf_widx
, len
, buf_ridx
);
149 *data_size
-= overlap
;
152 if (len
< sizeof(struct memory_handle
)) {
153 /* There isn't even enough space to write the struct */
157 struct memory_handle
*new_handle
=
158 (struct memory_handle
*)(&buffer
[buf_widx
]);
160 /* only advance the buffer write index of the size of the struct */
161 buf_widx
= RINGBUF_ADD(buf_widx
, sizeof(struct memory_handle
));
164 /* the new handle is the first one */
165 first_handle
= new_handle
;
169 cur_handle
->next
= new_handle
;
172 cur_handle
= new_handle
;
173 cur_handle
->id
= cur_handle_id
++;
174 cur_handle
->next
= NULL
;
179 /* Delete a given memory handle from the linked list
180 and return true for success. Nothing is actually erased from memory. */
181 static bool rm_handle(struct memory_handle
*h
)
183 if (h
== first_handle
) {
184 first_handle
= h
->next
;
185 if (h
== cur_handle
) {
186 /* h was the first and last handle: the buffer is now empty */
190 /* update buf_ridx to point to the new first handle */
191 buf_ridx
= (void *)first_handle
- (void *)buffer
;
194 struct memory_handle
*m
= first_handle
;
195 while (m
&& m
->next
!= h
) {
198 if (h
&& m
&& m
->next
== h
) {
200 if (h
== cur_handle
) {
212 /* Return a pointer to the memory handle of given ID.
213 NULL if the handle wasn't found */
214 static struct memory_handle
*find_handle(int handle_id
)
216 /* simple caching because most of the time the requested handle
217 will either be the same as the last, or the one after the last */
220 if (cached_handle_id
== handle_id
&&
221 cached_handle_id
== cached_handle
->id
)
222 return cached_handle
;
223 else if (cached_handle
->next
&& (cached_handle
->next
->id
== handle_id
))
225 /* JD's quick testing showd this block was only entered
226 2/1971 calls to find_handle.
227 8/1971 calls to find_handle resulted in a cache miss */
228 cached_handle
= cached_handle
->next
;
229 cached_handle_id
= handle_id
;
230 return cached_handle
;
234 struct memory_handle
*m
= first_handle
;
235 while (m
&& m
->id
!= handle_id
) {
238 cached_handle_id
= handle_id
;
240 return (m
&& m
->id
== handle_id
) ? m
: NULL
;
243 /* Move a memory handle and data_size of its data of delta.
244 Return a pointer to the new location of the handle.
245 delta is the value of which to move the struct data.
246 data_size is the amount of data to move along with the struct. */
247 static struct memory_handle
*move_handle(struct memory_handle
*h
,
248 size_t *delta
, size_t data_size
)
251 /* aligning backwards would yield a negative result,
252 and moving the handle of such a small amount is a waste
256 /* make sure delta is 32-bit aligned so that the handle struct is. */
257 *delta
= (*delta
- 3) & ~3;
259 size_t newpos
= RINGBUF_ADD((void *)h
- (void *)buffer
, *delta
);
261 struct memory_handle
*dest
= (struct memory_handle
*)(&buffer
[newpos
]);
263 /* Invalidate the cache to prevent it from keeping the old location of h */
264 if (h
== cached_handle
)
265 cached_handle
= NULL
;
267 /* the cur_handle pointer might need updating */
268 if (h
== cur_handle
) {
272 if (h
== first_handle
) {
276 struct memory_handle
*m
= first_handle
;
277 while (m
&& m
->next
!= h
) {
280 if (h
&& m
&& m
->next
== h
) {
287 rb
->memmove(dest
, h
, sizeof(struct memory_handle
) + data_size
);
294 BUFFER SPACE MANAGEMENT
295 =======================
297 buffer_handle : Buffer data for a handle
298 free_buffer : Free buffer space by moving a handle
299 fill_buffer : Call buffer_handle for all handles that have data to buffer
300 data_rem : Total amount of data needing to be buffered
301 wasted_space : Total amount of space available for freeing
303 These functions are used by the buffering thread to manage buffer space.
306 /* Buffer data for the given handle. Return the amount of data buffered
307 or -1 if the handle wasn't found */
308 static ssize_t
buffer_handle(int handle_id
)
310 DEBUGF("buffer_handle(%d)\n", handle_id
);
311 struct memory_handle
*h
= find_handle(handle_id
);
315 if (h
->filerem
== 0) {
316 /* nothing left to buffer */
320 if (h
->fd
< 0) /* file closed, reopen */
323 h
->fd
= rb
->open(h
->path
, O_RDONLY
);
331 rb
->lseek(h
->fd
, h
->offset
, SEEK_SET
);
335 while (h
->filerem
> 0)
337 /* max amount to copy */
338 size_t copy_n
= MIN( MIN(h
->filerem
, conf_filechunk
),
339 buffer_len
- h
->widx
);
341 /* stop copying if it would overwrite the reading position
342 or the next handle */
343 if (RINGBUF_ADD_CROSS(h
->widx
, copy_n
, buf_ridx
) >= 0 || (h
->next
&&
344 RINGBUF_ADD_CROSS(h
->widx
, copy_n
, (unsigned)
345 ((void *)h
->next
- (void *)buffer
)) > 0))
348 /* rc is the actual amount read */
349 int rc
= rb
->read(h
->fd
, &buffer
[h
->widx
], copy_n
);
353 DEBUGF("File ended %ld bytes early\n", (long)h
->filerem
);
354 h
->filesize
-= h
->filerem
;
360 h
->widx
= RINGBUF_ADD(h
->widx
, rc
);
368 if (h
->filerem
== 0) {
369 /* finished buffering the file */
373 DEBUGF("buffered %ld bytes (%ld of %ld available, remaining: %ld)\n",
374 ret
, h
->available
, h
->filesize
, h
->filerem
);
381 /* Free buffer space by moving the handle struct right before the useful
382 part of its data buffer or by moving all the data. */
383 static void free_buffer(int handle_id
)
385 struct memory_handle
*h
= find_handle(handle_id
);
390 /* The value of delta might change for alignment reasons */
392 if (h
->next
&& (h
->type
== TYPE_ID3
|| h
->type
== TYPE_CUESHEET
||
393 h
->type
== TYPE_IMAGE
) && h
->filerem
== 0 )
395 /* metadata handle: we can move all of it */
396 delta
= RINGBUF_SUB( (unsigned)((void *)h
->next
- (void *)buffer
),
397 h
->data
) - h
->available
;
398 h
= move_handle(h
, &delta
, h
->available
);
400 h
->data
= RINGBUF_ADD(h
->data
, delta
);
401 h
->ridx
= RINGBUF_ADD(h
->ridx
, delta
);
402 DEBUGF("free_buffer(%d): metadata, moved by %ld bytes\n",
407 /* only move the handle struct */
408 delta
= RINGBUF_SUB(h
->ridx
, h
->data
);
409 h
= move_handle(h
, &delta
, 0);
411 h
->data
= RINGBUF_ADD(h
->data
, delta
);
412 h
->available
-= delta
;
413 DEBUGF("free_buffer(%d): audio, %ld bytes freed\n", handle_id
, delta
);
417 /* Fill the buffer by buffering as much data as possible for handles that still
418 have data left to buffer */
419 static void fill_buffer(void)
421 DEBUGF("fill buffer()\n");
422 struct memory_handle
*m
= first_handle
;
424 if (m
->filerem
> 0) {
425 buffer_handle(m
->id
);
431 /* Return the total amount of data left to be buffered for all the handles */
432 static size_t data_rem(void)
436 struct memory_handle
*m
= first_handle
;
445 /* Return the amount of data we have but don't need anymore. This data can be
446 safely erased to reclaim buffer space. */
447 static size_t wasted_space(void)
451 struct memory_handle
*m
= first_handle
;
453 ret
+= RINGBUF_SUB(m
->ridx
, m
->data
);
462 BUFFERING API FUNCTIONS
463 =======================
465 bufopen : Request the opening of a new handle for a file
466 bufclose : Close an open handle
467 bufseek : Set the read pointer in a handle
468 bufadvance : Move the read pointer in a handle
469 bufread : Copy data from a handle into a given buffer
470 bufgetdata : Give a pointer to the handle's data
472 These functions are exported, to allow interaction with the buffer.
473 They take care of the content of the structs, and rely on the linked list
474 management functions for all the actual handle management work.
478 /* Request a file be buffered
479 filename: name of the file to open
480 offset:starting offset to buffer from the file
481 return value: <0 if the file cannot be opened, or one file already
482 queued to be opened, otherwise the handle for the file in the buffer
484 int bufopen(char *file
, size_t offset
, enum data_type type
)
486 if (cur_handle
&& cur_handle
->filerem
> 0) {
487 /* the current handle hasn't finished buffering. We can only add
488 a new one if there is already enough free space to finish
490 if (cur_handle
->filerem
< (buffer_len
- BUF_USED
)) {
491 /* Before adding the new handle we reserve some space for the
492 current one to finish buffering its data. */
493 buf_widx
= RINGBUF_ADD(buf_widx
, cur_handle
->filerem
);
499 int fd
= rb
->open(file
, O_RDONLY
);
503 size_t size
= rb
->filesize(fd
) - offset
;
505 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
508 struct memory_handle
*h
= add_handle(&size
);
511 DEBUGF("failed to add handle\n");
516 if (offset
) rb
->lseek(fd
, offset
, SEEK_SET
);
517 rb
->strncpy(h
->path
, file
, MAX_PATH
);
519 h
->filesize
= rb
->filesize(fd
);
520 h
->filerem
= h
->filesize
- offset
;
528 DEBUGF("allocated %ld bytes. ID: %d\n", size
, h
->id
);
532 /* Close the handle. Return 0 for success and < 0 for failure */
533 int bufclose(int handle_id
)
535 DEBUGF("bufclose(%d)\n", handle_id
);
536 struct memory_handle
*h
= find_handle(handle_id
);
544 /* Set reading index in handle (relatively to the start of the handle data).
545 Return 0 for success and < 0 for failure */
546 int bufseek(int handle_id
, size_t offset
)
548 struct memory_handle
*h
= find_handle(handle_id
);
552 if (offset
> h
->available
)
555 h
->ridx
= RINGBUF_ADD(h
->data
, offset
);
559 /* Advance the reading index in a handle (relatively to its current position).
560 Return 0 for success and < 0 for failure */
561 int bufadvance(int handle_id
, off_t offset
)
563 struct memory_handle
*h
= find_handle(handle_id
);
569 /* check for access beyond what's available */
570 if ((size_t)offset
> (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
)))
573 h
->ridx
= RINGBUF_ADD(h
->ridx
, offset
);
577 /* check for access before what's available */
578 if ((size_t)(-offset
) > RINGBUF_SUB(h
->ridx
, h
->data
))
581 h
->ridx
= RINGBUF_SUB(h
->ridx
, (size_t)(-offset
));
587 /* Copy data from the given handle to the dest buffer.
588 Return the number of bytes copied or < 0 for failure. */
589 ssize_t
bufread(int handle_id
, size_t size
, char *dest
)
591 struct memory_handle
*h
= find_handle(handle_id
);
592 size_t buffered_data
;
596 if (h
->available
== 0 && h
->filerem
> 0) /* Data isn't ready */
599 if (h
->available
== 0 && h
->filerem
== 0) /* File is finished reading */
602 buffered_data
= MIN(size
, h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
));
604 if (h
->ridx
+ buffered_data
> buffer_len
)
606 /* the data wraps around the end of the buffer */
607 size_t read
= buffer_len
- h
->ridx
;
608 rb
->memcpy(dest
, &buffer
[h
->ridx
], read
);
609 rb
->memcpy(dest
+read
, buffer
, buffered_data
- read
);
611 else rb
->memcpy(dest
, &buffer
[h
->ridx
], buffered_data
);
613 return buffered_data
;
616 /* Update the "data" pointer to make the handle's data available to the caller.
617 Return the length of the available linear data or < 0 for failure.
618 size is the amount of linear data requested. it can be 0 to get as
620 The guard buffer may be used to provide the requested size */
621 ssize_t
bufgetdata(int handle_id
, size_t size
, unsigned char **data
)
623 struct memory_handle
*h
= find_handle(handle_id
);
627 if (h
->available
== 0 && h
->filerem
> 0) /* Data isn't ready */
630 if (h
->available
== 0 && h
->filerem
== 0) /* File is finished reading */
635 if (h
->ridx
+ size
> buffer_len
&&
636 h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) >= size
)
638 /* the data wraps around the end of the buffer :
639 use the guard buffer to provide the requested amount of data. */
640 size_t copy_n
= MIN(h
->ridx
+ size
- buffer_len
, GUARD_SIZE
);
641 rb
->memcpy(guard_buffer
, (unsigned char *)buffer
, copy_n
);
642 ret
= buffer_len
- h
->ridx
+ copy_n
;
643 DEBUGF("used the guard buffer to complete\n");
647 ret
= MIN(h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
),
648 buffer_len
- h
->ridx
);
651 *data
= (unsigned char *)&buffer
[h
->ridx
];
653 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
654 (long)h->ridx, ret); */
666 struct memory_handle
*m1
, *m2
, *m3
, *m4
;
668 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
671 m1
= add_handle(NULL
);
673 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
676 m2
= add_handle(NULL
);
678 if (cur_handle
!= m2
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= NULL
)
681 m3
= add_handle(NULL
);
683 if (cur_handle
!= m3
|| first_handle
!= m1
|| m2
->next
!= m3
|| m3
->next
!= NULL
)
688 if (cur_handle
!= m3
|| first_handle
!= m1
|| m1
->next
!= m3
)
693 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
696 m4
= add_handle(NULL
);
698 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m4
|| m4
->next
!= NULL
)
703 if (cur_handle
!= m4
|| first_handle
!= m4
)
708 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
711 m1
= add_handle(NULL
);
712 m2
= add_handle(NULL
);
713 m3
= add_handle(NULL
);
714 m4
= add_handle(NULL
);
716 if (cur_handle
!= m4
|| first_handle
!= m1
)
719 size_t delta
= 1024*100;
720 m2
= move_handle(m2
, &delta
, 0);
722 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= m3
)
726 m1
= move_handle(m1
, &delta
, 0);
728 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m2
)
736 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
742 /* display a nice graphical view of the ringbuffer. */
743 static void graph_view(int width
)
745 #ifndef ROCKBOX_HAS_LOGF
747 r_pos
= buf_ridx
* width
/ buffer_len
;
748 w_pos
= buf_widx
* width
/ buffer_len
;
751 for (i
=0; i
<= width
; i
++)
753 if (i
!= r_pos
&& i
!= w_pos
)
755 if (buf_ridx
<= buf_widx
)
757 if (i
> r_pos
&& i
< w_pos
) {
765 if (i
> r_pos
|| i
< w_pos
) {
774 if (i
== r_pos
&& i
== w_pos
)
776 if (buf_ridx
<= buf_widx
) {
781 } else if (i
== r_pos
) {
783 } else if (i
== w_pos
) {
795 void print_progress(size_t amount
, int file
, int numfiles
)
798 rb
->snprintf(buf
, sizeof(buf
), "file %d of %d", file
, numfiles
);
799 rb
->lcd_puts(0, 0, buf
);
800 rb
->snprintf(buf
, sizeof(buf
), "read: %ld", amount
);
801 rb
->lcd_puts(0, 1, buf
);
804 void print_metadata(int handle_id
)
807 char *artist
, *title
, *newline
;
808 char art
[50], ttl
[50];
809 int artist_len
, title_len
;
812 ret
= bufgetdata(handle_id
, 0, &buf
);
815 newline
= rb
->strchr(artist
, '\n');
816 artist_len
= newline
- artist
;
817 rb
->strncpy(art
, artist
, artist_len
);
821 newline
= rb
->strchr(title
, '\n');
822 title_len
= newline
- title
;
823 rb
->strncpy(ttl
, title
, title_len
);
826 rb
->lcd_puts(0, 3, art
);
827 rb
->lcd_puts(0, 4, ttl
);
830 bool buffer_init(void)
832 buffer
= rb
->plugin_get_audio_buffer(&buffer_len
);
835 DEBUGF("couldn't allocate buffer\n");
838 buffer_len
-= GUARD_SIZE
;
839 guard_buffer
= buffer
+ buffer_len
;
847 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
852 bool disk_is_spinning(void)
863 static long codec_stack
[4*DEFAULT_STACK_SIZE
/sizeof(long)];
864 static struct thread_entry
* codecthread_id
;
866 static long bufopen_stack
[2*DEFAULT_STACK_SIZE
/sizeof(long)];
867 static struct thread_entry
* bufopenthread_id
;
869 bool done_playing
= false;
871 #define MAX_HANDLES 16
873 int handles
[MAX_HANDLES
];
874 int meta_handles
[MAX_HANDLES
];
876 void codec_thread(void)
879 int fd
= -1; /* used to write the files out as they are read */
881 char outfile
[MAX_PATH
];
882 long read
, total
= 0;
888 if (handles
[idx
] > 0) {
890 /* create the output file */
892 rb
->snprintf(outfile
, MAX_PATH
, "/file%d.mp3", idx
);
893 fd
= rb
->open(outfile
, O_CREAT
|O_TRUNC
|O_WRONLY
);
895 DEBUGF("couldn't create file\n");
896 rb
->splash(HZ
, "couldn't create file");
900 /* read as much data as possible */
902 read
= bufgetdata(handles
[idx
], GUARD_SIZE
, &data
);
904 read
= MIN(read
, GUARD_SIZE
);
905 rb
->write(fd
, data
, read
);
907 bufadvance(handles
[idx
], read
);
908 rb
->lcd_clear_display();
909 print_progress(total
, idx
+1, num_files
);
910 print_metadata(meta_handles
[idx
]);
916 if (read
>= 0 && total
>= 0) {
917 /* some data was read */
918 DEBUGF("read %ld bytes from handle %d\n", total
,
922 /* check the return value to determine what exactly happened */
924 DEBUGF("data for handle %d isn't ready\n", handles
[idx
]);
925 } else if (read
== -1) {
926 DEBUGF("couldn't find handle %d\n", handles
[idx
]);
927 } else if (read
== 0) {
928 DEBUGF("finished reading handle %d\n", handles
[idx
]);
929 bufclose(handles
[idx
]);
930 bufclose(meta_handles
[idx
]);
935 /* move on to the next file and check if we've finished */
937 if (idx
>= num_files
) {
948 DEBUGF("removing the codec thread\n");
949 rb
->remove_thread(NULL
);
952 void bufopen_thread(void)
956 while (idx
< num_files
)
958 /* open the metadata file */
959 rb
->snprintf(buf
, MAX_PATH
, "/meta%s.txt", files
[idx
]);
960 meta_handles
[idx
] = bufopen(buf
, 0, TYPE_ID3
);
961 if (meta_handles
[idx
] > 0)
963 /* open the audio file */
964 ret
= bufopen(files
[idx
], 0, TYPE_AUDIO
);
966 handles
[idx
++] = ret
;
968 /* couldn't open the audio file, close the metadata handle */
969 bufclose(meta_handles
[idx
]);
975 DEBUGF("bufopen thread finished\n");
976 rb
->remove_thread(NULL
);
980 /* this is the plugin entry point */
981 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
990 DEBUGF("linked list test failed\n");
991 rb
->splash(HZ
, "linked list test failed");
995 codecthread_id
= rb
->create_thread(codec_thread
,
999 IF_PRIO(,PRIORITY_PLAYBACK
)
1000 IF_COP(, CPU
, false));
1002 bufopenthread_id
= rb
->create_thread(bufopen_thread
,
1004 sizeof(bufopen_stack
),
1006 IF_PRIO(,PRIORITY_BACKGROUND
)
1007 IF_COP(, CPU
, false));
1009 if (!codecthread_id
)
1011 rb
->splash(HZ
, "failed to create codec thread");
1012 return PLUGIN_ERROR
;
1014 else if (!bufopenthread_id
)
1016 rb
->splash(HZ
, "failed to create bufopen thread");
1017 return PLUGIN_ERROR
;
1022 while (!done_playing
)
1024 if (data_rem() > 0 && wasted_space() > buffer_len
/5) {
1025 DEBUGF("there is %ld bytes of wasted space\n", wasted_space());
1027 /* free buffer from outdated audio data */
1028 struct memory_handle
*m
= first_handle
;
1030 if (m
->type
== TYPE_AUDIO
)
1035 /* free buffer by moving metadata */
1038 if (m
->type
!= TYPE_AUDIO
)
1046 if (data_rem() > 0 && BUF_USED
< 3*buffer_len
/4 &&
1049 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
1056 DEBUGF("done playing\n");
1061 DEBUGF("end of plugin\n");