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 #include "buffering.h"
28 /* Rockbox constants */
30 /* amount of data to read in one read() call */
31 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
34 #define BUFFER_SIZE (32*1024*1024)
35 #define GUARD_SIZE (32*1024)
38 /* Ring buffer helper macros */
39 /* Buffer pointer (p) plus value (v), wrapped if necessary */
40 #define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
41 /* Buffer pointer (p) minus value (v), wrapped if necessary */
42 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
43 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
44 #define RINGBUF_ADD_CROSS(p1,v,p2) \
45 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
46 /* Bytes available in the buffer */
47 #define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
50 #define MIN(a, b) (((a)<(b))?(a):(b))
54 static size_t buffer_len
;
56 static char *buffer_end
;
58 static size_t conf_filechunk
;
60 static size_t buf_widx
;
61 static size_t buf_ridx
;
63 /* current memory handle in the linked list. NULL when the list is empty. */
64 static struct memory_handle
*cur_handle
;
65 /* first memory handle in the linked list. NULL when the list is empty. */
66 static struct memory_handle
*first_handle
;
67 static int num_handles
;
70 /* add a new handle to the linked list and return it. It will have become the
72 static struct memory_handle
*add_handle(void)
74 /* this will give each handle a unique id */
75 static int cur_handle_id
= 0;
77 int data_size
= sizeof(struct memory_handle
) /*
78 + 1024*1024 - sizeof(struct memory_handle) */;
80 /* check that we actually can add the handle and its data */
81 if (RINGBUF_ADD_CROSS(buf_widx
, data_size
, buf_ridx
) >= 0) {
85 struct memory_handle
*new_handle
= (struct memory_handle
*)(buffer
+ buf_widx
);
86 buf_widx
= RINGBUF_ADD(buf_widx
, data_size
);
89 /* the new handle is the first one */
90 first_handle
= new_handle
;
94 cur_handle
->next
= new_handle
;
97 cur_handle
= new_handle
;
98 cur_handle
->id
= cur_handle_id
++;
103 /* delete a given memory handle from the linked list
104 and return true for success. Nothing is actually erased from memory. */
105 static bool rm_handle(struct memory_handle
*h
)
107 if (h
== first_handle
) {
108 first_handle
= h
->next
;
110 struct memory_handle
*m
= first_handle
;
111 while (m
&& m
->next
!= h
) {
114 if (h
&& m
&& m
->next
== h
) {
124 /* Return a pointer to the memory handle of given ID.
125 NULL if the handle wasn't found */
126 static struct memory_handle
*find_handle(int handle_id
)
128 static int last_handle_id
= -1;
129 static struct memory_handle
*last_m
= NULL
;
130 struct memory_handle
*m
= first_handle
;
131 /* simple cacheing because most of the time the requested handle
132 will either be the same as the last, or the one after the last */
135 if (last_handle_id
== handle_id
)
137 else if (last_m
->next
&& (last_m
->next
->id
== handle_id
))
139 last_m
= last_m
->next
;
140 last_handle_id
= handle_id
;
144 while (m
&& m
->id
!= handle_id
) {
147 last_handle_id
= handle_id
;
149 return (m
&& m
->id
== handle_id
) ? m
: NULL
;
152 /* Buffer data for the given handle. Return the amount of data buffered
153 or -1 if the handle wasn't found */
154 static int buffer_handle(int handle_id
)
156 struct memory_handle
*h
= find_handle(handle_id
);
157 //printf("find_handle %d:\nid: %d\npath: %s\n\n", handle_id, h->id, h->path);
161 if (h
->filerem
== 0) {
162 /* nothing left to buffer */
166 if (h
->fd
< 0) /* file closed, reopen */
169 h
->fd
= open(h
->path
, O_RDONLY
);
177 lseek(h
->fd
, h
->offset
, SEEK_SET
);
181 while (h
->filerem
> 0)
183 /* max amount to copy */
184 size_t copy_n
= MIN(conf_filechunk
, buffer_len
- buf_widx
);
186 if (RINGBUF_ADD_CROSS(buf_widx
, copy_n
, buf_ridx
) >= 0)
189 /* rc is the actual amount read */
190 int rc
= read(h
->fd
, &buffer
[buf_widx
], copy_n
);
194 printf("File ended %ldB early", h
->filerem
);
195 h
->filesize
-= h
->filerem
;
201 buf_widx
= RINGBUF_ADD(buf_widx
, rc
);
207 if (h
->filerem
== 0) {
208 /* finished buffering the file */
212 printf("buffered %d bytes (%d of %d available, remaining: %d)\n",
213 ret
, h
->available
, h
->filesize
, h
->filerem
);
217 /* Request a file be buffered
218 filename: name of the file t open
219 offset: starting offset to buffer from the file
220 RETURNS: <0 if the file cannot be opened, or one file already
221 queued to be opened, otherwise the handle for the file in the buffer
223 int bufopen(char *file
, size_t offset
)
225 /* add the file to the buffering queue. */
226 /* for now, we'll assume the queue is always empty, so the handle
227 gets added immediately */
229 printf("bufopen: %s (offset: %d)\n", file
, offset
);
231 int fd
= open(file
, O_RDONLY
);
236 lseek(fd
, offset
, SEEK_SET
);
238 struct memory_handle
*h
= add_handle();
241 strncpy(h
->path
, file
, MAX_PATH
);
243 h
->filesize
= filesize(fd
);
244 h
->filerem
= h
->filesize
- offset
;
246 h
->buf_idx
= buf_widx
;
251 printf("added handle : %d\n", h
->id
);
255 /* Close the handle. Return 0 for success and < 0 for failure */
256 int bufclose(int handle_id
)
258 printf("bufclose: %d\n", handle_id
);
259 struct memory_handle
*h
= find_handle(handle_id
);
263 /* when we close the first handle, we can reclaim the space from its buffer */
264 if (h
== first_handle
) {
265 buf_ridx
= h
->buf_idx
+ h
->available
;
266 /* is this right in all cases ? */
269 return rm_handle(h
) ? 0 : -1;
272 /* Seek in a handle. Return 0 for success and < 0 for failure */
273 int bufseek(int handle_id
, size_t offset
)
275 struct memory_handle
*h
= find_handle(handle_id
);
279 h
->buf_idx
= RINGBUF_ADD(h
->data
, offset
);
283 int bufread(int handle_id
, size_t size
, char *dest
)
285 struct memory_handle
*h
= find_handle(handle_id
);
286 size_t buffered_data
;
289 if (h
->available
== 0)
291 buffered_data
= MIN(size
,h
->available
);
293 if (h
->buf_idx
+ buffered_data
> buffer_len
)
295 size_t read
= (h
->buf_idx
+ buffered_data
) -buffer_len
;
296 memcpy(dest
, &buffer
[h
->buf_idx
], read
);
297 memcpy(dest
+read
, buffer
, buffered_data
- read
);
299 else memcpy(dest
, &buffer
[h
->buf_idx
], buffered_data
);
300 h
->buf_idx
= RINGBUF_ADD(h
->buf_idx
, buffered_data
);
301 h
->available
-= buffered_data
;
302 return buffered_data
;
305 static void list_handles(void)
307 struct memory_handle
*m
= first_handle
;
309 printf("%02d - %d\n", m
->id
, (void *)m
-(void *)buffer
);
314 void buffer_init(void)
316 buffer
= (char *)malloc(sizeof(char) * (BUFFER_SIZE
+ GUARD_SIZE
));
319 printf("couldn't allocate buffer\n");
322 buffer_len
= BUFFER_SIZE
;
323 buffer_end
= buffer
+ BUFFER_SIZE
;
332 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
335 int main(int argc
, char **argv
)
339 printf("sizeof memory_handle : %d\n", sizeof(struct memory_handle
));
343 for (i
= 1; i
< argc
; i
++) {
344 hdl
= bufopen(argv
[i
], 0);
346 printf("used: %d, free: %d\n", BUF_USED
, BUFFER_SIZE
- BUF_USED
);
347 printf("buf_widx: %d\n", buf_widx
);
353 printf("used: %d, free: %d\n", BUF_USED
, BUFFER_SIZE
- BUF_USED
);
354 printf("buf_widx: %d\n", buf_widx
);
357 printf("used: %d, free: %d\n", BUF_USED
, BUFFER_SIZE
- BUF_USED
);
358 printf("buf_widx: %d\n", buf_widx
);
362 printf("used: %d, free: %d\n", BUF_USED
, BUFFER_SIZE
- BUF_USED
);
363 printf("buf_widx: %d\n", buf_widx
);
368 /* returns true if the file still has some on disk unread */
369 bool handle_has_data(int handle
)
371 struct memory_handle
*m
= find_handle(handle
);
374 return m
->filerem
!= 0;
378 bool need_rebuffer(void)
381 free
= BUFFER_SIZE
- BUF_USED
;
382 return ((free
>= BUFFER_SIZE
/4));
384 #define MAX_HANDLES 64
385 int main(int argc
, char *argv
[])
388 int last_handle
= -1;
389 int handle_order
[MAX_HANDLES
];
390 int reading_handle
= 0;
392 char read_buffer
[GUARD_SIZE
];
394 while (done
== false)
396 if (next_file
<= argc
&& need_rebuffer())
398 printf("buffer usage: %d handles_used: %d\n", BUF_USED
,num_handles
);
399 if ( (!num_handles
||
400 handle_has_data(handle_order
[last_handle
]) == false))
402 int h
= bufopen(argv
[next_file
++], 0);
405 printf("new handle %d\n",h
);
407 handle_order
[last_handle
] = h
;
408 buffer_handle(handle_order
[last_handle
]);
413 if (handle_has_data(handle_order
[last_handle
]) == true)
415 printf("buffering handle %d\n",handle_order
[last_handle
]);
416 buffer_handle(handle_order
[last_handle
]);
422 printf("reading handle: %d\n", handle_order
[reading_handle
]);
423 long total
= 0, read
;
426 if (next_file
> argc
&& reading_handle
>= last_handle
)
429 snprintf(file
, MAX_PATH
, "./file%d.mp3", reading_handle
);
430 fd
= open(file
, O_CREAT
|O_TRUNC
|O_RDWR
, 770);
433 printf("ERROROROROR\n");
438 // printf("reading %d: %d left\n", handle_order[reading_handle],
439 // find_handle(handle_order[reading_handle])->available);
440 read
= bufread(handle_order
[reading_handle
], GUARD_SIZE
,read_buffer
);
442 write(fd
, read_buffer
, read
);
445 printf("finished reading %d, %d\n",handle_order
[reading_handle
], total
);
446 bufclose(handle_order
[reading_handle
]);