summaryrefslogtreecommitdiff
path: root/apps/buffering.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/buffering.c')
-rw-r--r--apps/buffering.c288
1 files changed, 204 insertions, 84 deletions
diff --git a/apps/buffering.c b/apps/buffering.c
index 578f0f261a..a130a787ff 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -58,7 +58,7 @@
58#define GUARD_BUFSIZE (32*1024) 58#define GUARD_BUFSIZE (32*1024)
59 59
60/* Define LOGF_ENABLE to enable logf output in this file */ 60/* Define LOGF_ENABLE to enable logf output in this file */
61/*#define LOGF_ENABLE*/ 61/* #define LOGF_ENABLE */
62#include "logf.h" 62#include "logf.h"
63 63
64/* macros to enable logf for queues 64/* macros to enable logf for queues
@@ -82,8 +82,6 @@
82#define LOGFQUEUE_SYS_TIMEOUT(...) 82#define LOGFQUEUE_SYS_TIMEOUT(...)
83#endif 83#endif
84 84
85/* default point to start buffer refill */
86#define BUFFERING_DEFAULT_WATERMARK (1024*128)
87/* amount of data to read in one read() call */ 85/* amount of data to read in one read() call */
88#define BUFFERING_DEFAULT_FILECHUNK (1024*32) 86#define BUFFERING_DEFAULT_FILECHUNK (1024*32)
89 87
@@ -94,6 +92,8 @@
94struct memory_handle { 92struct memory_handle {
95 int id; /* A unique ID for the handle */ 93 int id; /* A unique ID for the handle */
96 enum data_type type; /* Type of data buffered with this 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 */ 97 char path[MAX_PATH]; /* Path if data originated in a file */
98 int fd; /* File descriptor to path (-1 if closed) */ 98 int fd; /* File descriptor to path (-1 if closed) */
99 size_t data; /* Start index of the handle's data buffer */ 99 size_t data; /* Start index of the handle's data buffer */
@@ -125,9 +125,7 @@ static volatile size_t buf_ridx; /* current reading position */
125 125
126/* Configuration */ 126/* Configuration */
127static size_t conf_watermark = 0; /* Level to trigger filebuf fill */ 127static size_t conf_watermark = 0; /* Level to trigger filebuf fill */
128#if MEMORYSIZE > 8
129static size_t high_watermark = 0; /* High watermark for rebuffer */ 128static size_t high_watermark = 0; /* High watermark for rebuffer */
130#endif
131 129
132/* current memory handle in the linked list. NULL when the list is empty. */ 130/* current memory handle in the linked list. NULL when the list is empty. */
133static struct memory_handle *cur_handle; 131static struct memory_handle *cur_handle;
@@ -162,7 +160,6 @@ enum
162 Q_REBUFFER_HANDLE, /* Request reset and rebuffering of a handle at a new 160 Q_REBUFFER_HANDLE, /* Request reset and rebuffering of a handle at a new
163 file starting position. */ 161 file starting position. */
164 Q_CLOSE_HANDLE, /* Request closing a handle */ 162 Q_CLOSE_HANDLE, /* Request closing a handle */
165 Q_BASE_HANDLE, /* Set the reference handle for buf_useful_data */
166 163
167 /* Configuration: */ 164 /* Configuration: */
168 Q_START_FILL, /* Request that the buffering thread initiate a buffer 165 Q_START_FILL, /* Request that the buffering thread initiate a buffer
@@ -222,6 +219,9 @@ static inline ssize_t ringbuf_add_cross(uintptr_t p1, size_t v, uintptr_t p2)
222/* Bytes available in the buffer */ 219/* Bytes available in the buffer */
223#define BUF_USED ringbuf_sub(buf_widx, buf_ridx) 220#define BUF_USED ringbuf_sub(buf_widx, buf_ridx)
224 221
222/* Real buffer watermark */
223#define BUF_WATERMARK MIN(conf_watermark, high_watermark)
224
225/* 225/*
226LINKED LIST MANAGEMENT 226LINKED LIST MANAGEMENT
227====================== 227======================
@@ -313,6 +313,12 @@ static struct memory_handle *add_handle(size_t data_size, bool can_wrap,
313 /* Prevent buffering thread from looking at it */ 313 /* Prevent buffering thread from looking at it */
314 new_handle->filerem = 0; 314 new_handle->filerem = 0;
315 315
316 /* Handle can be moved by default */
317 new_handle->pinned = 0;
318
319 /* Handle data can be waited for by default */
320 new_handle->signaled = 0;
321
316 /* only advance the buffer write index of the size of the struct */ 322 /* only advance the buffer write index of the size of the struct */
317 buf_widx = ringbuf_add(buf_widx, sizeof(struct memory_handle)); 323 buf_widx = ringbuf_add(buf_widx, sizeof(struct memory_handle));
318 324
@@ -364,6 +370,9 @@ static bool rm_handle(const struct memory_handle *h)
364 buf_widx = cur_handle->widx; 370 buf_widx = cur_handle->widx;
365 } 371 }
366 } else { 372 } else {
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);
367 return false; 376 return false;
368 } 377 }
369 } 378 }
@@ -385,8 +394,7 @@ static struct memory_handle *find_handle(int handle_id)
385 394
386 /* simple caching because most of the time the requested handle 395 /* simple caching because most of the time the requested handle
387 will either be the same as the last, or the one after the last */ 396 will either be the same as the last, or the one after the last */
388 if (cached_handle) 397 if (cached_handle) {
389 {
390 if (cached_handle->id == handle_id) { 398 if (cached_handle->id == handle_id) {
391 return cached_handle; 399 return cached_handle;
392 } else if (cached_handle->next && 400 } else if (cached_handle->next &&
@@ -618,20 +626,22 @@ static void update_data_counters(struct data_counters *dc)
618static inline bool buffer_is_low(void) 626static inline bool buffer_is_low(void)
619{ 627{
620 update_data_counters(NULL); 628 update_data_counters(NULL);
621 return data_counters.useful < (conf_watermark / 2); 629 return data_counters.useful < BUF_WATERMARK / 2;
622} 630}
623 631
624/* Q_BUFFER_HANDLE event and buffer data for the given handle. 632/* Q_BUFFER_HANDLE event and buffer data for the given handle.
625 Return whether or not the buffering should continue explicitly. */ 633 Return whether or not the buffering should continue explicitly. */
626static bool buffer_handle(int handle_id, size_t to_buffer) 634static bool buffer_handle(int handle_id, size_t to_buffer)
627{ 635{
628 logf("buffer_handle(%d)", handle_id); 636 logf("buffer_handle(%d, %lu)", handle_id, (unsigned long)to_buffer);
629 struct memory_handle *h = find_handle(handle_id); 637 struct memory_handle *h = find_handle(handle_id);
630 bool stop = false; 638 bool stop = false;
631 639
632 if (!h) 640 if (!h)
633 return true; 641 return true;
634 642
643 logf(" type: %d", (int)h->type);
644
635 if (h->filerem == 0) { 645 if (h->filerem == 0) {
636 /* nothing left to buffer */ 646 /* nothing left to buffer */
637 return true; 647 return true;
@@ -659,13 +669,13 @@ static bool buffer_handle(int handle_id, size_t to_buffer)
659 if (!get_metadata((struct mp3entry *)(buffer + h->data), 669 if (!get_metadata((struct mp3entry *)(buffer + h->data),
660 h->fd, h->path)) { 670 h->fd, h->path)) {
661 /* metadata parsing failed: clear the buffer. */ 671 /* metadata parsing failed: clear the buffer. */
662 memset(buffer + h->data, 0, sizeof(struct mp3entry)); 672 wipe_mp3entry((struct mp3entry *)(buffer + h->data));
663 } 673 }
664 close(h->fd); 674 close(h->fd);
665 h->fd = -1; 675 h->fd = -1;
666 h->filerem = 0; 676 h->filerem = 0;
667 h->available = sizeof(struct mp3entry); 677 h->available = sizeof(struct mp3entry);
668 h->widx += sizeof(struct mp3entry); 678 h->widx = ringbuf_add(h->widx, sizeof(struct mp3entry));
669 send_event(BUFFER_EVENT_FINISHED, &handle_id); 679 send_event(BUFFER_EVENT_FINISHED, &handle_id);
670 return true; 680 return true;
671 } 681 }
@@ -698,7 +708,7 @@ static bool buffer_handle(int handle_id, size_t to_buffer)
698 break; 708 break;
699 } 709 }
700 710
701 DEBUGF("File ended %ld bytes early\n", (long)h->filerem); 711 logf("File ended %ld bytes early\n", (long)h->filerem);
702 h->filesize -= h->filerem; 712 h->filesize -= h->filerem;
703 h->filerem = 0; 713 h->filerem = 0;
704 break; 714 break;
@@ -770,22 +780,31 @@ static bool close_handle(int handle_id)
770 part of its data buffer or by moving all the data. */ 780 part of its data buffer or by moving all the data. */
771static void shrink_handle(struct memory_handle *h) 781static void shrink_handle(struct memory_handle *h)
772{ 782{
773 size_t delta;
774
775 if (!h) 783 if (!h)
776 return; 784 return;
777 785
778 if (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET || 786 if (h->type == TYPE_PACKET_AUDIO) {
779 h->type == TYPE_BITMAP || h->type == TYPE_CODEC || 787 /* only move the handle struct */
780 h->type == TYPE_ATOMIC_AUDIO) 788 /* data is pinned by default - if we start moving packet audio,
781 { 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);
792
793 /* The value of delta might change for alignment reasons */
794 if (!move_handle(&h, &delta, 0, true))
795 return;
796
797 h->data = ringbuf_add(h->data, delta);
798 h->available -= delta;
799 h->offset += delta;
800 } else {
782 /* metadata handle: we can move all of it */ 801 /* metadata handle: we can move all of it */
783 if (!h->next || h->filerem != 0) 802 if (h->pinned || !h->next || h->filerem != 0)
784 return; /* Last handle or not finished loading */ 803 return; /* Pinned, last handle or not finished loading */
785 804
786 uintptr_t handle_distance = 805 uintptr_t handle_distance =
787 ringbuf_sub(ringbuf_offset(h->next), h->data); 806 ringbuf_sub(ringbuf_offset(h->next), h->data);
788 delta = handle_distance - h->available; 807 size_t delta = handle_distance - h->available;
789 808
790 /* The value of delta might change for alignment reasons */ 809 /* The value of delta might change for alignment reasons */
791 if (!move_handle(&h, &delta, h->available, h->type==TYPE_CODEC)) 810 if (!move_handle(&h, &delta, h->available, h->type==TYPE_CODEC))
@@ -806,15 +825,6 @@ static void shrink_handle(struct memory_handle *h)
806 struct bitmap *bmp = (struct bitmap *)&buffer[h->data]; 825 struct bitmap *bmp = (struct bitmap *)&buffer[h->data];
807 bmp->data = &buffer[h->data + sizeof(struct bitmap)]; 826 bmp->data = &buffer[h->data + sizeof(struct bitmap)];
808 } 827 }
809 } else {
810 /* only move the handle struct */
811 delta = ringbuf_sub(h->ridx, h->data);
812 if (!move_handle(&h, &delta, 0, true))
813 return;
814
815 h->data = ringbuf_add(h->data, delta);
816 h->available -= delta;
817 h->offset += delta;
818 } 828 }
819} 829}
820 830
@@ -962,6 +972,8 @@ int bufopen(const char *file, size_t offset, enum data_type type,
962 mutex_unlock(&llist_mutex); 972 mutex_unlock(&llist_mutex);
963 return handle_id; 973 return handle_id;
964 } 974 }
975 else if (type == TYPE_UNKNOWN)
976 return ERR_UNSUPPORTED_TYPE;
965#ifdef APPLICATION 977#ifdef APPLICATION
966 /* loading code from memory is not supported in application builds */ 978 /* loading code from memory is not supported in application builds */
967 else if (type == TYPE_CODEC) 979 else if (type == TYPE_CODEC)
@@ -1083,7 +1095,12 @@ int bufopen(const char *file, size_t offset, enum data_type type,
1083*/ 1095*/
1084int bufalloc(const void *src, size_t size, enum data_type type) 1096int bufalloc(const void *src, size_t size, enum data_type type)
1085{ 1097{
1086 int handle_id = ERR_BUFFER_FULL; 1098 int handle_id;
1099
1100 if (type == TYPE_UNKNOWN)
1101 return ERR_UNSUPPORTED_TYPE;
1102
1103 handle_id = ERR_BUFFER_FULL;
1087 1104
1088 mutex_lock(&llist_mutex); 1105 mutex_lock(&llist_mutex);
1089 1106
@@ -1124,7 +1141,14 @@ int bufalloc(const void *src, size_t size, enum data_type type)
1124bool bufclose(int handle_id) 1141bool bufclose(int handle_id)
1125{ 1142{
1126 logf("bufclose(%d)", handle_id); 1143 logf("bufclose(%d)", handle_id);
1127 1144#if 0
1145 /* Don't interrupt the buffering thread if the handle is already
1146 stale */
1147 if (!find_handle(handle_id)) {
1148 logf(" handle already closed");
1149 return true;
1150 }
1151#endif
1128 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id); 1152 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id);
1129 return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id); 1153 return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id);
1130} 1154}
@@ -1236,9 +1260,10 @@ static int seek_handle(struct memory_handle *h, size_t newpos)
1236 1260
1237/* Set reading index in handle (relatively to the start of the file). 1261/* Set reading index in handle (relatively to the start of the file).
1238 Access before the available data will trigger a rebuffer. 1262 Access before the available data will trigger a rebuffer.
1239 Return 0 for success and < 0 for failure: 1263 Return 0 for success and for failure:
1240 -1 if the handle wasn't found 1264 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1241 -2 if the new requested position was beyond the end of the file 1265 ERR_INVALID_VALUE if the new requested position was beyond the end of
1266 the file
1242*/ 1267*/
1243int bufseek(int handle_id, size_t newpos) 1268int bufseek(int handle_id, size_t newpos)
1244{ 1269{
@@ -1250,7 +1275,11 @@ int bufseek(int handle_id, size_t newpos)
1250} 1275}
1251 1276
1252/* Advance the reading index in a handle (relatively to its current position). 1277/* Advance the reading index in a handle (relatively to its current position).
1253 Return 0 for success and < 0 for failure */ 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
1281 the file
1282 */
1254int bufadvance(int handle_id, off_t offset) 1283int bufadvance(int handle_id, off_t offset)
1255{ 1284{
1256 struct memory_handle *h = find_handle(handle_id); 1285 struct memory_handle *h = find_handle(handle_id);
@@ -1261,6 +1290,18 @@ int bufadvance(int handle_id, off_t offset)
1261 return seek_handle(h, newpos); 1290 return seek_handle(h, newpos);
1262} 1291}
1263 1292
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
1296 */
1297off_t bufftell(int handle_id)
1298{
1299 const struct memory_handle *h = find_handle(handle_id);
1300 if (!h)
1301 return ERR_HANDLE_NOT_FOUND;
1302 return h->offset + ringbuf_sub(h->ridx, h->data);
1303}
1304
1264/* Used by bufread and bufgetdata to prepare the buffer and retrieve the 1305/* Used by bufread and bufgetdata to prepare the buffer and retrieve the
1265 * actual amount of data available for reading. This function explicitly 1306 * actual amount of data available for reading. This function explicitly
1266 * does not check the validity of the input handle. It does do range checks 1307 * does not check the validity of the input handle. It does do range checks
@@ -1306,7 +1347,7 @@ static struct memory_handle *prep_bufdata(int handle_id, size_t *size,
1306 /* it is not safe for a non-buffering thread to sleep while 1347 /* it is not safe for a non-buffering thread to sleep while
1307 * holding a handle */ 1348 * holding a handle */
1308 h = find_handle(handle_id); 1349 h = find_handle(handle_id);
1309 if (!h) 1350 if (!h || h->signaled != 0)
1310 return NULL; 1351 return NULL;
1311 avail = handle_size_available(h); 1352 avail = handle_size_available(h);
1312 } 1353 }
@@ -1447,9 +1488,14 @@ SECONDARY EXPORTED FUNCTIONS
1447buf_handle_offset 1488buf_handle_offset
1448buf_request_buffer_handle 1489buf_request_buffer_handle
1449buf_set_base_handle 1490buf_set_base_handle
1491buf_handle_data_type
1492buf_is_handle
1493buf_pin_handle
1494buf_signal_handle
1495buf_length
1450buf_used 1496buf_used
1451register_buffering_callback 1497buf_set_watermark
1452unregister_buffering_callback 1498buf_get_watermark
1453 1499
1454These functions are exported, to allow interaction with the buffer. 1500These functions are exported, to allow interaction with the buffer.
1455They take care of the content of the structs, and rely on the linked list 1501They take care of the content of the structs, and rely on the linked list
@@ -1472,8 +1518,61 @@ void buf_request_buffer_handle(int handle_id)
1472 1518
1473void buf_set_base_handle(int handle_id) 1519void buf_set_base_handle(int handle_id)
1474{ 1520{
1475 LOGFQUEUE("buffering > Q_BASE_HANDLE %d", handle_id); 1521 mutex_lock(&llist_mutex);
1476 queue_post(&buffering_queue, Q_BASE_HANDLE, handle_id); 1522 base_handle_id = handle_id;
1523 mutex_unlock(&llist_mutex);
1524}
1525
1526enum data_type buf_handle_data_type(int handle_id)
1527{
1528 const struct memory_handle *h = find_handle(handle_id);
1529 if (!h)
1530 return TYPE_UNKNOWN;
1531 return h->type;
1532}
1533
1534ssize_t buf_handle_remaining(int handle_id)
1535{
1536 const struct memory_handle *h = find_handle(handle_id);
1537 if (!h)
1538 return ERR_HANDLE_NOT_FOUND;
1539 return h->filerem;
1540}
1541
1542bool buf_is_handle(int handle_id)
1543{
1544 return find_handle(handle_id) != NULL;
1545}
1546
1547bool buf_pin_handle(int handle_id, bool pin)
1548{
1549 struct memory_handle *h = find_handle(handle_id);
1550 if (!h)
1551 return false;
1552
1553 if (pin) {
1554 h->pinned++;
1555 } else if (h->pinned > 0) {
1556 h->pinned--;
1557 }
1558
1559 return true;
1560}
1561
1562bool buf_signal_handle(int handle_id, bool signal)
1563{
1564 struct memory_handle *h = find_handle(handle_id);
1565 if (!h)
1566 return false;
1567
1568 h->signaled = signal ? 1 : 0;
1569 return true;
1570}
1571
1572/* Return the size of the ringbuffer */
1573size_t buf_length(void)
1574{
1575 return buffer_len;
1477} 1576}
1478 1577
1479/* Return the amount of buffer space used */ 1578/* Return the amount of buffer space used */
@@ -1487,6 +1586,21 @@ void buf_set_watermark(size_t bytes)
1487 conf_watermark = bytes; 1586 conf_watermark = bytes;
1488} 1587}
1489 1588
1589size_t buf_get_watermark(void)
1590{
1591 return BUF_WATERMARK;
1592}
1593
1594#ifdef HAVE_IO_PRIORITY
1595void buf_back_off_storage(bool back_off)
1596{
1597 int priority = back_off ?
1598 IO_PRIORITY_BACKGROUND : IO_PRIORITY_IMMEDIATE;
1599 thread_set_io_priority(buffering_thread_id, priority);
1600}
1601#endif
1602
1603/** -- buffer thread helpers -- **/
1490static void shrink_buffer_inner(struct memory_handle *h) 1604static void shrink_buffer_inner(struct memory_handle *h)
1491{ 1605{
1492 if (h == NULL) 1606 if (h == NULL)
@@ -1503,7 +1617,7 @@ static void shrink_buffer(void)
1503 shrink_buffer_inner(first_handle); 1617 shrink_buffer_inner(first_handle);
1504} 1618}
1505 1619
1506void buffering_thread(void) 1620static void NORETURN_ATTR buffering_thread(void)
1507{ 1621{
1508 bool filling = false; 1622 bool filling = false;
1509 struct queue_event ev; 1623 struct queue_event ev;
@@ -1511,19 +1625,21 @@ void buffering_thread(void)
1511 1625
1512 while (true) 1626 while (true)
1513 { 1627 {
1514 if (!filling) { 1628 if (num_handles > 0) {
1629 if (!filling) {
1630 cancel_cpu_boost();
1631 }
1632 queue_wait_w_tmo(&buffering_queue, &ev, filling ? 1 : HZ/2);
1633 } else {
1634 filling = false;
1515 cancel_cpu_boost(); 1635 cancel_cpu_boost();
1636 queue_wait(&buffering_queue, &ev);
1516 } 1637 }
1517 1638
1518 queue_wait_w_tmo(&buffering_queue, &ev, filling ? 5 : HZ/2);
1519
1520 switch (ev.id) 1639 switch (ev.id)
1521 { 1640 {
1522 case Q_START_FILL: 1641 case Q_START_FILL:
1523 LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data); 1642 LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data);
1524 /* Call buffer callbacks here because this is one of two ways
1525 * to begin a full buffer fill */
1526 send_event(BUFFER_EVENT_BUFFER_LOW, 0);
1527 shrink_buffer(); 1643 shrink_buffer();
1528 queue_reply(&buffering_queue, 1); 1644 queue_reply(&buffering_queue, 1);
1529 filling |= buffer_handle((int)ev.data, 0); 1645 filling |= buffer_handle((int)ev.data, 0);
@@ -1553,36 +1669,21 @@ void buffering_thread(void)
1553 filling = true; 1669 filling = true;
1554 break; 1670 break;
1555 1671
1556 case Q_BASE_HANDLE:
1557 LOGFQUEUE("buffering < Q_BASE_HANDLE %d", (int)ev.data);
1558 base_handle_id = (int)ev.data;
1559 break;
1560
1561#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1562 case SYS_USB_CONNECTED:
1563 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
1564 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1565 usb_wait_for_disconnect(&buffering_queue);
1566 break;
1567#endif
1568
1569 case SYS_TIMEOUT: 1672 case SYS_TIMEOUT:
1570 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT"); 1673 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1571 break; 1674 break;
1572 } 1675 }
1573 1676
1574 update_data_counters(NULL); 1677 if (num_handles == 0 || !queue_empty(&buffering_queue))
1575 1678 continue;
1576 /* If the buffer is low, call the callbacks to get new data */
1577 if (num_handles > 0 && data_counters.useful <= conf_watermark)
1578 send_event(BUFFER_EVENT_BUFFER_LOW, 0);
1579 1679
1680 update_data_counters(NULL);
1580#if 0 1681#if 0
1581 /* TODO: This needs to be fixed to use the idle callback, disable it 1682 /* TODO: This needs to be fixed to use the idle callback, disable it
1582 * for simplicity until its done right */ 1683 * for simplicity until its done right */
1583#if MEMORYSIZE > 8 1684#if MEMORYSIZE > 8
1584 /* If the disk is spinning, take advantage by filling the buffer */ 1685 /* If the disk is spinning, take advantage by filling the buffer */
1585 else if (storage_disk_is_active() && queue_empty(&buffering_queue)) { 1686 else if (storage_disk_is_active()) {
1586 if (num_handles > 0 && data_counters.useful <= high_watermark) 1687 if (num_handles > 0 && data_counters.useful <= high_watermark)
1587 send_event(BUFFER_EVENT_BUFFER_LOW, 0); 1688 send_event(BUFFER_EVENT_BUFFER_LOW, 0);
1588 1689
@@ -1597,15 +1698,23 @@ void buffering_thread(void)
1597#endif 1698#endif
1598#endif 1699#endif
1599 1700
1600 if (queue_empty(&buffering_queue)) { 1701 if (filling) {
1601 if (filling) { 1702 if (data_counters.remaining > 0 && BUF_USED < buffer_len) {
1602 if (data_counters.remaining > 0 && BUF_USED < buffer_len) 1703 filling = fill_buffer();
1603 filling = fill_buffer(); 1704 }
1604 else if (data_counters.remaining == 0) 1705 else if (data_counters.remaining == 0) {
1605 filling = false; 1706 filling = false;
1606 } else if (ev.id == SYS_TIMEOUT) { 1707 }
1607 if (data_counters.remaining > 0 && 1708 } else if (ev.id == SYS_TIMEOUT) {
1608 data_counters.useful <= conf_watermark) { 1709 if (data_counters.useful < BUF_WATERMARK) {
1710 /* The buffer is low and we're idle, just watching the levels
1711 - call the callbacks to get new data */
1712 send_event(BUFFER_EVENT_BUFFER_LOW, NULL);
1713
1714 /* Continue anything else we haven't finished - it might
1715 get booted off or stop early because the receiver hasn't
1716 had a chance to clear anything yet */
1717 if (data_counters.remaining > 0) {
1609 shrink_buffer(); 1718 shrink_buffer();
1610 filling = fill_buffer(); 1719 filling = fill_buffer();
1611 } 1720 }
@@ -1618,9 +1727,14 @@ void buffering_init(void)
1618{ 1727{
1619 mutex_init(&llist_mutex); 1728 mutex_init(&llist_mutex);
1620 1729
1621 conf_watermark = BUFFERING_DEFAULT_WATERMARK; 1730 /* Thread should absolutely not respond to USB because if it waits first,
1622 1731 then it cannot properly service the handles and leaks will happen -
1623 queue_init(&buffering_queue, true); 1732 this is a worker thread and shouldn't need to care about any system
1733 notifications.
1734 ***
1735 Whoever is using buffering should be responsible enough to clear all
1736 the handles at the right time. */
1737 queue_init(&buffering_queue, false);
1624 buffering_thread_id = create_thread( buffering_thread, buffering_stack, 1738 buffering_thread_id = create_thread( buffering_thread, buffering_stack,
1625 sizeof(buffering_stack), CREATE_THREAD_FROZEN, 1739 sizeof(buffering_stack), CREATE_THREAD_FROZEN,
1626 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING) 1740 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING)
@@ -1636,6 +1750,9 @@ bool buffering_reset(char *buf, size_t buflen)
1636 /* Wraps of storage-aligned data must also be storage aligned, 1750 /* Wraps of storage-aligned data must also be storage aligned,
1637 thus buf and buflen must be a aligned to an integer multiple of 1751 thus buf and buflen must be a aligned to an integer multiple of
1638 the storage alignment */ 1752 the storage alignment */
1753
1754 buflen -= GUARD_BUFSIZE;
1755
1639 STORAGE_ALIGN_BUFFER(buf, buflen); 1756 STORAGE_ALIGN_BUFFER(buf, buflen);
1640 1757
1641 if (!buf || !buflen) 1758 if (!buf || !buflen)
@@ -1654,10 +1771,13 @@ bool buffering_reset(char *buf, size_t buflen)
1654 num_handles = 0; 1771 num_handles = 0;
1655 base_handle_id = -1; 1772 base_handle_id = -1;
1656 1773
1657 /* Set the high watermark as 75% full...or 25% empty :) */ 1774 /* Set the high watermark as 75% full...or 25% empty :)
1658#if MEMORYSIZE > 8 1775 This is the greatest fullness that will trigger low-buffer events
1776 no matter what the setting because high-bitrate files can have
1777 ludicrous margins that even exceed the buffer size - most common
1778 with a huge anti-skip buffer but even without that setting,
1779 staying constantly active in buffering is pointless */
1659 high_watermark = 3*buflen / 4; 1780 high_watermark = 3*buflen / 4;
1660#endif
1661 1781
1662 thread_thaw(buffering_thread_id); 1782 thread_thaw(buffering_thread_id);
1663 1783
@@ -1673,5 +1793,5 @@ void buffering_get_debugdata(struct buffering_debug *dbgdata)
1673 dbgdata->wasted_space = dc.wasted; 1793 dbgdata->wasted_space = dc.wasted;
1674 dbgdata->buffered_data = dc.buffered; 1794 dbgdata->buffered_data = dc.buffered;
1675 dbgdata->useful_data = dc.useful; 1795 dbgdata->useful_data = dc.useful;
1676 dbgdata->watermark = conf_watermark; 1796 dbgdata->watermark = BUF_WATERMARK;
1677} 1797}