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"
44 #include "mp3_playback.h"
54 #define ata_disk_is_active() 1
58 #define GUARD_BUFSIZE (32*1024)
60 #define GUARD_BUFSIZE (8*1024)
63 #define LOGFQUEUE logf
65 /* amount of data to read in one read() call */
66 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
68 /* Ring buffer helper macros */
69 /* Buffer pointer (p) plus value (v), wrapped if necessary */
70 #define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
71 /* Buffer pointer (p) minus value (v), wrapped if necessary */
72 #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
73 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
74 #define RINGBUF_ADD_CROSS(p1,v,p2) \
75 ((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
76 /* Bytes available in the buffer */
77 #define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
79 struct memory_handle
{
80 int id
; /* A unique ID for the handle */
84 size_t data
; /* Start index of the handle's data buffer */
85 size_t ridx
; /* Current read pointer, relative to the main buffer */
86 size_t widx
; /* Current write pointer */
87 size_t filesize
; /* File total length */
88 size_t filerem
; /* Remaining bytes of file NOT in buffer */
89 size_t available
; /* Available bytes to read from buffer */
90 size_t offset
; /* Offset at which we started reading the file */
91 struct memory_handle
*next
;
93 /* at all times, we have: filesize == offset + available + filerem */
97 static char *guard_buffer
;
99 static size_t buffer_len
;
101 static size_t buf_widx
; /* current writing position */
102 static size_t buf_ridx
; /* current reading position */
103 /* buf_*idx are values relative to the buffer, not real pointers. */
105 static size_t conf_filechunk
;
107 /* current memory handle in the linked list. NULL when the list is empty. */
108 static struct memory_handle
*cur_handle
;
109 /* first memory handle in the linked list. NULL when the list is empty. */
110 static struct memory_handle
*first_handle
;
112 static int num_handles
; /* number of handles in the list */
114 /* Handle cache (makes find_handle faster).
115 These need to be global so that move_handle can invalidate them. */
116 static int cached_handle_id
= -1;
117 static struct memory_handle
*cached_handle
= NULL
;
121 LINKED LIST MANAGEMENT
122 ======================
124 add_handle : Add a handle to the list
125 rm_handle : Remove a handle from the list
126 find_handle : Get a handle pointer from an ID
127 move_handle : Move a handle in the buffer (with or without its data)
129 These functions only handle the linked list structure. They don't touch the
130 contents of the struct memory_handle headers. They also change the buf_*idx
131 pointers when necessary and manage the handle IDs.
133 The first and current (== last) handle are kept track of.
134 A new handle is added at buf_widx and becomes the current one.
135 buf_widx always points to the current writing position for the current handle
136 buf_ridx always points to the location of the first handle.
137 buf_ridx == buf_widx means the buffer is empty.
141 /* Add a new handle to the linked list and return it. It will have become the
142 new current handle. The handle will reserve "data_size" bytes or if that's
143 not possible, decrease "data_size" to allow adding the handle. */
144 static struct memory_handle
*add_handle(size_t *data_size
)
146 /* this will give each handle a unique id */
147 static int cur_handle_id
= 1;
149 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
150 but before that we check we can actually align. */
151 if (RINGBUF_ADD_CROSS(buf_widx
, 3, buf_ridx
) >= 0) {
154 buf_widx
= (RINGBUF_ADD(buf_widx
, 3)) & ~3;
156 size_t len
= (data_size
? *data_size
: 0)
157 + sizeof(struct memory_handle
);
159 /* check that we actually can add the handle and its data */
160 int overlap
= RINGBUF_ADD_CROSS(buf_widx
, len
, buf_ridx
);
162 *data_size
-= overlap
;
165 if (len
< sizeof(struct memory_handle
)) {
166 /* There isn't even enough space to write the struct */
170 struct memory_handle
*new_handle
=
171 (struct memory_handle
*)(&buffer
[buf_widx
]);
173 /* only advance the buffer write index of the size of the struct */
174 buf_widx
= RINGBUF_ADD(buf_widx
, sizeof(struct memory_handle
));
177 /* the new handle is the first one */
178 first_handle
= new_handle
;
182 cur_handle
->next
= new_handle
;
185 cur_handle
= new_handle
;
186 cur_handle
->id
= cur_handle_id
++;
187 cur_handle
->next
= NULL
;
192 /* Delete a given memory handle from the linked list
193 and return true for success. Nothing is actually erased from memory. */
194 static bool rm_handle(struct memory_handle
*h
)
196 if (h
== first_handle
) {
197 first_handle
= h
->next
;
198 if (h
== cur_handle
) {
199 /* h was the first and last handle: the buffer is now empty */
203 /* update buf_ridx to point to the new first handle */
204 buf_ridx
= (void *)first_handle
- (void *)buffer
;
207 struct memory_handle
*m
= first_handle
;
208 while (m
&& m
->next
!= h
) {
211 if (h
&& m
&& m
->next
== h
) {
213 if (h
== cur_handle
) {
225 /* Return a pointer to the memory handle of given ID.
226 NULL if the handle wasn't found */
227 static struct memory_handle
*find_handle(int handle_id
)
229 /* simple caching because most of the time the requested handle
230 will either be the same as the last, or the one after the last */
233 if (cached_handle_id
== handle_id
&&
234 cached_handle_id
== cached_handle
->id
)
235 return cached_handle
;
236 else if (cached_handle
->next
&& (cached_handle
->next
->id
== handle_id
))
238 /* JD's quick testing showd this block was only entered
239 2/1971 calls to find_handle.
240 8/1971 calls to find_handle resulted in a cache miss */
241 cached_handle
= cached_handle
->next
;
242 cached_handle_id
= handle_id
;
243 return cached_handle
;
247 struct memory_handle
*m
= first_handle
;
248 while (m
&& m
->id
!= handle_id
) {
251 cached_handle_id
= handle_id
;
253 return (m
&& m
->id
== handle_id
) ? m
: NULL
;
256 /* Move a memory handle and data_size of its data of delta.
257 Return a pointer to the new location of the handle.
258 delta is the value of which to move the struct data.
259 data_size is the amount of data to move along with the struct. */
260 static struct memory_handle
*move_handle(struct memory_handle
*h
,
261 size_t *delta
, size_t data_size
)
264 /* aligning backwards would yield a negative result,
265 and moving the handle of such a small amount is a waste
269 /* make sure delta is 32-bit aligned so that the handle struct is. */
270 *delta
= (*delta
- 3) & ~3;
272 size_t newpos
= RINGBUF_ADD((void *)h
- (void *)buffer
, *delta
);
274 struct memory_handle
*dest
= (struct memory_handle
*)(&buffer
[newpos
]);
276 /* Invalidate the cache to prevent it from keeping the old location of h */
277 if (h
== cached_handle
)
278 cached_handle
= NULL
;
280 /* the cur_handle pointer might need updating */
281 if (h
== cur_handle
) {
285 if (h
== first_handle
) {
289 struct memory_handle
*m
= first_handle
;
290 while (m
&& m
->next
!= h
) {
293 if (h
&& m
&& m
->next
== h
) {
300 memmove(dest
, h
, sizeof(struct memory_handle
) + data_size
);
307 BUFFER SPACE MANAGEMENT
308 =======================
310 buffer_handle : Buffer data for a handle
311 free_buffer : Free buffer space by moving a handle
312 fill_buffer : Call buffer_handle for all handles that have data to buffer
313 can_add_handle : Indicate whether it's safe to add a handle.
314 data_rem : Total amount of data needing to be buffered
315 wasted_space : Total amount of space available for freeing
317 These functions are used by the buffering thread to manage buffer space.
320 static bool filebuf_is_lowdata(void)
322 return BUF_USED
< AUDIO_FILEBUF_CRITICAL
;
325 /* Yield to the codec thread for as long as possible if it is in need of data.
326 Return true if the caller should break to let the buffering thread process
328 static bool yield_codec(void)
332 if (!queue_empty(&buffering_queue
))
335 while (pcmbuf_is_lowdata() && !filebuf_is_lowdata())
339 if (!queue_empty(&buffering_queue
))
346 /* Buffer data for the given handle. Return the amount of data buffered
347 or -1 if the handle wasn't found */
348 /* TODO: add an argument for the requested amount */
349 static ssize_t
buffer_handle(int handle_id
)
351 DEBUGF("buffer_handle(%d)\n", handle_id
);
352 struct memory_handle
*h
= find_handle(handle_id
);
356 if (h
->filerem
== 0) {
357 /* nothing left to buffer */
361 if (h
->fd
< 0) /* file closed, reopen */
364 h
->fd
= open(h
->path
, O_RDONLY
);
372 lseek(h
->fd
, h
->offset
, SEEK_SET
);
378 while (h
->filerem
> 0)
380 /* max amount to copy */
381 size_t copy_n
= MIN( MIN(h
->filerem
, conf_filechunk
),
382 buffer_len
- h
->widx
);
384 /* stop copying if it would overwrite the reading position
385 or the next handle */
386 if (RINGBUF_ADD_CROSS(h
->widx
, copy_n
, buf_ridx
) >= 0 || (h
->next
&&
387 RINGBUF_ADD_CROSS(h
->widx
, copy_n
, (unsigned)
388 ((void *)h
->next
- (void *)buffer
)) > 0))
391 /* rc is the actual amount read */
392 int rc
= read(h
->fd
, &buffer
[h
->widx
], copy_n
);
396 if (h
->type
== TYPE_CODEC
) {
397 DEBUGF("Partial codec\n");
401 DEBUGF("File ended %ld bytes early\n", (long)h
->filerem
);
402 h
->filesize
-= h
->filerem
;
408 h
->widx
= RINGBUF_ADD(h
->widx
, rc
);
415 /* DEBUGF("buffer_handle(%d): buffered %ld bytes. done: %ld. remaining: %ld.\n",
416 h->id, rc, h->available, h->filerem); */
418 /* Stop buffering if new queue events have arrived */
423 if (h
->filerem
== 0) {
424 /* finished buffering the file */
429 DEBUGF("buffered %ld bytes (%ld of %ld available, rem: %ld, off: %ld)\n",
430 (long)ret
, (long)h
->available
, (long)h
->filesize
,
431 (long)h
->filerem
, (long)h
->offset
);
436 /* Reset writing position and data buffer of a handle to its current offset.
437 Use this after having set the new offset to use.
438 Returns 0 for success or -1 if the handle wasn't found. */
439 static void reset_handle(int handle_id
)
441 DEBUGF("reset_handle(%d)\n", handle_id
);
443 struct memory_handle
*h
= find_handle(handle_id
);
451 h
->filerem
= h
->filesize
- h
->offset
;
454 lseek(h
->fd
, h
->offset
, SEEK_SET
);
458 /* Seek to a nonbuffered part of a handle by rebuffering the data. */
459 static void rebuffer_handle(int handle_id
, size_t newpos
)
461 struct memory_handle
*h
= find_handle(handle_id
);
465 DEBUGF("rebuffer_handle: resetting the handle to offset %ld\n", (long)newpos
);
468 LOGFQUEUE("? >| buffering Q_RESET_HANDLE");
469 queue_send(&buffering_queue
, Q_RESET_HANDLE
, handle_id
);
471 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
472 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, handle_id
);
477 /* Free buffer space by moving the handle struct right before the useful
478 part of its data buffer or by moving all the data. */
479 static void free_buffer(int handle_id
)
481 struct memory_handle
*h
= find_handle(handle_id
);
486 /* The value of delta might change for alignment reasons */
488 if (h
->next
&& (h
->type
== TYPE_ID3
|| h
->type
== TYPE_CUESHEET
||
489 h
->type
== TYPE_IMAGE
) && h
->filerem
== 0 )
491 /* metadata handle: we can move all of it */
492 delta
= RINGBUF_SUB( (unsigned)((void *)h
->next
- (void *)buffer
),
493 h
->data
) - h
->available
;
494 h
= move_handle(h
, &delta
, h
->available
);
496 h
->data
= RINGBUF_ADD(h
->data
, delta
);
497 h
->ridx
= RINGBUF_ADD(h
->ridx
, delta
);
498 h
->widx
= RINGBUF_ADD(h
->widx
, delta
);
500 /* when moving a struct mp3entry we need to readjust its pointers. */
501 if (h
->type
== TYPE_ID3
&& h
->filesize
== sizeof(struct mp3entry
)) {
502 adjust_mp3entry((struct mp3entry
*)&buffer
[h
->data
],
503 (void *)&buffer
[h
->data
],
504 (void *)&buffer
[RINGBUF_SUB(h
->data
, delta
)]);
507 DEBUGF("free_buffer(%d): metadata, moved by %ld bytes\n",
508 handle_id
, (long)delta
);
512 /* only move the handle struct */
513 delta
= RINGBUF_SUB(h
->ridx
, h
->data
);
514 h
= move_handle(h
, &delta
, 0);
516 h
->data
= RINGBUF_ADD(h
->data
, delta
);
517 h
->available
-= delta
;
519 DEBUGF("free_buffer(%d): audio, %ld bytes freed\n",
520 handle_id
, (long)delta
);
524 /* Fill the buffer by buffering as much data as possible for handles that still
525 have data left to buffer */
526 static void fill_buffer(void)
528 DEBUGF("fill buffer()\n");
529 struct memory_handle
*m
= first_handle
;
531 if (m
->filerem
> 0) {
532 buffer_handle(m
->id
);
538 /* Check whether it's safe to add a new handle and reserve space to let the
539 current one finish buffering its data. Used by bufopen and bufalloc as
540 a preliminary check before even trying to physically add the handle.
541 Returns true if it's ok to add a new handle, false if not.
543 static bool can_add_handle(void)
545 if (cur_handle
&& cur_handle
->filerem
> 0) {
546 /* the current handle hasn't finished buffering. We can only add
547 a new one if there is already enough free space to finish
549 if (cur_handle
->filerem
< (buffer_len
- BUF_USED
)) {
550 /* Before adding the new handle we reserve some space for the
551 current one to finish buffering its data. */
552 buf_widx
= RINGBUF_ADD(buf_widx
, cur_handle
->filerem
);
561 /* Return the total amount of data left to be buffered for all the handles */
562 static size_t data_rem(void)
566 struct memory_handle
*m
= first_handle
;
575 /* Return the amount of data we have but don't need anymore. This data can be
576 safely erased to reclaim buffer space. */
577 static size_t wasted_space(void)
581 struct memory_handle
*m
= first_handle
;
583 ret
+= RINGBUF_SUB(m
->ridx
, m
->data
);
592 BUFFERING API FUNCTIONS
593 =======================
595 bufopen : Request the opening of a new handle for a file
596 bufalloc : Open a new handle for data other than a file.
597 bufclose : Close an open handle
598 bufseek : Set the read pointer in a handle
599 bufadvance : Move the read pointer in a handle
600 bufread : Copy data from a handle into a given buffer
601 bufgetdata : Give a pointer to the handle's data
602 bufused : Return the amount of buffer space used
604 These functions are exported, to allow interaction with the buffer.
605 They take care of the content of the structs, and rely on the linked list
606 management functions for all the actual handle management work.
610 /* Request a file be buffered
611 filename: name of the file to open
612 offset: offset at which to start buffering the file, useful when the first
613 (offset-1) bytes of the file aren't needed.
614 return value: <0 if the file cannot be opened, or one file already
615 queued to be opened, otherwise the handle for the file in the buffer
617 int bufopen(char *file
, size_t offset
, enum data_type type
)
619 if (!can_add_handle())
622 int fd
= open(file
, O_RDONLY
);
626 size_t size
= filesize(fd
) - offset
;
628 if (type
!= TYPE_AUDIO
&&
629 size
+ sizeof(struct memory_handle
) > buffer_len
- buf_widx
)
631 /* for types other than audio, the data can't wrap, so we force it */
635 DEBUGF("bufopen: %s (offset: %ld) (%ld bytes needed)...\n",
636 file
, (long)offset
, (long)size
);
638 struct memory_handle
*h
= add_handle(&size
);
641 DEBUGF("bufopen: failed to add handle\n");
646 strncpy(h
->path
, file
, MAX_PATH
);
648 h
->filesize
= filesize(fd
);
649 h
->filerem
= h
->filesize
- offset
;
659 DEBUGF("bufopen: allocated %ld bytes. ID: %d\n", (long)size
, h
->id
);
662 if (type
== TYPE_CODEC
|| type
== TYPE_CUESHEET
|| type
== TYPE_IMAGE
) {
663 /* Immediately buffer those */
664 ssize_t ret
= buffer_handle(h
->id
);
666 /* Check that we got the complete file */
667 if ((size_t)ret
!= h
->filesize
) {
674 DEBUGF("bufopen: opened handle %d\n", h
->id
);
678 /* Open a new handle from data that isn't in a file.
679 src is the source buffer from which to copy data. It can be NULL to simply
680 reserve buffer space.
681 size is the requested size. The call will only be successful if the
682 requested amount of data can entirely fit in the buffer without wrapping.
683 Return value is the handle id for success or <0 for failure.
685 int bufalloc(void *src
, size_t size
, enum data_type type
)
687 if (!can_add_handle())
690 if (size
+ sizeof(struct memory_handle
) > buffer_len
- buf_widx
) {
691 /* The data would need to wrap. */
692 DEBUGF("bufalloc: data wrap\n");
696 size_t allocsize
= size
;
697 struct memory_handle
*h
= add_handle(&allocsize
);
699 if (!h
|| allocsize
!= size
)
703 if (type
== TYPE_ID3
&& size
== sizeof(struct mp3entry
)) {
704 DEBUGF("bufalloc: allocating metadata\n");
705 /* specially take care of struct mp3entry */
706 copy_mp3entry((struct mp3entry
*)&buffer
[buf_widx
],
707 (struct mp3entry
*)src
);
709 memcpy(&buffer
[buf_widx
], src
, size
);
724 buf_widx
= RINGBUF_ADD(buf_widx
, size
);
726 DEBUGF("bufalloc: opened handle %d\n", h
->id
);
730 /* Close the handle. Return 0 for success and < 0 for failure */
731 int bufclose(int handle_id
)
733 DEBUGF("bufclose(%d)\n", handle_id
);
734 struct memory_handle
*h
= find_handle(handle_id
);
747 /* Set reading index in handle (relatively to the start of the file).
748 Access before the available data will trigger a rebuffer.
749 TODO: Make it behave like bufadvance
750 TODO: Maybe force an immediate rebuffer by calling buffer_handle() ?
751 Return 0 for success and < 0 for failure:
752 -1 if the handle wasn't found
753 -2 if there is no data available at the new position
754 (the reading index is still moved)
755 -3 if the new requested position was beyond the end of the file
757 int bufseek(int handle_id
, size_t newpos
)
760 struct memory_handle
*h
= find_handle(handle_id
);
764 if (newpos
> h
->filesize
) {
765 /* access beyond the end of the file */
769 else if (newpos
< h
->offset
) {
770 /* access before what we currently have. A rebuffer is needed. */
772 /* TODO: Add a reset_handle queue call here like in bufadvance. */
776 else if (newpos
> h
->offset
+ h
->available
) {
777 /* data isn't available yet. */
781 h
->ridx
= RINGBUF_ADD(h
->data
, newpos
);
785 /* Advance the reading index in a handle (relatively to its current position).
786 Return 0 for success and < 0 for failure */
787 int bufadvance(int handle_id
, off_t offset
)
789 struct memory_handle
*h
= find_handle(handle_id
);
793 size_t newpos
= h
->offset
+ RINGBUF_SUB(h
->ridx
, h
->data
) + offset
;
797 /* check for access beyond what's available */
798 if ((size_t)offset
> (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
)))
800 DEBUGF("bufadvance: access after data\n");
801 rebuffer_handle(handle_id
, newpos
);
804 h
->ridx
= RINGBUF_ADD(h
->ridx
, offset
);
808 /* check for access before what's available */
809 if ((size_t)(-offset
) > RINGBUF_SUB(h
->ridx
, h
->data
))
811 DEBUGF("bufadvance: access before data\n");
812 rebuffer_handle(handle_id
, newpos
);
815 h
->ridx
= RINGBUF_SUB(h
->ridx
, (size_t)(-offset
));
818 //DEBUGF("bufadvance: %ld\n", (long)offset);
822 /* Copy data from the given handle to the dest buffer.
823 Return the number of bytes copied or < 0 for failure. */
824 ssize_t
bufread(int handle_id
, size_t size
, char *dest
)
826 struct memory_handle
*h
= find_handle(handle_id
);
827 size_t buffered_data
;
831 if (size
== 0 && h
->filerem
> 0 &&
832 h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) == 0)
833 /* Data isn't ready */
836 if (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) < size
&& h
->filerem
> 0)
837 /* Data isn't ready */
840 if (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) == 0 && h
->filerem
== 0)
841 /* File is finished reading */
844 buffered_data
= MIN(size
, h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
));
846 if (h
->ridx
+ buffered_data
> buffer_len
)
848 /* the data wraps around the end of the buffer */
849 size_t read
= buffer_len
- h
->ridx
;
850 memcpy(dest
, &buffer
[h
->ridx
], read
);
851 memcpy(dest
+read
, buffer
, buffered_data
- read
);
853 else memcpy(dest
, &buffer
[h
->ridx
], buffered_data
);
855 return buffered_data
;
858 /* Update the "data" pointer to make the handle's data available to the caller.
859 Return the length of the available linear data or < 0 for failure.
860 size is the amount of linear data requested. it can be 0 to get as
862 The guard buffer may be used to provide the requested size */
863 ssize_t
bufgetdata(int handle_id
, size_t size
, unsigned char **data
)
865 struct memory_handle
*h
= find_handle(handle_id
);
869 if (size
== 0 && h
->filerem
> 0 &&
870 h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) == 0)
871 /* Data isn't ready */
874 if (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) < size
&& h
->filerem
> 0)
875 /* Data isn't ready */
878 if (h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) == 0 && h
->filerem
== 0)
879 /* File is finished reading */
884 if (h
->ridx
+ size
> buffer_len
&&
885 h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
) >= size
)
887 /* the data wraps around the end of the buffer :
888 use the guard buffer to provide the requested amount of data. */
889 size_t copy_n
= MIN(h
->ridx
+ size
- buffer_len
, GUARD_BUFSIZE
);
890 memcpy(guard_buffer
, (unsigned char *)buffer
, copy_n
);
891 ret
= buffer_len
- h
->ridx
+ copy_n
;
892 DEBUGF("used the guard buffer to complete\n");
896 ret
= MIN(h
->available
- RINGBUF_SUB(h
->ridx
, h
->data
),
897 buffer_len
- h
->ridx
);
900 *data
= (unsigned char *)&buffer
[h
->ridx
];
902 /* DEBUGF("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id,
903 (long)h->ridx, ret); */
907 /* Return the amount of buffer space used */
913 bool buffering_init(char *filebuf
, size_t filebuflen
)
915 if (!filebuf
|| !filebuflen
)
919 buffer_len
= filebuflen
;
920 guard_buffer
= buffer
+ buffer_len
;
928 conf_filechunk
= AUDIO_DEFAULT_FILECHUNK
;
930 queue_init(&buffering_queue
, true);
931 queue_enable_queue_send(&buffering_queue
, &buffering_queue_sender_list
);
936 void buffering_thread(void)
938 struct queue_event ev
;
942 queue_wait_w_tmo(&buffering_queue
, &ev
, HZ
/2);
945 case Q_BUFFER_HANDLE
:
946 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
947 queue_reply(&buffering_queue
, 1);
948 buffer_handle((int)ev
.data
);
952 LOGFQUEUE("buffering < Q_RESET_HANDLE");
953 queue_reply(&buffering_queue
, 1);
954 reset_handle((int)ev
.data
);
958 case SYS_USB_CONNECTED
:
959 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
960 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
961 usb_wait_for_disconnect(&buffering_queue
);
966 if (queue_empty(&buffering_queue
) &&
967 data_rem() > 0 && wasted_space() > buffer_len
/5) {
968 DEBUGF("there is %ld bytes of wasted space\n", (long)wasted_space());
970 /* free buffer from outdated audio data */
971 struct memory_handle
*m
= first_handle
;
973 if (m
->type
== TYPE_AUDIO
)
978 /* free buffer by moving metadata */
981 if (m
->type
!= TYPE_AUDIO
)
988 if (queue_empty(&buffering_queue
) &&
989 data_rem() > 0 && BUF_USED
< 3*buffer_len
/4 /* &&
990 ata_disk_is_active() */)
992 DEBUGF("%ld bytes left to buffer and the buffer is low\n",
1001 ssize_t
get_offset(int handle_id
, void *ptr
)
1003 struct memory_handle
*h
= find_handle(handle_id
);
1007 return (size_t)ptr
- (size_t)&buffer
[h
->ridx
];