1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Nicolas Pennequin
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include "buffering.h"
44 #include "mp3_playback.h"
49 #include "appevents.h"
53 #include "jpeg_load.h"
58 #define GUARD_BUFSIZE (32*1024)
60 /* Define LOGF_ENABLE to enable logf output in this file */
61 /* #define LOGF_ENABLE */
64 /* macros to enable logf for queues
65 logging on SYS_TIMEOUT can be disabled */
67 /* Define this for logf output of all queuing except SYS_TIMEOUT */
68 #define BUFFERING_LOGQUEUES
69 /* Define this to logf SYS_TIMEOUT messages */
70 /* #define BUFFERING_LOGQUEUES_SYS_TIMEOUT */
73 #ifdef BUFFERING_LOGQUEUES
74 #define LOGFQUEUE logf
76 #define LOGFQUEUE(...)
79 #ifdef BUFFERING_LOGQUEUES_SYS_TIMEOUT
80 #define LOGFQUEUE_SYS_TIMEOUT logf
82 #define LOGFQUEUE_SYS_TIMEOUT(...)
85 /* amount of data to read in one read() call */
86 #define BUFFERING_DEFAULT_FILECHUNK (1024*32)
88 #define BUF_HANDLE_MASK 0x7FFFFFFF
91 /* assert(sizeof(struct memory_handle)%4==0) */
92 struct memory_handle
{
93 int id
; /* A unique ID for the handle */
94 enum data_type type
; /* Type of data buffered with this handle */
95 int8_t pinned
; /* Count of references */
96 int8_t signaled
; /* Stop any attempt at waiting to get the data */
97 char path
[MAX_PATH
]; /* Path if data originated in a file */
98 int fd
; /* File descriptor to path (-1 if closed) */
99 size_t data
; /* Start index of the handle's data buffer */
100 volatile size_t ridx
; /* Read pointer, relative to the main buffer */
101 size_t widx
; /* Write pointer, relative to the main buffer */
102 size_t filesize
; /* File total length */
103 size_t filerem
; /* Remaining bytes of file NOT in buffer */
104 volatile size_t available
; /* Available bytes to read from buffer */
105 size_t offset
; /* Offset at which we started reading the file */
106 struct memory_handle
*next
;
108 /* invariant: filesize == offset + available + filerem */
111 struct buf_message_data
118 static char *guard_buffer
;
120 static size_t buffer_len
;
122 static volatile size_t buf_widx
; /* current writing position */
123 static volatile size_t buf_ridx
; /* current reading position */
124 /* buf_*idx are values relative to the buffer, not real pointers. */
127 static size_t conf_watermark
= 0; /* Level to trigger filebuf fill */
128 static size_t high_watermark
= 0; /* High watermark for rebuffer */
130 /* current memory handle in the linked list. NULL when the list is empty. */
131 static struct memory_handle
*cur_handle
;
132 /* first memory handle in the linked list. NULL when the list is empty. */
133 static struct memory_handle
*first_handle
;
135 static int num_handles
; /* number of handles in the list */
137 static int base_handle_id
;
139 /* Main lock for adding / removing handles */
140 static struct mutex llist_mutex SHAREDBSS_ATTR
;
142 /* Handle cache (makes find_handle faster).
143 This is global so that move_handle and rm_handle can invalidate it. */
144 static struct memory_handle
*cached_handle
= NULL
;
146 static struct data_counters
148 size_t remaining
; /* Amount of data needing to be buffered */
149 size_t wasted
; /* Amount of space available for freeing */
150 size_t buffered
; /* Amount of data currently in the buffer */
151 size_t useful
; /* Amount of data still useful to the user */
155 /* Messages available to communicate with the buffering thread */
158 Q_BUFFER_HANDLE
= 1, /* Request buffering of a handle, this should not be
159 used in a low buffer situation. */
160 Q_REBUFFER_HANDLE
, /* Request reset and rebuffering of a handle at a new
161 file starting position. */
162 Q_CLOSE_HANDLE
, /* Request closing a handle */
165 Q_START_FILL
, /* Request that the buffering thread initiate a buffer
166 fill at its earliest convenience */
167 Q_HANDLE_ADDED
, /* Inform the buffering thread that a handle was added,
168 (which means the disk is spinning) */
171 /* Buffering thread */
172 static void buffering_thread(void);
173 static long buffering_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)];
174 static const char buffering_thread_name
[] = "buffering";
175 static unsigned int buffering_thread_id
= 0;
176 static struct event_queue buffering_queue SHAREDBSS_ATTR
;
177 static struct queue_sender_list buffering_queue_sender_list SHAREDBSS_ATTR
;
181 /* Ring buffer helper functions */
183 static inline uintptr_t ringbuf_offset(const void *ptr
)
185 return (uintptr_t)(ptr
- (void*)buffer
);
188 /* Buffer pointer (p) plus value (v), wrapped if necessary */
189 static inline uintptr_t ringbuf_add(uintptr_t p
, size_t v
)
191 uintptr_t res
= p
+ v
;
192 if (res
>= buffer_len
)
193 res
-= buffer_len
; /* wrap if necssary */
198 /* Buffer pointer (p) minus value (v), wrapped if necessary */
199 static inline uintptr_t ringbuf_sub(uintptr_t p
, size_t v
)
203 res
+= buffer_len
; /* wrap */
209 /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
210 static inline ssize_t
ringbuf_add_cross(uintptr_t p1
, size_t v
, uintptr_t p2
)
212 ssize_t res
= p1
+ v
- p2
;
213 if (p1
>= p2
) /* wrap if necessary */
219 /* Bytes available in the buffer */
220 #define BUF_USED ringbuf_sub(buf_widx, buf_ridx)
222 /* Real buffer watermark */
223 #define BUF_WATERMARK MIN(conf_watermark, high_watermark)
226 LINKED LIST MANAGEMENT
227 ======================
229 add_handle : Add a handle to the list
230 rm_handle : Remove a handle from the list
231 find_handle : Get a handle pointer from an ID
232 move_handle : Move a handle in the buffer (with or without its data)
234 These functions only handle the linked list structure. They don't touch the
235 contents of the struct memory_handle headers. They also change the buf_*idx
236 pointers when necessary and manage the handle IDs.
238 The first and current (== last) handle are kept track of.
239 A new handle is added at buf_widx and becomes the current one.
240 buf_widx always points to the current writing position for the current handle
241 buf_ridx always points to the location of the first handle.
242 buf_ridx == buf_widx means the buffer is empty.
246 /* Add a new handle to the linked list and return it. It will have become the
248 data_size must contain the size of what will be in the handle.
249 can_wrap tells us whether this type of data may wrap on buffer
250 alloc_all tells us if we must immediately be able to allocate data_size
251 returns a valid memory handle if all conditions for allocation are met.
252 NULL if there memory_handle itself cannot be allocated or if the
253 data_size cannot be allocated and alloc_all is set. */
254 static struct memory_handle
*add_handle(size_t data_size
, bool can_wrap
,
257 /* gives each handle a unique id */
258 static int cur_handle_id
= 0;
260 size_t widx
, new_widx
;
264 if (num_handles
>= BUF_MAX_HANDLES
)
269 if (cur_handle
&& cur_handle
->filerem
> 0) {
270 /* the current handle hasn't finished buffering. We can only add
271 a new one if there is already enough free space to finish
273 size_t req
= cur_handle
->filerem
;
274 if (ringbuf_add_cross(cur_handle
->widx
, req
, buf_ridx
) >= 0) {
275 /* Not enough space to finish allocation */
278 /* Allocate the remainder of the space for the current handle */
279 widx
= ringbuf_add(cur_handle
->widx
, cur_handle
->filerem
);
283 /* align to 4 bytes up always leaving a gap */
284 new_widx
= ringbuf_add(widx
, 4) & ~3;
286 len
= data_size
+ sizeof(struct memory_handle
);
288 /* First, will the handle wrap? */
289 /* If the handle would wrap, move to the beginning of the buffer,
290 * or if the data must not but would wrap, move it to the beginning */
291 if (new_widx
+ sizeof(struct memory_handle
) > buffer_len
||
292 (!can_wrap
&& new_widx
+ len
> buffer_len
)) {
296 /* How far we shifted the new_widx to align things, must be < buffer_len */
297 shift
= ringbuf_sub(new_widx
, widx
);
299 /* How much space are we short in the actual ring buffer? */
300 overlap
= ringbuf_add_cross(widx
, shift
+ len
, buf_ridx
);
301 if (overlap
>= 0 && (alloc_all
|| (size_t)overlap
>= data_size
)) {
302 /* Not enough space for required allocations */
306 /* There is enough space for the required data, advance the buf_widx and
307 * initialize the struct */
310 struct memory_handle
*new_handle
=
311 (struct memory_handle
*)(&buffer
[buf_widx
]);
313 /* Prevent buffering thread from looking at it */
314 new_handle
->filerem
= 0;
316 /* Handle can be moved by default */
317 new_handle
->pinned
= 0;
319 /* Handle data can be waited for by default */
320 new_handle
->signaled
= 0;
322 /* only advance the buffer write index of the size of the struct */
323 buf_widx
= ringbuf_add(buf_widx
, sizeof(struct memory_handle
));
325 new_handle
->id
= cur_handle_id
;
326 /* Wrap signed int is safe and 0 doesn't happen */
327 cur_handle_id
= (cur_handle_id
+ 1) & BUF_HANDLE_MASK
;
328 new_handle
->next
= NULL
;
332 /* the new handle is the first one */
333 first_handle
= new_handle
;
336 cur_handle
->next
= new_handle
;
338 cur_handle
= new_handle
;
343 /* Delete a given memory handle from the linked list
344 and return true for success. Nothing is actually erased from memory. */
345 static bool rm_handle(const struct memory_handle
*h
)
350 if (h
== first_handle
) {
351 first_handle
= h
->next
;
352 if (h
== cur_handle
) {
353 /* h was the first and last handle: the buffer is now empty */
355 buf_ridx
= buf_widx
= 0;
357 /* update buf_ridx to point to the new first handle */
358 buf_ridx
= (size_t)ringbuf_offset(first_handle
);
361 struct memory_handle
*m
= first_handle
;
362 /* Find the previous handle */
363 while (m
&& m
->next
!= h
) {
366 if (m
&& m
->next
== h
) {
368 if (h
== cur_handle
) {
370 buf_widx
= cur_handle
->widx
;
373 /* If we don't find ourselves, this is a seriously incoherent
374 state with a corrupted list and severe action is needed! */
375 panicf("rm_handle fail: %d", h
->id
);
380 /* Invalidate the cache to prevent it from keeping the old location of h */
381 if (h
== cached_handle
)
382 cached_handle
= NULL
;
388 /* Return a pointer to the memory handle of given ID.
389 NULL if the handle wasn't found */
390 static struct memory_handle
*find_handle(int handle_id
)
395 /* simple caching because most of the time the requested handle
396 will either be the same as the last, or the one after the last */
398 if (cached_handle
->id
== handle_id
) {
399 return cached_handle
;
400 } else if (cached_handle
->next
&&
401 (cached_handle
->next
->id
== handle_id
)) {
402 cached_handle
= cached_handle
->next
;
403 return cached_handle
;
407 struct memory_handle
*m
= first_handle
;
408 while (m
&& m
->id
!= handle_id
) {
411 /* This condition can only be reached with !m or m->id == handle_id */
418 /* Move a memory handle and data_size of its data delta bytes along the buffer.
419 delta maximum bytes available to move the handle. If the move is performed
420 it is set to the actual distance moved.
421 data_size is the amount of data to move along with the struct.
422 returns true if the move is successful and false if the handle is NULL,
423 the move would be less than the size of a memory_handle after
424 correcting for wraps or if the handle is not found in the linked
425 list for adjustment. This function has no side effects if false
427 static bool move_handle(struct memory_handle
**h
, size_t *delta
,
428 size_t data_size
, bool can_wrap
)
430 struct memory_handle
*dest
;
431 const struct memory_handle
*src
;
432 size_t final_delta
= *delta
, size_to_move
;
433 uintptr_t oldpos
, newpos
;
434 intptr_t overlap
, overlap_old
;
436 if (h
== NULL
|| (src
= *h
) == NULL
)
439 size_to_move
= sizeof(struct memory_handle
) + data_size
;
441 /* Align to four bytes, down */
443 if (final_delta
< sizeof(struct memory_handle
)) {
444 /* It's not legal to move less than the size of the struct */
448 oldpos
= ringbuf_offset(src
);
449 newpos
= ringbuf_add(oldpos
, final_delta
);
450 overlap
= ringbuf_add_cross(newpos
, size_to_move
, buffer_len
);
451 overlap_old
= ringbuf_add_cross(oldpos
, size_to_move
, buffer_len
);
454 /* Some part of the struct + data would wrap, maybe ok */
455 ssize_t correction
= 0;
456 /* If the overlap lands inside the memory_handle */
458 /* Otherwise the overlap falls in the data area and must all be
459 * backed out. This may become conditional if ever we move
460 * data that is allowed to wrap (ie audio) */
461 correction
= overlap
;
462 } else if ((uintptr_t)overlap
> data_size
) {
463 /* Correct the position and real delta to prevent the struct from
464 * wrapping, this guarantees an aligned delta if the struct size is
465 * aligned and the buffer is aligned */
466 correction
= overlap
- data_size
;
469 /* Align correction to four bytes up */
470 correction
= (correction
+ 3) & ~3;
471 if (final_delta
< correction
+ sizeof(struct memory_handle
)) {
472 /* Delta cannot end up less than the size of the struct */
475 newpos
-= correction
;
476 overlap
-= correction
;/* Used below to know how to split the data */
477 final_delta
-= correction
;
481 dest
= (struct memory_handle
*)(&buffer
[newpos
]);
483 if (src
== first_handle
) {
487 struct memory_handle
*m
= first_handle
;
488 while (m
&& m
->next
!= src
) {
491 if (m
&& m
->next
== src
) {
498 /* Update the cache to prevent it from keeping the old location of h */
499 if (src
== cached_handle
)
500 cached_handle
= dest
;
502 /* the cur_handle pointer might need updating */
503 if (src
== cur_handle
)
506 /* x = handle(s) following this one...
507 * ...if last handle, unmoveable if metadata, only shrinkable if audio.
508 * In other words, no legal move can be made that would have the src head
509 * and dest tail of the data overlap itself. These facts reduce the
510 * problem to four essential permutations.
512 * movement: always "clockwise" >>>>
514 * (src nowrap, dest nowrap)
519 * (src nowrap, dest wrap)
524 * (src wrap, dest nowrap)
529 * (src wrap, dest wrap)
532 * move: "23", "1", "0"
534 if (overlap_old
> 0) {
535 /* Move over already wrapped data by the final delta */
536 memmove(&buffer
[final_delta
], buffer
, overlap_old
);
538 size_to_move
-= overlap_old
;
542 /* Move data that now wraps to the beginning */
543 size_to_move
-= overlap
;
544 memmove(buffer
, SKIPBYTES(src
, size_to_move
),
545 overlap_old
> 0 ? final_delta
: (size_t)overlap
);
548 /* Move leading fragment containing handle struct */
549 memmove(dest
, src
, size_to_move
);
551 /* Update the caller with the new location of h and the distance moved */
553 *delta
= final_delta
;
559 BUFFER SPACE MANAGEMENT
560 =======================
562 update_data_counters: Updates the values in data_counters
563 buffer_is_low : Returns true if the amount of useful data in the buffer is low
564 buffer_handle : Buffer data for a handle
565 rebuffer_handle : Seek to a nonbuffered part of a handle by rebuffering the data
566 shrink_handle : Free buffer space by moving a handle
567 fill_buffer : Call buffer_handle for all handles that have data to buffer
569 These functions are used by the buffering thread to manage buffer space.
571 static size_t handle_size_available(const struct memory_handle
*h
)
573 /* Obtain proper distances from data start */
574 size_t rd
= ringbuf_sub(h
->ridx
, h
->data
);
575 size_t wr
= ringbuf_sub(h
->widx
, h
->data
);
580 return 0; /* ridx is ahead of or equal to widx at this time */
583 static void update_data_counters(struct data_counters
*dc
)
587 size_t remaining
= 0;
590 struct memory_handle
*m
;
596 mutex_lock(&llist_mutex
);
598 m
= find_handle(base_handle_id
);
599 is_useful
= m
== NULL
;
603 buffered
+= m
->available
;
604 /* wasted could come out larger than the buffer size if ridx's are
605 overlapping data ahead of their handles' buffered data */
606 wasted
+= ringbuf_sub(m
->ridx
, m
->data
);
607 remaining
+= m
->filerem
;
609 if (m
->id
== base_handle_id
)
613 useful
+= handle_size_available(m
);
618 mutex_unlock(&llist_mutex
);
620 dc
->buffered
= buffered
;
622 dc
->remaining
= remaining
;
626 static inline bool buffer_is_low(void)
628 update_data_counters(NULL
);
629 return data_counters
.useful
< BUF_WATERMARK
/ 2;
632 /* Q_BUFFER_HANDLE event and buffer data for the given handle.
633 Return whether or not the buffering should continue explicitly. */
634 static bool buffer_handle(int handle_id
, size_t to_buffer
)
636 logf("buffer_handle(%d, %lu)", handle_id
, (unsigned long)to_buffer
);
637 struct memory_handle
*h
= find_handle(handle_id
);
643 logf(" type: %d", (int)h
->type
);
645 if (h
->filerem
== 0) {
646 /* nothing left to buffer */
650 if (h
->fd
< 0) { /* file closed, reopen */
652 h
->fd
= open(h
->path
, O_RDONLY
);
656 /* could not open the file, truncate it where it is */
657 h
->filesize
-= h
->filerem
;
663 lseek(h
->fd
, h
->offset
, SEEK_SET
);
668 if (h
->type
== TYPE_ID3
) {
669 if (!get_metadata((struct mp3entry
*)(buffer
+ h
->data
),
671 /* metadata parsing failed: clear the buffer. */
672 wipe_mp3entry((struct mp3entry
*)(buffer
+ h
->data
));
677 h
->available
= sizeof(struct mp3entry
);
678 h
->widx
= ringbuf_add(h
->widx
, sizeof(struct mp3entry
));
679 send_event(BUFFER_EVENT_FINISHED
, &handle_id
);
683 while (h
->filerem
> 0 && !stop
)
685 /* max amount to copy */
686 ssize_t copy_n
= MIN( MIN(h
->filerem
, BUFFERING_DEFAULT_FILECHUNK
),
687 buffer_len
- h
->widx
);
688 uintptr_t offset
= h
->next
? ringbuf_offset(h
->next
) : buf_ridx
;
689 ssize_t overlap
= ringbuf_add_cross(h
->widx
, copy_n
, offset
) + 1;
692 /* read only up to available space and stop if it would overwrite
693 or be on top of the reading position or the next handle */
699 return false; /* no space for read */
701 /* rc is the actual amount read */
702 int rc
= read(h
->fd
, &buffer
[h
->widx
], copy_n
);
705 /* Some kind of filesystem error, maybe recoverable if not codec */
706 if (h
->type
== TYPE_CODEC
) {
707 logf("Partial codec");
711 logf("File ended %ld bytes early\n", (long)h
->filerem
);
712 h
->filesize
-= h
->filerem
;
718 h
->widx
= ringbuf_add(h
->widx
, rc
);
724 /* If this is a large file, see if we need to break or give the codec
726 if (h
->type
== TYPE_PACKET_AUDIO
&&
727 pcmbuf_is_lowdata() && !buffer_is_low()) {
733 if (to_buffer
== 0) {
734 /* Normal buffering - check queue */
735 if(!queue_empty(&buffering_queue
))
738 if (to_buffer
<= (size_t)rc
)
744 if (h
->filerem
== 0) {
745 /* finished buffering the file */
748 send_event(BUFFER_EVENT_FINISHED
, &handle_id
);
754 /* Close the specified handle id and free its allocation. */
755 static bool close_handle(int handle_id
)
758 struct memory_handle
*h
;
760 mutex_lock(&llist_mutex
);
761 h
= find_handle(handle_id
);
763 /* If the handle is not found, it is closed */
770 /* rm_handle returns true unless the handle somehow persists after
772 retval
= rm_handle(h
);
775 mutex_unlock(&llist_mutex
);
779 /* Free buffer space by moving the handle struct right before the useful
780 part of its data buffer or by moving all the data. */
781 static void shrink_handle(struct memory_handle
*h
)
786 if (h
->type
== TYPE_PACKET_AUDIO
) {
787 /* only move the handle struct */
788 /* data is pinned by default - if we start moving packet audio,
789 the semantics will determine whether or not data is movable
790 but the handle will remain movable in either case */
791 size_t delta
= ringbuf_sub(h
->ridx
, h
->data
);
793 /* The value of delta might change for alignment reasons */
794 if (!move_handle(&h
, &delta
, 0, true))
797 h
->data
= ringbuf_add(h
->data
, delta
);
798 h
->available
-= delta
;
801 /* metadata handle: we can move all of it */
802 if (h
->pinned
|| !h
->next
|| h
->filerem
!= 0)
803 return; /* Pinned, last handle or not finished loading */
805 uintptr_t handle_distance
=
806 ringbuf_sub(ringbuf_offset(h
->next
), h
->data
);
807 size_t delta
= handle_distance
- h
->available
;
809 /* The value of delta might change for alignment reasons */
810 if (!move_handle(&h
, &delta
, h
->available
, h
->type
==TYPE_CODEC
))
813 size_t olddata
= h
->data
;
814 h
->data
= ringbuf_add(h
->data
, delta
);
815 h
->ridx
= ringbuf_add(h
->ridx
, delta
);
816 h
->widx
= ringbuf_add(h
->widx
, delta
);
818 if (h
->type
== TYPE_ID3
&& h
->filesize
== sizeof(struct mp3entry
)) {
819 /* when moving an mp3entry we need to readjust its pointers. */
820 adjust_mp3entry((struct mp3entry
*)&buffer
[h
->data
],
821 (void *)&buffer
[h
->data
],
822 (const void *)&buffer
[olddata
]);
823 } else if (h
->type
== TYPE_BITMAP
) {
824 /* adjust the bitmap's pointer */
825 struct bitmap
*bmp
= (struct bitmap
*)&buffer
[h
->data
];
826 bmp
->data
= &buffer
[h
->data
+ sizeof(struct bitmap
)];
831 /* Fill the buffer by buffering as much data as possible for handles that still
832 have data left to buffer
833 Return whether or not to continue filling after this */
834 static bool fill_buffer(void)
836 logf("fill_buffer()");
837 struct memory_handle
*m
= first_handle
;
841 while (queue_empty(&buffering_queue
) && m
) {
842 if (m
->filerem
> 0) {
843 if (!buffer_handle(m
->id
, 0)) {
854 /* only spin the disk down if the filling wasn't interrupted by an
855 event arriving in the queue. */
862 /* Given a file descriptor to a bitmap file, write the bitmap data to the
863 buffer, with a struct bitmap and the actual data immediately following.
864 Return value is the total size (struct + data). */
865 static int load_image(int fd
, const char *path
,
866 struct bufopen_bitmap_data
*data
)
869 struct bitmap
*bmp
= (struct bitmap
*)&buffer
[buf_widx
];
870 struct dim
*dim
= data
->dim
;
871 struct mp3_albumart
*aa
= data
->embedded_albumart
;
873 /* get the desired image size */
874 bmp
->width
= dim
->width
, bmp
->height
= dim
->height
;
875 /* FIXME: alignment may be needed for the data buffer. */
876 bmp
->data
= &buffer
[buf_widx
+ sizeof(struct bitmap
)];
880 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
881 bmp
->maskdata
= NULL
;
884 int free
= (int)MIN(buffer_len
- BUF_USED
, buffer_len
- buf_widx
)
885 - sizeof(struct bitmap
);
889 lseek(fd
, aa
->pos
, SEEK_SET
);
890 rc
= clip_jpeg_fd(fd
, aa
->size
, bmp
, free
, FORMAT_NATIVE
|FORMAT_DITHER
|
891 FORMAT_RESIZE
|FORMAT_KEEP_ASPECT
, NULL
);
893 else if (strcmp(path
+ strlen(path
) - 4, ".bmp"))
894 rc
= read_jpeg_fd(fd
, bmp
, free
, FORMAT_NATIVE
|FORMAT_DITHER
|
895 FORMAT_RESIZE
|FORMAT_KEEP_ASPECT
, NULL
);
898 rc
= read_bmp_fd(fd
, bmp
, free
, FORMAT_NATIVE
|FORMAT_DITHER
|
899 FORMAT_RESIZE
|FORMAT_KEEP_ASPECT
, NULL
);
900 return rc
+ (rc
> 0 ? sizeof(struct bitmap
) : 0);
906 MAIN BUFFERING API CALLS
907 ========================
909 bufopen : Request the opening of a new handle for a file
910 bufalloc : Open a new handle for data other than a file.
911 bufclose : Close an open handle
912 bufseek : Set the read pointer in a handle
913 bufadvance : Move the read pointer in a handle
914 bufread : Copy data from a handle into a given buffer
915 bufgetdata : Give a pointer to the handle's data
917 These functions are exported, to allow interaction with the buffer.
918 They take care of the content of the structs, and rely on the linked list
919 management functions for all the actual handle management work.
923 /* Reserve space in the buffer for a file.
924 filename: name of the file to open
925 offset: offset at which to start buffering the file, useful when the first
926 offset bytes of the file aren't needed.
927 type: one of the data types supported (audio, image, cuesheet, others
928 user_data: user data passed possibly passed in subcalls specific to a
929 data_type (only used for image (albumart) buffering so far )
930 return value: <0 if the file cannot be opened, or one file already
931 queued to be opened, otherwise the handle for the file in the buffer
933 int bufopen(const char *file
, size_t offset
, enum data_type type
,
936 #ifndef HAVE_ALBUMART
937 /* currently only used for aa loading */
940 int handle_id
= ERR_BUFFER_FULL
;
942 /* No buffer refs until after the mutex_lock call! */
944 if (type
== TYPE_ID3
) {
945 /* ID3 case: allocate space, init the handle and return. */
946 mutex_lock(&llist_mutex
);
948 struct memory_handle
*h
=
949 add_handle(sizeof(struct mp3entry
), false, true);
954 h
->filesize
= sizeof(struct mp3entry
);
961 strlcpy(h
->path
, file
, MAX_PATH
);
963 buf_widx
= ringbuf_add(buf_widx
, sizeof(struct mp3entry
));
965 h
->filerem
= sizeof(struct mp3entry
);
967 /* Inform the buffering thread that we added a handle */
968 LOGFQUEUE("buffering > Q_HANDLE_ADDED %d", handle_id
);
969 queue_post(&buffering_queue
, Q_HANDLE_ADDED
, handle_id
);
972 mutex_unlock(&llist_mutex
);
975 else if (type
== TYPE_UNKNOWN
)
976 return ERR_UNSUPPORTED_TYPE
;
978 /* loading code from memory is not supported in application builds */
979 else if (type
== TYPE_CODEC
)
980 return ERR_UNSUPPORTED_TYPE
;
982 /* Other cases: there is a little more work. */
983 int fd
= open(file
, O_RDONLY
);
985 return ERR_FILE_ERROR
;
989 if (type
== TYPE_BITMAP
) {
990 /* if albumart is embedded, the complete file is not buffered,
991 * but only the jpeg part; filesize() would be wrong */
992 struct bufopen_bitmap_data
*aa
= (struct bufopen_bitmap_data
*)user_data
;
993 if (aa
->embedded_albumart
)
994 size
= aa
->embedded_albumart
->size
;
999 bool can_wrap
= type
==TYPE_PACKET_AUDIO
|| type
==TYPE_CODEC
;
1001 size_t adjusted_offset
= offset
;
1002 if (adjusted_offset
> size
)
1003 adjusted_offset
= 0;
1005 /* Reserve extra space because alignment can move data forward */
1006 size_t padded_size
= STORAGE_PAD(size
-adjusted_offset
);
1008 mutex_lock(&llist_mutex
);
1010 struct memory_handle
*h
= add_handle(padded_size
, can_wrap
, false);
1012 DEBUGF("%s(): failed to add handle\n", __func__
);
1013 mutex_unlock(&llist_mutex
);
1015 return ERR_BUFFER_FULL
;
1019 strlcpy(h
->path
, file
, MAX_PATH
);
1020 h
->offset
= adjusted_offset
;
1022 #ifdef STORAGE_WANTS_ALIGN
1023 /* Don't bother to storage align bitmaps because they are not
1024 * loaded directly into the buffer.
1026 if (type
!= TYPE_BITMAP
) {
1027 /* Align to desired storage alignment */
1028 size_t alignment_pad
= STORAGE_OVERLAP(adjusted_offset
-
1029 (size_t)(&buffer
[buf_widx
]));
1030 buf_widx
= ringbuf_add(buf_widx
, alignment_pad
);
1032 #endif /* STORAGE_WANTS_ALIGN */
1041 #ifdef HAVE_ALBUMART
1042 if (type
== TYPE_BITMAP
) {
1043 /* Bitmap file: we load the data instead of the file */
1045 rc
= load_image(fd
, file
, (struct bufopen_bitmap_data
*)user_data
);
1048 handle_id
= ERR_FILE_ERROR
;
1052 buf_widx
= ringbuf_add(buf_widx
, rc
);
1059 if (type
== TYPE_CUESHEET
)
1065 h
->filerem
= size
- adjusted_offset
;
1068 mutex_unlock(&llist_mutex
);
1070 if (type
== TYPE_CUESHEET
) {
1071 /* Immediately start buffering those */
1072 LOGFQUEUE("buffering >| Q_BUFFER_HANDLE %d", handle_id
);
1073 queue_send(&buffering_queue
, Q_BUFFER_HANDLE
, handle_id
);
1075 /* Other types will get buffered in the course of normal operations */
1078 if (handle_id
>= 0) {
1079 /* Inform the buffering thread that we added a handle */
1080 LOGFQUEUE("buffering > Q_HANDLE_ADDED %d", handle_id
);
1081 queue_post(&buffering_queue
, Q_HANDLE_ADDED
, handle_id
);
1085 logf("bufopen: new hdl %d", handle_id
);
1089 /* Open a new handle from data that needs to be copied from memory.
1090 src is the source buffer from which to copy data. It can be NULL to simply
1091 reserve buffer space.
1092 size is the requested size. The call will only be successful if the
1093 requested amount of data can entirely fit in the buffer without wrapping.
1094 Return value is the handle id for success or <0 for failure.
1096 int bufalloc(const void *src
, size_t size
, enum data_type type
)
1100 if (type
== TYPE_UNKNOWN
)
1101 return ERR_UNSUPPORTED_TYPE
;
1103 handle_id
= ERR_BUFFER_FULL
;
1105 mutex_lock(&llist_mutex
);
1107 struct memory_handle
*h
= add_handle(size
, false, true);
1113 if (type
== TYPE_ID3
&& size
== sizeof(struct mp3entry
)) {
1114 /* specially take care of struct mp3entry */
1115 copy_mp3entry((struct mp3entry
*)&buffer
[buf_widx
],
1116 (const struct mp3entry
*)src
);
1118 memcpy(&buffer
[buf_widx
], src
, size
);
1128 buf_widx
= ringbuf_add(buf_widx
, size
);
1130 h
->available
= size
;
1134 mutex_unlock(&llist_mutex
);
1136 logf("bufalloc: new hdl %d", handle_id
);
1140 /* Close the handle. Return true for success and false for failure */
1141 bool bufclose(int handle_id
)
1143 logf("bufclose(%d)", handle_id
);
1145 /* Don't interrupt the buffering thread if the handle is already
1147 if (!find_handle(handle_id
)) {
1148 logf(" handle already closed");
1152 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id
);
1153 return queue_send(&buffering_queue
, Q_CLOSE_HANDLE
, handle_id
);
1156 /* Backend to bufseek and bufadvance. Call only in response to
1157 Q_REBUFFER_HANDLE! */
1158 static void rebuffer_handle(int handle_id
, size_t newpos
)
1160 struct memory_handle
*h
= find_handle(handle_id
);
1163 queue_reply(&buffering_queue
, ERR_HANDLE_NOT_FOUND
);
1167 /* When seeking foward off of the buffer, if it is a short seek attempt to
1168 avoid rebuffering the whole track, just read enough to satisfy */
1169 if (newpos
> h
->offset
&&
1170 newpos
- h
->offset
< BUFFERING_DEFAULT_FILECHUNK
) {
1172 size_t amount
= newpos
- h
->offset
;
1173 h
->ridx
= ringbuf_add(h
->data
, amount
);
1175 if (buffer_handle(handle_id
, amount
+ 1)) {
1176 size_t rd
= ringbuf_sub(h
->ridx
, h
->data
);
1177 size_t wr
= ringbuf_sub(h
->widx
, h
->data
);
1179 /* It really did succeed */
1180 queue_reply(&buffering_queue
, 0);
1181 buffer_handle(handle_id
, 0); /* Ok, try the rest */
1185 /* Data collision or other file error - must reset */
1187 if (newpos
> h
->filesize
)
1188 newpos
= h
->filesize
; /* file truncation happened above */
1191 /* Reset the handle to its new position */
1194 size_t next
= h
->next
? ringbuf_offset(h
->next
) : buf_ridx
;
1196 #ifdef STORAGE_WANTS_ALIGN
1197 /* Strip alignment padding then redo */
1198 size_t new_index
= ringbuf_add(ringbuf_offset(h
), sizeof (*h
));
1200 /* Align to desired storage alignment if space permits - handle could
1201 have been shrunken too close to the following one after a previous
1203 size_t alignment_pad
=
1204 STORAGE_OVERLAP(h
->offset
- (size_t)(&buffer
[new_index
]));
1206 if (ringbuf_add_cross(new_index
, alignment_pad
, next
) >= 0)
1207 alignment_pad
= 0; /* Forego storage alignment this time */
1209 new_index
= ringbuf_add(new_index
, alignment_pad
);
1211 /* Just clear the data buffer */
1212 size_t new_index
= h
->data
;
1213 #endif /* STORAGE_WANTS_ALIGN */
1215 h
->ridx
= h
->widx
= h
->data
= new_index
;
1217 if (h
== cur_handle
)
1218 buf_widx
= new_index
;
1221 h
->filerem
= h
->filesize
- h
->offset
;
1224 lseek(h
->fd
, h
->offset
, SEEK_SET
);
1226 if (h
->next
&& ringbuf_sub(next
, h
->data
) <= h
->filesize
- newpos
) {
1227 /* There isn't enough space to rebuffer all of the track from its new
1228 offset, so we ask the user to free some */
1229 DEBUGF("%s(): space is needed\n", __func__
);
1230 int hid
= handle_id
;
1231 send_event(BUFFER_EVENT_REBUFFER
, &hid
);
1234 /* Now we do the rebuffer */
1235 queue_reply(&buffering_queue
, 0);
1236 buffer_handle(handle_id
, 0);
1239 /* Backend to bufseek and bufadvance */
1240 static int seek_handle(struct memory_handle
*h
, size_t newpos
)
1242 if (newpos
> h
->filesize
) {
1243 /* access beyond the end of the file */
1244 return ERR_INVALID_VALUE
;
1246 else if ((newpos
< h
->offset
|| h
->offset
+ h
->available
<= newpos
) &&
1247 (newpos
< h
->filesize
|| h
->filerem
> 0)) {
1248 /* access before or after buffered data and not to end of file or file
1249 is not buffered to the end-- a rebuffer is needed. */
1250 struct buf_message_data parm
= { h
->id
, newpos
};
1251 return queue_send(&buffering_queue
, Q_REBUFFER_HANDLE
,
1255 h
->ridx
= ringbuf_add(h
->data
, newpos
- h
->offset
);
1261 /* Set reading index in handle (relatively to the start of the file).
1262 Access before the available data will trigger a rebuffer.
1263 Return 0 for success and for failure:
1264 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1265 ERR_INVALID_VALUE if the new requested position was beyond the end of
1268 int bufseek(int handle_id
, size_t newpos
)
1270 struct memory_handle
*h
= find_handle(handle_id
);
1272 return ERR_HANDLE_NOT_FOUND
;
1274 return seek_handle(h
, newpos
);
1277 /* Advance the reading index in a handle (relatively to its current position).
1278 Return 0 for success and for failure:
1279 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1280 ERR_INVALID_VALUE if the new requested position was beyond the end of
1283 int bufadvance(int handle_id
, off_t offset
)
1285 struct memory_handle
*h
= find_handle(handle_id
);
1287 return ERR_HANDLE_NOT_FOUND
;
1289 size_t newpos
= h
->offset
+ ringbuf_sub(h
->ridx
, h
->data
) + offset
;
1290 return seek_handle(h
, newpos
);
1293 /* Get the read position from the start of the file
1294 Returns the offset from byte 0 of the file and for failure:
1295 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1297 off_t
bufftell(int handle_id
)
1299 const struct memory_handle
*h
= find_handle(handle_id
);
1301 return ERR_HANDLE_NOT_FOUND
;
1302 return h
->offset
+ ringbuf_sub(h
->ridx
, h
->data
);
1305 /* Used by bufread and bufgetdata to prepare the buffer and retrieve the
1306 * actual amount of data available for reading. This function explicitly
1307 * does not check the validity of the input handle. It does do range checks
1308 * on size and returns a valid (and explicit) amount of data for reading */
1309 static struct memory_handle
*prep_bufdata(int handle_id
, size_t *size
,
1310 bool guardbuf_limit
)
1312 struct memory_handle
*h
= find_handle(handle_id
);
1318 size_t avail
= handle_size_available(h
);
1320 if (avail
== 0 && h
->filerem
== 0) {
1321 /* File is finished reading */
1328 if (realsize
== 0 || realsize
> avail
+ h
->filerem
)
1329 realsize
= avail
+ h
->filerem
;
1331 if (guardbuf_limit
&& h
->type
== TYPE_PACKET_AUDIO
1332 && realsize
> GUARD_BUFSIZE
) {
1333 logf("data request > guardbuf");
1334 /* If more than the size of the guardbuf is requested and this is a
1335 * bufgetdata, limit to guard_bufsize over the end of the buffer */
1336 realsize
= MIN(realsize
, buffer_len
- h
->ridx
+ GUARD_BUFSIZE
);
1337 /* this ensures *size <= buffer_len - h->ridx + GUARD_BUFSIZE */
1340 if (h
->filerem
> 0 && avail
< realsize
) {
1341 /* Data isn't ready. Request buffering */
1342 LOGFQUEUE("buffering >| Q_START_FILL %d",handle_id
);
1343 queue_send(&buffering_queue
, Q_START_FILL
, handle_id
);
1344 /* Wait for the data to be ready */
1348 /* it is not safe for a non-buffering thread to sleep while
1349 * holding a handle */
1350 h
= find_handle(handle_id
);
1351 if (!h
|| h
->signaled
!= 0)
1353 avail
= handle_size_available(h
);
1355 while (h
->filerem
> 0 && avail
< realsize
);
1358 *size
= MIN(realsize
, avail
);
1363 /* Note: It is safe for the thread responsible for handling the rebuffer
1364 * cleanup request to call bufread or bufgetdata only when the data will
1365 * be available-- not if it could be blocked waiting for it in prep_bufdata.
1366 * It should be apparent that if said thread is being forced to wait for
1367 * buffering but has not yet responded to the cleanup request, the space
1368 * can never be cleared to allow further reading of the file because it is
1369 * not listening to callbacks any longer. */
1371 /* Copy data from the given handle to the dest buffer.
1372 Return the number of bytes copied or < 0 for failure (handle not found).
1373 The caller is blocked until the requested amount of data is available.
1375 ssize_t
bufread(int handle_id
, size_t size
, void *dest
)
1377 const struct memory_handle
*h
;
1378 size_t adjusted_size
= size
;
1380 h
= prep_bufdata(handle_id
, &adjusted_size
, false);
1382 return ERR_HANDLE_NOT_FOUND
;
1384 if (h
->ridx
+ adjusted_size
> buffer_len
) {
1385 /* the data wraps around the end of the buffer */
1386 size_t read
= buffer_len
- h
->ridx
;
1387 memcpy(dest
, &buffer
[h
->ridx
], read
);
1388 memcpy(dest
+read
, buffer
, adjusted_size
- read
);
1390 memcpy(dest
, &buffer
[h
->ridx
], adjusted_size
);
1393 return adjusted_size
;
1396 /* Update the "data" pointer to make the handle's data available to the caller.
1397 Return the length of the available linear data or < 0 for failure (handle
1399 The caller is blocked until the requested amount of data is available.
1400 size is the amount of linear data requested. it can be 0 to get as
1402 The guard buffer may be used to provide the requested size. This means it's
1403 unsafe to request more than the size of the guard buffer.
1405 ssize_t
bufgetdata(int handle_id
, size_t size
, void **data
)
1407 const struct memory_handle
*h
;
1408 size_t adjusted_size
= size
;
1410 h
= prep_bufdata(handle_id
, &adjusted_size
, true);
1412 return ERR_HANDLE_NOT_FOUND
;
1414 if (h
->ridx
+ adjusted_size
> buffer_len
) {
1415 /* the data wraps around the end of the buffer :
1416 use the guard buffer to provide the requested amount of data. */
1417 size_t copy_n
= h
->ridx
+ adjusted_size
- buffer_len
;
1418 /* prep_bufdata ensures
1419 adjusted_size <= buffer_len - h->ridx + GUARD_BUFSIZE,
1420 so copy_n <= GUARD_BUFSIZE */
1421 memcpy(guard_buffer
, (const unsigned char *)buffer
, copy_n
);
1425 *data
= &buffer
[h
->ridx
];
1427 return adjusted_size
;
1430 ssize_t
bufgettail(int handle_id
, size_t size
, void **data
)
1434 const struct memory_handle
*h
;
1436 h
= find_handle(handle_id
);
1439 return ERR_HANDLE_NOT_FOUND
;
1442 return ERR_HANDLE_NOT_DONE
;
1444 /* We don't support tail requests of > guardbuf_size, for simplicity */
1445 if (size
> GUARD_BUFSIZE
)
1446 return ERR_INVALID_VALUE
;
1448 tidx
= ringbuf_sub(h
->widx
, size
);
1450 if (tidx
+ size
> buffer_len
) {
1451 size_t copy_n
= tidx
+ size
- buffer_len
;
1452 memcpy(guard_buffer
, (const unsigned char *)buffer
, copy_n
);
1455 *data
= &buffer
[tidx
];
1459 ssize_t
bufcuttail(int handle_id
, size_t size
)
1461 struct memory_handle
*h
;
1462 size_t adjusted_size
= size
;
1464 h
= find_handle(handle_id
);
1467 return ERR_HANDLE_NOT_FOUND
;
1470 return ERR_HANDLE_NOT_DONE
;
1472 if (h
->available
< adjusted_size
)
1473 adjusted_size
= h
->available
;
1475 h
->available
-= adjusted_size
;
1476 h
->filesize
-= adjusted_size
;
1477 h
->widx
= ringbuf_sub(h
->widx
, adjusted_size
);
1478 if (h
== cur_handle
)
1481 return adjusted_size
;
1486 SECONDARY EXPORTED FUNCTIONS
1487 ============================
1491 buf_handle_data_type
1500 These functions are exported, to allow interaction with the buffer.
1501 They take care of the content of the structs, and rely on the linked list
1502 management functions for all the actual handle management work.
1505 ssize_t
buf_handle_offset(int handle_id
)
1507 const struct memory_handle
*h
= find_handle(handle_id
);
1509 return ERR_HANDLE_NOT_FOUND
;
1513 void buf_set_base_handle(int handle_id
)
1515 mutex_lock(&llist_mutex
);
1516 base_handle_id
= handle_id
;
1517 mutex_unlock(&llist_mutex
);
1520 enum data_type
buf_handle_data_type(int handle_id
)
1522 const struct memory_handle
*h
= find_handle(handle_id
);
1524 return TYPE_UNKNOWN
;
1528 ssize_t
buf_handle_remaining(int handle_id
)
1530 const struct memory_handle
*h
= find_handle(handle_id
);
1532 return ERR_HANDLE_NOT_FOUND
;
1536 bool buf_is_handle(int handle_id
)
1538 return find_handle(handle_id
) != NULL
;
1541 bool buf_pin_handle(int handle_id
, bool pin
)
1543 struct memory_handle
*h
= find_handle(handle_id
);
1549 } else if (h
->pinned
> 0) {
1556 bool buf_signal_handle(int handle_id
, bool signal
)
1558 struct memory_handle
*h
= find_handle(handle_id
);
1562 h
->signaled
= signal
? 1 : 0;
1566 /* Return the size of the ringbuffer */
1567 size_t buf_length(void)
1572 /* Return the amount of buffer space used */
1573 size_t buf_used(void)
1578 void buf_set_watermark(size_t bytes
)
1580 conf_watermark
= bytes
;
1583 size_t buf_get_watermark(void)
1585 return BUF_WATERMARK
;
1588 #ifdef HAVE_IO_PRIORITY
1589 void buf_back_off_storage(bool back_off
)
1591 int priority
= back_off
?
1592 IO_PRIORITY_BACKGROUND
: IO_PRIORITY_IMMEDIATE
;
1593 thread_set_io_priority(buffering_thread_id
, priority
);
1597 /** -- buffer thread helpers -- **/
1598 static void shrink_buffer_inner(struct memory_handle
*h
)
1603 shrink_buffer_inner(h
->next
);
1608 static void shrink_buffer(void)
1610 logf("shrink_buffer()");
1611 shrink_buffer_inner(first_handle
);
1614 static void NORETURN_ATTR
buffering_thread(void)
1616 bool filling
= false;
1617 struct queue_event ev
;
1618 struct buf_message_data
*parm
;
1622 if (num_handles
> 0) {
1626 queue_wait_w_tmo(&buffering_queue
, &ev
, filling
? 1 : HZ
/2);
1630 queue_wait(&buffering_queue
, &ev
);
1636 LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev
.data
);
1638 queue_reply(&buffering_queue
, 1);
1639 if (buffer_handle((int)ev
.data
, 0)) {
1642 else if (num_handles
> 0 && conf_watermark
> 0) {
1643 update_data_counters(NULL
);
1644 if (data_counters
.useful
>= BUF_WATERMARK
) {
1645 send_event(BUFFER_EVENT_BUFFER_LOW
, NULL
);
1650 case Q_BUFFER_HANDLE
:
1651 LOGFQUEUE("buffering < Q_BUFFER_HANDLE %d", (int)ev
.data
);
1652 queue_reply(&buffering_queue
, 1);
1653 buffer_handle((int)ev
.data
, 0);
1656 case Q_REBUFFER_HANDLE
:
1657 parm
= (struct buf_message_data
*)ev
.data
;
1658 LOGFQUEUE("buffering < Q_REBUFFER_HANDLE %d %ld",
1659 parm
->handle_id
, parm
->data
);
1660 rebuffer_handle(parm
->handle_id
, parm
->data
);
1663 case Q_CLOSE_HANDLE
:
1664 LOGFQUEUE("buffering < Q_CLOSE_HANDLE %d", (int)ev
.data
);
1665 queue_reply(&buffering_queue
, close_handle((int)ev
.data
));
1668 case Q_HANDLE_ADDED
:
1669 LOGFQUEUE("buffering < Q_HANDLE_ADDED %d", (int)ev
.data
);
1670 /* A handle was added: the disk is spinning, so we can fill */
1675 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1679 if (num_handles
== 0 || !queue_empty(&buffering_queue
))
1682 update_data_counters(NULL
);
1684 /* TODO: This needs to be fixed to use the idle callback, disable it
1685 * for simplicity until its done right */
1687 /* If the disk is spinning, take advantage by filling the buffer */
1688 else if (storage_disk_is_active()) {
1689 if (num_handles
> 0 && data_counters
.useful
<= high_watermark
)
1690 send_event(BUFFER_EVENT_BUFFER_LOW
, 0);
1692 if (data_counters
.remaining
> 0 && BUF_USED
<= high_watermark
) {
1693 /* This is a new fill, shrink the buffer up first */
1696 filling
= fill_buffer();
1697 update_data_counters(NULL
);
1704 filling
= data_counters
.remaining
> 0 ? fill_buffer() : false;
1705 } else if (ev
.id
== SYS_TIMEOUT
) {
1706 if (data_counters
.useful
< BUF_WATERMARK
) {
1707 /* The buffer is low and we're idle, just watching the levels
1708 - call the callbacks to get new data */
1709 send_event(BUFFER_EVENT_BUFFER_LOW
, NULL
);
1711 /* Continue anything else we haven't finished - it might
1712 get booted off or stop early because the receiver hasn't
1713 had a chance to clear anything yet */
1714 if (data_counters
.remaining
> 0) {
1716 filling
= fill_buffer();
1723 void buffering_init(void)
1725 mutex_init(&llist_mutex
);
1727 /* Thread should absolutely not respond to USB because if it waits first,
1728 then it cannot properly service the handles and leaks will happen -
1729 this is a worker thread and shouldn't need to care about any system
1732 Whoever is using buffering should be responsible enough to clear all
1733 the handles at the right time. */
1734 queue_init(&buffering_queue
, false);
1735 buffering_thread_id
= create_thread( buffering_thread
, buffering_stack
,
1736 sizeof(buffering_stack
), CREATE_THREAD_FROZEN
,
1737 buffering_thread_name
IF_PRIO(, PRIORITY_BUFFERING
)
1740 queue_enable_queue_send(&buffering_queue
, &buffering_queue_sender_list
,
1741 buffering_thread_id
);
1744 /* Initialise the buffering subsystem */
1745 bool buffering_reset(char *buf
, size_t buflen
)
1747 /* Wraps of storage-aligned data must also be storage aligned,
1748 thus buf and buflen must be a aligned to an integer multiple of
1749 the storage alignment */
1751 buflen
-= GUARD_BUFSIZE
;
1753 STORAGE_ALIGN_BUFFER(buf
, buflen
);
1755 if (!buf
|| !buflen
)
1759 buffer_len
= buflen
;
1760 guard_buffer
= buf
+ buflen
;
1765 first_handle
= NULL
;
1767 cached_handle
= NULL
;
1769 base_handle_id
= -1;
1771 /* Set the high watermark as 75% full...or 25% empty :)
1772 This is the greatest fullness that will trigger low-buffer events
1773 no matter what the setting because high-bitrate files can have
1774 ludicrous margins that even exceed the buffer size - most common
1775 with a huge anti-skip buffer but even without that setting,
1776 staying constantly active in buffering is pointless */
1777 high_watermark
= 3*buflen
/ 4;
1779 thread_thaw(buffering_thread_id
);
1784 void buffering_get_debugdata(struct buffering_debug
*dbgdata
)
1786 struct data_counters dc
;
1787 update_data_counters(&dc
);
1788 dbgdata
->num_handles
= num_handles
;
1789 dbgdata
->data_rem
= dc
.remaining
;
1790 dbgdata
->wasted_space
= dc
.wasted
;
1791 dbgdata
->buffered_data
= dc
.buffered
;
1792 dbgdata
->useful_data
= dc
.useful
;
1793 dbgdata
->watermark
= BUF_WATERMARK
;