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 struct memory_handle
{
56 int id
; /* A unique ID for the handle */
57 //enum data_type type;
58 //enum data_state state;
61 size_t data
; /* Start index of the handle's data buffer */
62 size_t data_len
; /* Length of the data buffer for the handle */
63 size_t ridx
; /* Current read pointer, relative to the main buffer */
64 size_t widx
; /* Current write pointer */
65 size_t filesize
; /* File total length */
66 size_t filerem
; /* Remaining bytes of file NOT in buffer */
67 size_t available
; /* Available bytes to read from buffer */
68 size_t offset
; /* Offset at which we started reading the file */
69 struct memory_handle
*next
;
74 static char *guard_buffer
;
76 static size_t buffer_len
;
77 static size_t buf_widx
;
78 static size_t buf_ridx
;
80 static size_t conf_filechunk
;
82 /* current memory handle in the linked list. NULL when the list is empty. */
83 static struct memory_handle
*cur_handle
;
84 /* first memory handle in the linked list. NULL when the list is empty. */
85 static struct memory_handle
*first_handle
;
86 static int num_handles
;
88 static void graph_view(int width
);
91 /* add a new handle to the linked list and return it. It will have become the
92 new current handle. The handle will reserve "data_size" bytes or if that's
93 not possible, decrease "data_size" to allow adding the handle. */
94 static struct memory_handle
*add_handle(size_t *data_size
)
96 /* this will give each handle a unique id */
97 static int cur_handle_id
= 1;
99 size_t len
= (data_size
? *data_size
: 0)
100 + sizeof(struct memory_handle
);
102 /* check that we actually can add the handle and its data */
103 int overlap
= RINGBUF_ADD_CROSS(buf_widx
, len
+ 3, buf_ridx
);
105 *data_size
-= overlap
;
108 if (len
< sizeof(struct memory_handle
)) {
112 /* make sure buf_widx is 32-bit aligned so that the handle struct is. */
113 buf_widx
= (RINGBUF_ADD(buf_widx
, 3)) & ~3;
115 struct memory_handle
*new_handle
= (struct memory_handle
*)(&buffer
[buf_widx
]);
117 /* only advance the buffer write index of the size of the struct */
118 buf_widx
= RINGBUF_ADD(buf_widx
, sizeof(struct memory_handle
));
121 /* the new handle is the first one */
122 first_handle
= new_handle
;
126 cur_handle
->next
= new_handle
;
129 cur_handle
= new_handle
;
130 cur_handle
->id
= cur_handle_id
++;
131 cur_handle
->next
= NULL
;
136 /* delete a given memory handle from the linked list
137 and return true for success. Nothing is actually erased from memory. */
138 static bool rm_handle(struct memory_handle
*h
)
140 if (h
== first_handle
) {
141 first_handle
= h
->next
;
142 if (h
== cur_handle
) {
143 DEBUGF("removing the first and last handle\n");
144 /* h was the first and last handle */
148 buf_ridx
= (void *)first_handle
- (void *)buffer
;
151 struct memory_handle
*m
= first_handle
;
152 while (m
&& m
->next
!= h
) {
155 if (h
&& m
&& m
->next
== h
) {
157 if (h
== cur_handle
) {
169 /* these are unfortunalty needed to be global
170 so move_handle can invalidate them */
171 static int cached_handle_id
= -1;
172 static struct memory_handle
*cached_handle
= NULL
;
174 /* Return a pointer to the memory handle of given ID.
175 NULL if the handle wasn't found */
176 static struct memory_handle
*find_handle(int handle_id
)
178 /* simple caching because most of the time the requested handle
179 will either be the same as the last, or the one after the last */
182 if (cached_handle_id
== handle_id
&& cached_handle_id
== cached_handle
->id
)
183 return cached_handle
;
184 else if (cached_handle
->next
&& (cached_handle
->next
->id
== handle_id
))
186 /* JD's quick testing showd this block was only entered
187 2/1971 calls to find_handle.
188 8/1971 calls to find_handle resulted in a cache miss */
189 cached_handle
= cached_handle
->next
;
190 cached_handle_id
= handle_id
;
191 return cached_handle
;
195 struct memory_handle
*m
= first_handle
;
196 while (m
&& m
->id
!= handle_id
) {
199 cached_handle_id
= handle_id
;
201 return (m
&& m
->id
== handle_id
) ? m
: NULL
;
204 /* Move a memory handle to newpos.
205 Return a pointer to the new location of the handle */
206 static struct memory_handle
*move_handle(size_t *delta
, struct memory_handle
*h
)
208 /* make sure delta is 32-bit aligned so that the handle struct is. */
209 *delta
= (RINGBUF_ADD(*delta
, 3)) & ~3;
211 size_t newpos
= RINGBUF_ADD((void *)h
- (void *)buffer
, *delta
);
213 DEBUGF("move_handle\n");
214 struct memory_handle
*dest
= (struct memory_handle
*)(&buffer
[newpos
]);
216 /* Invalidate the cache to prevent it from keeping the old location of h */
217 if (h
== cached_handle
)
218 cached_handle
= NULL
;
220 /* the cur_handle pointer might need updating */
221 if (h
== cur_handle
) {
225 if (h
== first_handle
) {
229 struct memory_handle
*m
= first_handle
;
230 while (m
&& m
->next
!= h
) {
233 if (h
&& m
&& m
->next
== h
) {
240 DEBUGF("h: %lx", (long)h);
241 DEBUGF("h->id: %d", h->id);
242 DEBUGF("dest: %lx", (long)dest);
243 DEBUGF("dest->id: %d", dest->id);
246 rb
->memmove(dest
, h
, sizeof(struct memory_handle
));
248 DEBUGF("h: %lx", (long)h);
249 DEBUGF("dest: %lx", (long)dest);
250 DEBUGF("dest->id: %d", dest->id);
254 /* Buffer data for the given handle. Return the amount of data buffered
255 or -1 if the handle wasn't found */
256 static ssize_t
buffer_handle(int handle_id
)
258 DEBUGF("buffer_handle(%d)\n", handle_id
);
259 struct memory_handle
*h
= find_handle(handle_id
);
263 if (h
->filerem
== 0) {
264 /* nothing left to buffer */
268 if (h
->fd
< 0) /* file closed, reopen */
271 h
->fd
= rb
->open(h
->path
, O_RDONLY
);
279 rb
->lseek(h
->fd
, h
->offset
, SEEK_SET
);
283 while (h
->filerem
> 0)
285 //DEBUGF("h: %d\n", (void *)h - (void *)buffer);
286 //DEBUGF("buf_widx: %ld\n", (long)buf_widx);
287 /* max amount to copy */
288 size_t copy_n
= MIN(conf_filechunk
, buffer_len
- buf_widx
);
290 /* stop copying if it would overwrite the reading position */
291 if (RINGBUF_ADD_CROSS(buf_widx
, copy_n
, buf_ridx
) >= 0)
294 /* rc is the actual amount read */
295 int rc
= rb
->read(h
->fd
, &buffer
[buf_widx
], copy_n
);
299 //DEBUGF("failed on fd %d at buf_widx = %ld for handle %d\n", h->fd, (long)buf_widx, h->id);
300 DEBUGF("File ended %ld bytes early\n", (long)h
->filerem
);
301 h
->filesize
-= h
->filerem
;
307 h
->widx
= RINGBUF_ADD(h
->widx
, rc
);
315 if (h
->filerem
== 0) {
316 /* finished buffering the file */
320 DEBUGF("buffered %ld bytes (%ld of %ld available, remaining: %ld)\n",
321 ret
, h
->available
, h
->filesize
, h
->filerem
);
328 /* Free buffer space by moving the handle struct right before the useful
329 part of its data buffer */
330 static void free_buffer(int handle_id
)
332 DEBUGF("free_buffer(%d)\n", handle_id
);
333 struct memory_handle
*h
= find_handle(handle_id
);
337 size_t delta
= RINGBUF_SUB(h
->ridx
, h
->data
);
338 h
= move_handle(&delta
, h
);
339 /* The value of delta might change for alignment reasons */
340 h
->data
= RINGBUF_ADD(h
->data
, delta
);
342 h
->available
-= delta
;
347 static void fill_buffer(void)
349 DEBUGF("fill buffer()\n");
350 struct memory_handle
*m
= first_handle
;
352 if (m
->filerem
> 0) {
353 buffer_handle(first_handle
->id
);
360 static size_t data_rem(void)
364 struct memory_handle
*m
= first_handle
;
373 static size_t wasted_space(void)
377 struct memory_handle
*m
= first_handle
;
379 ret
+= RINGBUF_SUB(m
->ridx
, m
->data
);
386 /* Request a file be buffered
387 filename: name of the file t open
388 offset: starting offset to buffer from the file
389 RETURNS: <0 if the file cannot be opened, or one file already
390 queued to be opened, otherwise the handle for the file in the buffer
392 int bufopen(char *file
, size_t offset
)
394 DEBUGF("bufopen: %s (offset: %ld)\n", file
, offset
);
396 int fd
= rb
->open(file
, O_RDONLY
);
401 rb
->lseek(fd
, offset
, SEEK_SET
);
403 size_t size
= rb
->filesize(fd
) - offset
;
404 struct memory_handle
*h
= add_handle(&size
);
407 DEBUGF("failed to add handle\n");
411 rb
->strncpy(h
->path
, file
, MAX_PATH
);
413 h
->filesize
= rb
->filesize(fd
);
414 h
->filerem
= h
->filesize
- offset
;
422 DEBUGF("added handle : %d\n", h
->id
);
426 /* Close the handle. Return 0 for success and < 0 for failure */
427 int bufclose(int handle_id
)
429 DEBUGF("bufclose(%d)\n", handle_id
);
430 struct memory_handle
*h
= find_handle(handle_id
);
438 /* Set the reading index in a handle (relatively to the start of the handle data).
439 Return 0 for success and < 0 for failure */
440 int bufseek(int handle_id
, size_t offset
)
442 struct memory_handle
*h
= find_handle(handle_id
);
446 if (offset
> h
->available
)
449 h
->ridx
= RINGBUF_ADD(h
->data
, offset
);
453 /* Advance the reading index in a handle (relatively to its current position).
454 Return 0 for success and < 0 for failure */
455 int bufadvance(int handle_id
, off_t offset
)
457 struct memory_handle
*h
= find_handle(handle_id
);
463 /* check for access beyond what's available */
464 if ((size_t)offset
> (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
)))
467 h
->ridx
= RINGBUF_ADD(h
->ridx
, offset
);
471 /* check for access before what's available */
472 if ((size_t)(-offset
) > RINGBUF_SUB(h
->ridx
, h
->data
))
475 h
->ridx
= RINGBUF_SUB(h
->ridx
, (size_t)(-offset
));
481 /* Copy data from the given handle to the dest buffer.
482 Return the number of bytes copied or < 0 for failure. */
483 ssize_t
bufread(int handle_id
, size_t size
, char *dest
)
485 struct memory_handle
*h
= find_handle(handle_id
);
486 size_t buffered_data
;
490 if (h
->available
== 0 && h
->filerem
> 0)
493 if (h
->available
== 0 && h
->filerem
== 0)
496 buffered_data
= MIN(size
, h
->available
);
498 if (h
->ridx
+ buffered_data
> buffer_len
)
500 size_t read
= buffer_len
- h
->ridx
;
501 rb
->memcpy(dest
, &buffer
[h
->ridx
], read
);
502 rb
->memcpy(dest
+read
, buffer
, buffered_data
- read
);
504 else rb
->memcpy(dest
, &buffer
[h
->ridx
], buffered_data
);
506 h
->ridx
= RINGBUF_ADD(h
->ridx
, buffered_data
);
507 h
->available
-= buffered_data
;
508 return buffered_data
;
511 /* Update the "data" pointer to make the handle's data available to the caller.
512 Return the length of the available linear data or < 0 for failure. */
513 ssize_t
bufgetdata(int handle_id
, size_t size
, unsigned char **data
)
515 struct memory_handle
*h
= find_handle(handle_id
);
519 if (h
->available
== 0 && h
->filerem
> 0)
522 if (h
->available
== 0 && h
->filerem
== 0)
527 if (h
->ridx
+ size
> buffer_len
&&
528 h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) >= size
)
530 /* use the guard buffer to provide what was requested. */
531 size_t copy_n
= h
->ridx
+ size
- buffer_len
;
532 rb
->memcpy(guard_buffer
, (unsigned char *)buffer
, copy_n
);
537 ret
= MIN(h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
),
538 buffer_len
- h
->ridx
);
541 *data
= (unsigned char *)&buffer
[h
->ridx
];
543 //DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);
549 struct memory_handle
*m1
, *m2
, *m3
, *m4
;
551 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
554 m1
= add_handle(NULL
);
556 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
559 m2
= add_handle(NULL
);
561 if (cur_handle
!= m2
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= NULL
)
564 m3
= add_handle(NULL
);
566 if (cur_handle
!= m3
|| first_handle
!= m1
|| m2
->next
!= m3
|| m3
->next
!= NULL
)
571 if (cur_handle
!= m3
|| first_handle
!= m1
|| m1
->next
!= m3
)
576 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
579 m4
= add_handle(NULL
);
581 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m4
|| m4
->next
!= NULL
)
586 if (cur_handle
!= m4
|| first_handle
!= m4
)
591 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
594 m1
= add_handle(NULL
);
595 m2
= add_handle(NULL
);
596 m3
= add_handle(NULL
);
597 m4
= add_handle(NULL
);
599 if (cur_handle
!= m4
|| first_handle
!= m1
)
603 m2
= move_handle(1024*100, m2
);
605 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= m3
)
608 m1
= move_handle(1024*100*3, m1
);
610 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m2
)
619 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
625 /* display a nice graphical view of the ringbuffer. */
626 static void graph_view(int width
)
628 #ifndef ROCKBOX_HAS_LOGF
630 r_pos
= buf_ridx
* width
/ buffer_len
;
631 w_pos
= buf_widx
* width
/ buffer_len
;
634 for (i
=0; i
<= width
; i
++)
636 if (i
!= r_pos
&& i
!= w_pos
)
638 if (buf_ridx
<= buf_widx
)
640 if (i
> r_pos
&& i
< w_pos
) {
648 if (i
> r_pos
|| i
< w_pos
) {
657 if (i
== r_pos
&& i
== w_pos
)
659 if (buf_ridx
<= buf_widx
) {
664 } else if (i
== r_pos
) {
666 } else if (i
== w_pos
) {
678 bool buffer_init(void)
680 buffer
= rb
->plugin_get_audio_buffer(&buffer_len
);
683 DEBUGF("couldn't allocate buffer\n");
686 buffer_len
-= GUARD_SIZE
;
687 guard_buffer
= buffer
+ buffer_len
;
695 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
700 bool disk_is_spinning(void)
706 static long playback_stack
[4*DEFAULT_STACK_SIZE
/sizeof(long)];
707 static struct thread_entry
* playbackthread_id
;
709 bool done_playing
= false;
711 #define MAX_HANDLES 16
713 void playback_thread(void)
716 int handles
[MAX_HANDLES
];
718 int fd
= -1; /* used to write the files out as they are read */
720 char outfile
[MAX_PATH
];
721 long read
, total
= 0;
727 if (handles
[idx
] <= 0) {
728 handles
[idx
] = bufopen(files
[idx
], 0);
733 rb
->snprintf(outfile
, MAX_PATH
, "/file%d.mp3", idx
);
734 fd
= rb
->open(outfile
, O_CREAT
|O_TRUNC
|O_WRONLY
);
736 DEBUGF("couldn't create file\n");
737 rb
->splash(HZ
, "couldn't create file");
742 read
= bufgetdata(handles
[idx
], GUARD_SIZE
, &data
);
744 read
= MIN(read
, GUARD_SIZE
);
745 rb
->write(fd
, data
, read
);
747 bufadvance(handles
[idx
], read
);
752 if (read
>= 0 && total
>= 0) {
753 DEBUGF("read %ld bytes from handle %d\n", total
, handles
[idx
]);
757 if (idx
< num_files
-1 && handles
[idx
+1] <= 0) {
758 handles
[idx
+1] = bufopen(files
[idx
+1], 0);
763 DEBUGF("data for handle %d isn't ready\n", handles
[idx
]);
764 } else if (read
== -1) {
765 DEBUGF("couldn't find handle %d\n", handles
[idx
]);
766 } else if (read
== 0) {
767 DEBUGF("finished reading handle %d\n", handles
[idx
]);
768 bufclose(handles
[idx
]);
773 if (idx
>= num_files
) {
784 DEBUGF("removing the playback thread\n");
785 rb
->remove_thread(NULL
);
789 /* this is the plugin entry point */
790 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
799 DEBUGF("linked list test failed\n");
800 rb
->splash(HZ
, "linked list test failed");
804 playbackthread_id
= rb
->create_thread(playback_thread
,
806 sizeof(playback_stack
),
808 IF_PRIO(,PRIORITY_PLAYBACK
)
809 IF_COP(, CPU
, false));
811 if (!playbackthread_id
)
813 rb
->splash(HZ
, "failed to create playback thread");
819 while (!done_playing
)
821 if (wasted_space() > buffer_len
/4) {
822 DEBUGF("there is %ld bytes of wasted space\n", wasted_space());
823 struct memory_handle
*m
= first_handle
;
830 if (data_rem() > 0 && BUF_USED
< buffer_len
/4 && disk_is_spinning()) {
831 DEBUGF("%ld bytes left to buffer and the buffer is running low\n", data_rem());
837 DEBUGF("done playing\n");
842 DEBUGF("end of plugin\n");