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 struct memory_handle
{
44 int id
; /* A unique ID for the handle */
45 //enum data_type type;
46 //enum data_state state;
49 size_t data
; /* Start index of the handle's data buffer */
50 size_t ridx
; /* Current read pointer, relative to the main buffer */
51 size_t widx
; /* Current write pointer */
52 size_t filesize
; /* File total length */
53 size_t filerem
; /* Remaining bytes of file NOT in buffer */
54 size_t available
; /* Available bytes to read from buffer */
55 size_t offset
; /* Offset at which we started reading the file */
56 struct memory_handle
*next
;
60 static char *guard_buffer
;
62 static size_t buffer_len
;
63 static size_t buf_widx
;
64 static size_t buf_ridx
;
66 static size_t conf_filechunk
;
68 /* current memory handle in the linked list. NULL when the list is empty. */
69 static struct memory_handle
*cur_handle
;
70 /* first memory handle in the linked list. NULL when the list is empty. */
71 static struct memory_handle
*first_handle
;
72 static int num_handles
;
74 static void graph_view(int width
);
77 /* add a new handle to the linked list and return it. It will have become the
79 static struct memory_handle
*add_handle(void)
81 /* this will give each handle a unique id */
82 static int cur_handle_id
= 0;
84 int data_size
= sizeof(struct memory_handle
);
86 /* check that we actually can add the handle and its data */
87 if (RINGBUF_ADD_CROSS(buf_widx
, data_size
, buf_ridx
) >= 0) {
91 struct memory_handle
*new_handle
= (struct memory_handle
*)(buffer
+ buf_widx
);
92 buf_widx
= RINGBUF_ADD(buf_widx
, data_size
);
95 /* the new handle is the first one */
96 first_handle
= new_handle
;
100 cur_handle
->next
= new_handle
;
103 cur_handle
= new_handle
;
104 cur_handle
->id
= cur_handle_id
++;
105 cur_handle
->next
= NULL
;
110 /* delete a given memory handle from the linked list
111 and return true for success. Nothing is actually erased from memory. */
112 static bool rm_handle(struct memory_handle
*h
)
114 if (h
== first_handle
) {
115 first_handle
= h
->next
;
116 if (h
== cur_handle
) {
117 rb
->logf("removing the first and last handle\n");
121 buf_ridx
= (void *)first_handle
- (void *)buffer
;
124 struct memory_handle
*m
= first_handle
;
125 while (m
&& m
->next
!= h
) {
128 if (h
&& m
&& m
->next
== h
) {
130 if (h
== cur_handle
) {
142 /* these are unfortunalty needed to be global
143 so move_handle can invalidate them */
144 static int cached_handle_id
= -1;
145 static struct memory_handle
*cached_handle
= NULL
;
147 /* Return a pointer to the memory handle of given ID.
148 NULL if the handle wasn't found */
149 static struct memory_handle
*find_handle(int handle_id
)
151 /* simple caching because most of the time the requested handle
152 will either be the same as the last, or the one after the last */
155 if (cached_handle_id
== handle_id
&& cached_handle_id
== cached_handle
->id
)
156 return cached_handle
;
157 else if (cached_handle
->next
&& (cached_handle
->next
->id
== handle_id
))
159 /* JD's quick testing showd this block was only entered
160 2/1971 calls to find_handle.
161 8/1971 calls to find_handle resulted in a cache miss */
162 cached_handle
= cached_handle
->next
;
163 cached_handle_id
= handle_id
;
164 return cached_handle
;
168 struct memory_handle
*m
= first_handle
;
169 while (m
&& m
->id
!= handle_id
) {
172 cached_handle_id
= handle_id
;
174 return (m
&& m
->id
== handle_id
) ? m
: NULL
;
177 /* Move a memory handle to newpos.
178 Return a pointer to the new location of the handle */
179 static struct memory_handle
*move_handle(size_t newpos
, struct memory_handle
*h
)
181 struct memory_handle
*dest
= (struct memory_handle
*)(buffer
+ newpos
);
183 /* Invalidate the cache to prevent it from keeping the old location of h */
184 if (h
== cached_handle
)
185 cached_handle
= NULL
;
187 /* the cur_handle pointer might need updating */
188 if (h
== cur_handle
) {
192 if (h
== first_handle
) {
196 struct memory_handle
*m
= first_handle
;
197 while (m
&& m
->next
!= h
) {
200 if (h
&& m
&& m
->next
== h
) {
206 rb
->memmove(dest
, h
, sizeof(struct memory_handle
));
209 /* Buffer data for the given handle. Return the amount of data buffered
210 or -1 if the handle wasn't found */
211 static int buffer_handle(int handle_id
)
213 rb
->logf("buffer_handle(%d)", handle_id
);
214 struct memory_handle
*h
= find_handle(handle_id
);
218 if (h
->filerem
== 0) {
219 /* nothing left to buffer */
223 if (h
->fd
< 0) /* file closed, reopen */
226 h
->fd
= rb
->open(h
->path
, O_RDONLY
);
234 rb
->lseek(h
->fd
, h
->offset
, SEEK_SET
);
238 while (h
->filerem
> 0)
240 //rb->logf("h: %d\n", (void *)h - (void *)buffer);
241 //rb->logf("buf_widx: %ld\n", (long)buf_widx);
242 /* max amount to copy */
243 size_t copy_n
= MIN(conf_filechunk
, buffer_len
- buf_widx
);
245 /* stop copying if it would overwrite the reading position */
246 if (RINGBUF_ADD_CROSS(buf_widx
, copy_n
, buf_ridx
) >= 0)
249 /* rc is the actual amount read */
250 int rc
= rb
->read(h
->fd
, &buffer
[buf_widx
], copy_n
);
254 //rb->logf("failed on fd %d at buf_widx = %ld for handle %d\n", h->fd, (long)buf_widx, h->id);
255 rb
->logf("File ended %ld bytes early\n", (long)h
->filerem
);
256 h
->filesize
-= h
->filerem
;
262 h
->widx
= RINGBUF_ADD(h
->widx
, rc
);
270 if (h
->filerem
== 0) {
271 /* finished buffering the file */
275 rb
->logf("buffered %d bytes (%d of %d available, remaining: %d)\n",
276 ret
, h
->available
, h
->filesize
, h
->filerem
);
280 /* Free buffer space by moving the first handle struct right before the useful
281 part of its data buffer */
282 static void free_buffer(int handle_id
)
284 rb
->logf("free_buffer(%d)\n", handle_id
);
285 struct memory_handle
*h
= find_handle(handle_id
);
289 size_t delta
= RINGBUF_SUB(h
->ridx
, h
->data
);
290 size_t dest
= RINGBUF_ADD((void *)h
- (void *)buffer
, delta
);
291 //rb->logf("buf_ridx: %ld, buf_widx: %ld\n", (long)buf_ridx, (long)buf_widx);
292 //rb->logf("dest: %ld, delta: %ld\n", (long)dest, (long)delta);
293 h
= move_handle(dest
, h
);
294 h
->data
= RINGBUF_ADD(h
->data
, delta
);
296 h
->available
-= delta
;
300 /* Request a file be buffered
301 filename: name of the file t open
302 offset: starting offset to buffer from the file
303 RETURNS: <0 if the file cannot be opened, or one file already
304 queued to be opened, otherwise the handle for the file in the buffer
306 int bufopen(char *file
, size_t offset
)
308 /* add the file to the buffering queue. */
309 /* for now, we'll assume the queue is always empty, so the handle
310 gets added immediately */
312 rb
->logf("bufopen: %s (offset: %d)\n", file
, offset
);
314 int fd
= rb
->open(file
, O_RDONLY
);
319 rb
->lseek(fd
, offset
, SEEK_SET
);
321 struct memory_handle
*h
= add_handle();
324 rb
->strncpy(h
->path
, file
, MAX_PATH
);
326 h
->filesize
= rb
->filesize(fd
);
327 h
->filerem
= h
->filesize
- offset
;
334 rb
->logf("added handle : %d\n", h
->id
);
338 /* Close the handle. Return 0 for success and < 0 for failure */
339 int bufclose(int handle_id
)
341 rb
->logf("bufclose(%d)\n", handle_id
);
342 struct memory_handle
*h
= find_handle(handle_id
);
350 /* Set the reading index in a handle (relatively to the start of the handle data).
351 Return 0 for success and < 0 for failure */
352 int bufseek(int handle_id
, size_t offset
)
354 struct memory_handle
*h
= find_handle(handle_id
);
358 if (offset
> h
->available
)
361 h
->ridx
= RINGBUF_ADD(h
->data
, offset
);
365 /* Advance the reading index in a handle (relatively to its current position).
366 Return 0 for success and < 0 for failure */
367 int bufadvance(int handle_id
, ssize_t offset
)
369 struct memory_handle
*h
= find_handle(handle_id
);
375 if (offset
> h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
))
378 h
->ridx
= RINGBUF_ADD(h
->ridx
, offset
);
382 if (-offset
> RINGBUF_SUB(h
->ridx
, h
->data
))
385 h
->ridx
= RINGBUF_SUB(h
->ridx
, -offset
);
391 /* Copy data from the given handle to the dest buffer.
392 Return the number of bytes copied or -1 for failure. */
393 int bufread(int handle_id
, size_t size
, char *dest
)
395 struct memory_handle
*h
= find_handle(handle_id
);
396 size_t buffered_data
;
399 if (h
->available
== 0)
401 buffered_data
= MIN(size
, h
->available
);
403 if (h
->ridx
+ buffered_data
> buffer_len
)
405 size_t read
= buffer_len
- h
->ridx
;
406 rb
->memcpy(dest
, &buffer
[h
->ridx
], read
);
407 rb
->memcpy(dest
+read
, buffer
, buffered_data
- read
);
409 else rb
->memcpy(dest
, &buffer
[h
->ridx
], buffered_data
);
411 h
->ridx
= RINGBUF_ADD(h
->ridx
, buffered_data
);
412 h
->available
-= buffered_data
;
413 return buffered_data
;
416 /* Update the "data" pointer to make the handle's data available to the caller.
417 Return the length of the available linear data or -1 for failure. */
418 long bufgetdata(int handle_id
, size_t size
, unsigned char **data
)
420 struct memory_handle
*h
= find_handle(handle_id
);
426 if (h
->ridx
+ size
> buffer_len
&&
427 h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) >= size
)
429 /* use the guard buffer to provide what was requested. */
430 int copy_n
= h
->ridx
+ size
- buffer_len
;
431 rb
->memcpy(guard_buffer
, (unsigned char *)buffer
, copy_n
);
436 ret
= MIN(h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
),
437 buffer_len
- h
->ridx
);
440 *data
= (unsigned char *)(buffer
+ h
->ridx
);
442 //rb->logf("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);
448 struct memory_handle
*m1
, *m2
, *m3
, *m4
;
450 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
455 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
460 if (cur_handle
!= m2
|| first_handle
!= m1
|| m1
->next
!= m2
|| m2
->next
!= NULL
)
465 if (cur_handle
!= m3
|| first_handle
!= m1
|| m2
->next
!= m3
|| m3
->next
!= NULL
)
470 if (cur_handle
!= m3
|| first_handle
!= m1
|| m1
->next
!= m3
)
475 if (cur_handle
!= m1
|| first_handle
!= m1
|| m1
->next
!= NULL
)
480 if (cur_handle
!= m4
|| first_handle
!= m1
|| m1
->next
!= m4
|| m4
->next
!= NULL
)
485 if (cur_handle
!= m4
|| first_handle
!= m4
)
490 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
498 if (cur_handle
!= m4
|| first_handle
!= m1
)
502 m2 = move_handle(m2->data + 1024*1024, m2);
504 if (cur_handle != m4 || first_handle != m1 || m1->next != m2 || m2->next != m3 ||
505 find_handle(m2id) != m2)
509 m1 = move_handle(m1->data + 1024*1024*3, m1);
511 if (cur_handle != m4 || first_handle != m1 || m1->next != m2 ||
512 find_handle(m1id) != m1)
520 if (cur_handle
!= NULL
|| first_handle
!= NULL
)
527 static void list_handles(void)
529 struct memory_handle
*m
= first_handle
;
531 rb
->logf("%02d - %d\n", m
->id
, (void *)m
-(void *)buffer
);
537 /* display a nice graphical view of the ringbuffer. */
538 static void graph_view(int width
)
541 r_pos
= buf_ridx
* width
/ buffer_len
;
542 w_pos
= buf_widx
* width
/ buffer_len
;
545 for (i
=0; i
<= width
; i
++)
547 if (i
!= r_pos
&& i
!= w_pos
)
549 if (buf_ridx
<= buf_widx
)
551 if (i
> r_pos
&& i
< w_pos
) {
559 if (i
> r_pos
|| i
< w_pos
) {
568 if (i
== r_pos
&& i
== w_pos
)
570 if (buf_ridx
<= buf_widx
) {
575 } else if (i
== r_pos
) {
577 } else if (i
== w_pos
) {
586 bool buffer_init(void)
588 buffer
= rb
->plugin_get_audio_buffer(&buffer_len
);
591 rb
->logf("couldn't allocate buffer\n");
594 buffer_len
-= GUARD_SIZE
;
595 guard_buffer
= buffer
+ buffer_len
;
603 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
608 /* returns true if the file still has some on disk unread */
609 bool handle_has_data(int handle
)
611 struct memory_handle
*m
= find_handle(handle
);
614 return m
->filerem
!= 0;
619 bool need_rebuffer(void)
622 wasted
= first_handle
? RINGBUF_SUB(first_handle
->ridx
, first_handle
->data
) : 0;
623 while (wasted
> buffer_len
/ 2)
625 free_buffer(first_handle
->id
);
626 wasted
= first_handle
? RINGBUF_SUB(first_handle
->ridx
, first_handle
->data
) : 0;
628 free
= buffer_len
- BUF_USED
;
629 return ((free
>= buffer_len
/4));
632 bool disk_is_spinning(void)
637 #define MAX_HANDLES 64
639 /* this is the plugin entry point */
640 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
646 char *argv
[] = { NULL
,
647 "/070623 - David Vendetta.mp3",
648 "/africanism all stars feat the hard boys - hard (bob sinclair remix).mp3",
649 "/alan_braxe__kris_menace_-_lumberjack.mp3",
650 "/Ame - Rej (A Hundred Birds Remix).mp3",
651 "/Antena - Camino del Sol (Joakim Remix).mp3" };
654 int last_handle
= -1;
655 int handle_order
[MAX_HANDLES
];
656 int reading_handle
= 0;
657 bool done_buffering
= false, done_playing
= false;
658 //char read_buffer[GUARD_SIZE];
660 int fd
= -1; /* used to write the files out as they are read */
661 int current_handle
= -1;
662 struct memory_handle
*m
= NULL
;
667 rb
->logf("linked list test failed\n");
668 rb
->splash(HZ
, "linked list test failed");
676 while (!done_buffering
|| !done_playing
)
678 rb
->logf("buffer usage: %d handles_used: %d\n", BUF_USED
, num_handles
);
681 /* "Buffering thread" section */
682 if (!done_buffering
&& need_rebuffer() && disk_is_spinning())
684 m
= find_handle(current_handle
);
685 if ( !m
|| ((m
->filerem
== 0) && (m
->next
== NULL
)))
687 int h
= bufopen(argv
[next_file
], 0);
692 //rb->logf("new handle %d\n",h);
694 handle_order
[last_handle
] = h
;
695 buffer_handle(m
->id
);
708 current_handle
= m
?m
->id
:-1;
712 rb
->logf("buffering handle %d\n",m
->id
);
713 buffer_handle(m
->id
);
717 if (next_file
== argc
&& m
->filerem
== 0)
718 done_buffering
= true;
720 /* "Playback thread" section */
723 rb
->logf("reading handle: %d\n", handle_order
[reading_handle
]);
727 if (reading_handle
>= last_handle
728 && !handle_has_data(handle_order
[reading_handle
]))
733 rb
->snprintf(file
, MAX_PATH
, "/file%d.mp3", reading_handle
);
734 fd
= rb
->open(file
, O_CREAT
|O_TRUNC
|O_WRONLY
);
737 rb
->logf("ERROROROROR\n");
738 rb
->splash(HZ
, "couldn't create file");
744 //read = bufread(handle_order[reading_handle], GUARD_SIZE,read_buffer);
745 //write(fd, read_buffer, read);
746 read
= bufgetdata(handle_order
[reading_handle
], GUARD_SIZE
, &data
);
747 read
= MIN(read
, GUARD_SIZE
);
748 rb
->write(fd
, data
, read
);
750 bufadvance(handle_order
[reading_handle
], read
);
754 rb
->logf("read %ld bytes from handle %d\n", total
, handle_order
[reading_handle
]);
756 /* close the fd/handle if there is no more data or an error */
757 if (read
< 0 || handle_has_data(handle_order
[reading_handle
]) == false)
759 rb
->logf("finished reading %d\n",handle_order
[reading_handle
]);
760 bufclose(handle_order
[reading_handle
]);
767 rb
->logf("there is data left to buffer for %d\n", handle_order
[reading_handle
]);
772 rb
->logf("buffer usage: %d handles_used: %d\n", BUF_USED
,num_handles
);