summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/buffering.c1238
-rw-r--r--apps/buffering.h120
-rw-r--r--apps/debug_menu.c51
-rw-r--r--apps/playback.c1291
-rw-r--r--apps/playback.h4
-rw-r--r--firmware/export/thread.h2
7 files changed, 1787 insertions, 920 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 3686fc29f7..dc5b987b61 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -14,6 +14,7 @@ menus/display_menu.c
14menus/theme_menu.c 14menus/theme_menu.c
15#if CONFIG_CODEC == SWCODEC 15#if CONFIG_CODEC == SWCODEC
16menus/eq_menu.c 16menus/eq_menu.c
17buffering.c
17#endif 18#endif
18menus/main_menu.c 19menus/main_menu.c
19menus/playback_menu.c 20menus/playback_menu.c
diff --git a/apps/buffering.c b/apps/buffering.c
new file mode 100644
index 0000000000..7ebcbae39d
--- /dev/null
+++ b/apps/buffering.c
@@ -0,0 +1,1238 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Nicolas Pennequin
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "config.h"
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include "buffering.h"
26
27#include "ata.h"
28#include "system.h"
29#include "thread.h"
30#include "file.h"
31#include "panic.h"
32#include "memory.h"
33#include "lcd.h"
34#include "font.h"
35#include "button.h"
36#include "kernel.h"
37#include "tree.h"
38#include "debug.h"
39#include "sprintf.h"
40#include "settings.h"
41#include "codecs.h"
42#include "audio.h"
43#include "mp3_playback.h"
44#include "usb.h"
45#include "status.h"
46#include "screens.h"
47#include "playlist.h"
48#include "playback.h"
49#include "pcmbuf.h"
50#include "buffer.h"
51
52#ifdef SIMULATOR
53#define ata_disk_is_active() 1
54#endif
55
56#if MEM > 1
57#define GUARD_BUFSIZE (32*1024)
58#else
59#define GUARD_BUFSIZE (8*1024)
60#endif
61
62/* Define LOGF_ENABLE to enable logf output in this file */
63/*#define LOGF_ENABLE*/
64#include "logf.h"
65
66/* macros to enable logf for queues
67 logging on SYS_TIMEOUT can be disabled */
68#ifdef SIMULATOR
69/* Define this for logf output of all queuing except SYS_TIMEOUT */
70#define BUFFERING_LOGQUEUES
71/* Define this to logf SYS_TIMEOUT messages */
72/* #define BUFFERING_LOGQUEUES_SYS_TIMEOUT */
73#endif
74
75#ifdef BUFFERING_LOGQUEUES
76#define LOGFQUEUE logf
77#else
78#define LOGFQUEUE(...)
79#endif
80
81#ifdef BUFFERING_LOGQUEUES_SYS_TIMEOUT
82#define LOGFQUEUE_SYS_TIMEOUT logf
83#else
84#define LOGFQUEUE_SYS_TIMEOUT(...)
85#endif
86
87/* default point to start buffer refill */
88#define BUFFERING_DEFAULT_WATERMARK (1024*512)
89/* amount of data to read in one read() call */
90#define BUFFERING_DEFAULT_FILECHUNK (1024*32)
91/* point at which the file buffer will fight for CPU time */
92#define BUFFERING_CRITICAL_LEVEL (1024*128)
93
94
95/* Ring buffer helper macros */
96/* Buffer pointer (p) plus value (v), wrapped if necessary */
97#define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)
98/* Buffer pointer (p) minus value (v), wrapped if necessary */
99#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)
100/* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
101#define RINGBUF_ADD_CROSS(p1,v,p2) \
102((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)
103/* Bytes available in the buffer */
104#define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)
105
106struct memory_handle {
107 int id; /* A unique ID for the handle */
108 enum data_type type;
109 char path[MAX_PATH];
110 int fd;
111 size_t data; /* Start index of the handle's data buffer */
112 volatile size_t ridx; /* Current read pointer, relative to the main buffer */
113 size_t widx; /* Current write pointer */
114 size_t filesize; /* File total length */
115 size_t filerem; /* Remaining bytes of file NOT in buffer */
116 volatile size_t available; /* Available bytes to read from buffer */
117 size_t offset; /* Offset at which we started reading the file */
118 struct memory_handle *next;
119};
120/* at all times, we have: filesize == offset + available + filerem */
121
122
123static char *buffer;
124static char *guard_buffer;
125
126static size_t buffer_len;
127
128static volatile size_t buf_widx; /* current writing position */
129static volatile size_t buf_ridx; /* current reading position */
130/* buf_*idx are values relative to the buffer, not real pointers. */
131
132/* Configuration */
133static size_t conf_watermark = 0; /* Level to trigger filebuf fill */
134static size_t conf_filechunk = 0; /* Largest chunk the codec accepts */
135static size_t conf_preseek = 0; /* Codec pre-seek margin */
136#if MEM > 8
137static size_t high_watermark = 0; /* High watermark for rebuffer */
138#endif
139
140/* current memory handle in the linked list. NULL when the list is empty. */
141static struct memory_handle *cur_handle;
142/* first memory handle in the linked list. NULL when the list is empty. */
143static struct memory_handle *first_handle;
144
145static int num_handles; /* number of handles in the list */
146
147static int base_handle_id;
148
149static struct mutex llist_mutex;
150
151/* Handle cache (makes find_handle faster).
152 This needs be to be global so that move_handle can invalidate it. */
153static struct memory_handle *cached_handle = NULL;
154
155static buffer_low_callback buffer_low_callback_funcs[MAX_BUF_CALLBACKS];
156static int buffer_callback_count = 0;
157
158static struct {
159 size_t remaining; /* Amount of data needing to be buffered */
160 size_t wasted; /* Amount of space available for freeing */
161 size_t buffered; /* Amount of data currently in the buffer */
162 size_t useful; /* Amount of data still useful to the user */
163} data_counters;
164
165
166/* Messages available to communicate with the buffering thread */
167enum {
168 Q_BUFFER_HANDLE = 1, /* Request buffering of a handle */
169 Q_RESET_HANDLE, /* (internal) Request resetting of a handle to its
170 offset (the offset has to be set beforehand) */
171 Q_CLOSE_HANDLE, /* Request closing a handle */
172 Q_BASE_HANDLE, /* Set the reference handle for buf_useful_data */
173
174 /* Configuration: */
175 Q_SET_WATERMARK,
176 Q_SET_CHUNKSIZE,
177 Q_SET_PRESEEK,
178};
179
180/* Buffering thread */
181void buffering_thread(void);
182static long buffering_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)];
183static const char buffering_thread_name[] = "buffering";
184static struct thread_entry *buffering_thread_p;
185static struct event_queue buffering_queue;
186static struct queue_sender_list buffering_queue_sender_list;
187
188
189/*
190LINKED LIST MANAGEMENT
191======================
192
193add_handle : Add a handle to the list
194rm_handle : Remove a handle from the list
195find_handle : Get a handle pointer from an ID
196move_handle : Move a handle in the buffer (with or without its data)
197
198These functions only handle the linked list structure. They don't touch the
199contents of the struct memory_handle headers. They also change the buf_*idx
200pointers when necessary and manage the handle IDs.
201
202The first and current (== last) handle are kept track of.
203A new handle is added at buf_widx and becomes the current one.
204buf_widx always points to the current writing position for the current handle
205buf_ridx always points to the location of the first handle.
206buf_ridx == buf_widx means the buffer is empty.
207*/
208
209
210/* Add a new handle to the linked list and return it. It will have become the
211 new current handle. "data_size" must contain the size of what will be in the
212 handle. On return, it's the size available for the handle. */
213static struct memory_handle *add_handle(size_t *data_size)
214{
215 mutex_lock(&llist_mutex);
216
217 /* this will give each handle a unique id */
218 static int cur_handle_id = 1;
219
220 /* make sure buf_widx is 32-bit aligned so that the handle struct is,
221 but before that we check we can actually align. */
222 if (RINGBUF_ADD_CROSS(buf_widx, 3, buf_ridx) >= 0) {
223 mutex_unlock(&llist_mutex);
224 return NULL;
225 }
226 buf_widx = (RINGBUF_ADD(buf_widx, 3)) & ~3;
227
228 size_t len = (data_size ? *data_size : 0)
229 + sizeof(struct memory_handle);
230
231 /* check that we actually can add the handle and its data */
232 int overlap = RINGBUF_ADD_CROSS(buf_widx, len, buf_ridx);
233 if (overlap >= 0) {
234 *data_size -= overlap;
235 len -= overlap;
236 }
237 if (len < sizeof(struct memory_handle)) {
238 /* There isn't even enough space to write the struct */
239 mutex_unlock(&llist_mutex);
240 return NULL;
241 }
242
243 struct memory_handle *new_handle =
244 (struct memory_handle *)(&buffer[buf_widx]);
245
246 /* only advance the buffer write index of the size of the struct */
247 buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle));
248
249 if (!first_handle) {
250 /* the new handle is the first one */
251 first_handle = new_handle;
252 }
253
254 if (cur_handle) {
255 cur_handle->next = new_handle;
256 }
257
258 cur_handle = new_handle;
259 cur_handle->id = cur_handle_id++;
260 cur_handle->next = NULL;
261 num_handles++;
262
263 mutex_unlock(&llist_mutex);
264 return cur_handle;
265}
266
267/* Delete a given memory handle from the linked list
268 and return true for success. Nothing is actually erased from memory. */
269static bool rm_handle(struct memory_handle *h)
270{
271 mutex_lock(&llist_mutex);
272
273 if (h == first_handle) {
274 first_handle = h->next;
275 if (h == cur_handle) {
276 /* h was the first and last handle: the buffer is now empty */
277 cur_handle = NULL;
278 buf_ridx = buf_widx;
279 } else {
280 /* update buf_ridx to point to the new first handle */
281 buf_ridx = (void *)first_handle - (void *)buffer;
282 }
283 } else {
284 struct memory_handle *m = first_handle;
285 while (m && m->next != h) {
286 m = m->next;
287 }
288 if (h && m && m->next == h) {
289 m->next = h->next;
290 if (h == cur_handle) {
291 cur_handle = m;
292 buf_widx = cur_handle->widx;
293 }
294 } else {
295 mutex_unlock(&llist_mutex);
296 return false;
297 }
298 }
299
300 /* Invalidate the cache to prevent it from keeping the old location of h */
301 if (h == cached_handle)
302 cached_handle = NULL;
303
304 num_handles--;
305
306 mutex_unlock(&llist_mutex);
307 return true;
308}
309
310/* Return a pointer to the memory handle of given ID.
311 NULL if the handle wasn't found */
312static struct memory_handle *find_handle(int handle_id)
313{
314 if (handle_id <= 0)
315 return NULL;
316
317 mutex_lock(&llist_mutex);
318
319 /* simple caching because most of the time the requested handle
320 will either be the same as the last, or the one after the last */
321 if (cached_handle)
322 {
323 if (cached_handle->id == handle_id) {
324 mutex_unlock(&llist_mutex);
325 return cached_handle;
326 } else if (cached_handle->next &&
327 (cached_handle->next->id == handle_id)) {
328 cached_handle = cached_handle->next;
329 mutex_unlock(&llist_mutex);
330 return cached_handle;
331 }
332 }
333
334 struct memory_handle *m = first_handle;
335 while (m && m->id != handle_id) {
336 m = m->next;
337 }
338 /* This condition can only be reached with !m or m->id == handle_id */
339 if (m) {
340 cached_handle = m;
341 }
342
343 mutex_unlock(&llist_mutex);
344 return m;
345}
346
347/* Move a memory handle and data_size of its data of delta.
348 Return a pointer to the new location of the handle.
349 delta is the value of which to move the struct data.
350 data_size is the amount of data to move along with the struct. */
351static struct memory_handle *move_handle(struct memory_handle *h,
352 size_t *delta, size_t data_size)
353{
354 mutex_lock(&llist_mutex);
355
356 if (*delta < 4) {
357 /* aligning backwards would yield a negative result,
358 and moving the handle of such a small amount is a waste
359 of time anyway. */
360 mutex_unlock(&llist_mutex);
361 return NULL;
362 }
363 /* make sure delta is 32-bit aligned so that the handle struct is. */
364 *delta = (*delta - 3) & ~3;
365
366 size_t newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
367
368 struct memory_handle *dest = (struct memory_handle *)(&buffer[newpos]);
369
370 /* Invalidate the cache to prevent it from keeping the old location of h */
371 if (h == cached_handle)
372 cached_handle = NULL;
373
374 /* the cur_handle pointer might need updating */
375 if (h == cur_handle) {
376 cur_handle = dest;
377 }
378
379 if (h == first_handle) {
380 first_handle = dest;
381 buf_ridx = newpos;
382 } else {
383 struct memory_handle *m = first_handle;
384 while (m && m->next != h) {
385 m = m->next;
386 }
387 if (h && m && m->next == h) {
388 m->next = dest;
389 } else {
390 mutex_unlock(&llist_mutex);
391 return NULL;
392 }
393 }
394
395 memmove(dest, h, sizeof(struct memory_handle) + data_size);
396
397 mutex_unlock(&llist_mutex);
398 return dest;
399}
400
401
402/*
403BUFFER SPACE MANAGEMENT
404=======================
405
406yield_codec : Used by buffer_handle to know if it should interrupt buffering
407buffer_handle : Buffer data for a handle
408reset_handle : Reset writing position and data buffer of a handle to its
409 current offset
410rebuffer_handle : Seek to a nonbuffered part of a handle by rebuffering the data
411shrink_handle : Free buffer space by moving a handle
412fill_buffer : Call buffer_handle for all handles that have data to buffer
413can_add_handle : Indicate whether it's safe to add a handle
414
415These functions are used by the buffering thread to manage buffer space.
416*/
417
418
419static inline bool filebuf_is_lowdata(void)
420{
421 return BUF_USED < BUFFERING_CRITICAL_LEVEL;
422}
423
424/* Yield to the codec thread for as long as possible if it is in need of data.
425 Return true if the caller should break to let the buffering thread process
426 new queue events */
427static bool yield_codec(void)
428{
429 yield();
430
431 if (!queue_empty(&buffering_queue))
432 return true;
433
434 while (pcmbuf_is_lowdata() && !filebuf_is_lowdata())
435 {
436 sleep(2);
437
438 if (!queue_empty(&buffering_queue))
439 return true;
440 }
441
442 return false;
443}
444
445/* Buffer data for the given handle. Return the amount of data buffered
446 or -1 if the handle wasn't found */
447static ssize_t buffer_handle(int handle_id)
448{
449 logf("buffer_handle(%d)", handle_id);
450 struct memory_handle *h = find_handle(handle_id);
451 if (!h)
452 return -1;
453
454 if (h->filerem == 0) {
455 /* nothing left to buffer */
456 return 0;
457 }
458
459 if (h->fd < 0) /* file closed, reopen */
460 {
461 if (*h->path)
462 h->fd = open(h->path, O_RDONLY);
463 else
464 return -1;
465
466 if (h->fd < 0)
467 return -1;
468
469 if (h->offset)
470 lseek(h->fd, h->offset, SEEK_SET);
471 }
472
473 trigger_cpu_boost();
474
475 ssize_t ret = 0;
476 while (h->filerem > 0)
477 {
478 /* max amount to copy */
479 size_t copy_n = MIN( MIN(h->filerem, conf_filechunk),
480 buffer_len - h->widx);
481
482 /* stop copying if it would overwrite the reading position
483 or the next handle */
484 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0 || (h->next &&
485 RINGBUF_ADD_CROSS(h->widx, copy_n, (unsigned)
486 ((void *)h->next - (void *)buffer)) > 0))
487 break;
488
489 /* rc is the actual amount read */
490 int rc = read(h->fd, &buffer[h->widx], copy_n);
491
492 if (rc < 0)
493 {
494 if (h->type == TYPE_CODEC) {
495 logf("Partial codec");
496 break;
497 }
498
499 DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
500 h->filesize -= h->filerem;
501 h->filerem = 0;
502 break;
503 }
504
505 /* Advance buffer */
506 h->widx = RINGBUF_ADD(h->widx, rc);
507 if (h == cur_handle)
508 buf_widx = h->widx;
509 h->available += rc;
510 ret += rc;
511 h->filerem -= rc;
512
513 /* Stop buffering if new queue events have arrived */
514 if (yield_codec())
515 break;
516 }
517
518 if (h->filerem == 0) {
519 /* finished buffering the file */
520 close(h->fd);
521 h->fd = -1;
522 }
523
524 return ret;
525}
526
527/* Reset writing position and data buffer of a handle to its current offset.
528 Use this after having set the new offset to use. */
529static void reset_handle(int handle_id)
530{
531 logf("reset_handle(%d)", handle_id);
532
533 struct memory_handle *h = find_handle(handle_id);
534 if (!h)
535 return;
536
537 h->widx = h->data;
538 if (h == cur_handle)
539 buf_widx = h->widx;
540 h->available = 0;
541 h->filerem = h->filesize - h->offset;
542
543 if (h->fd >= 0) {
544 lseek(h->fd, h->offset, SEEK_SET);
545 }
546}
547
548/* Seek to a nonbuffered part of a handle by rebuffering the data. */
549static void rebuffer_handle(int handle_id, size_t newpos)
550{
551 struct memory_handle *h = find_handle(handle_id);
552 if (!h)
553 return;
554
555 h->offset = newpos;
556
557 LOGFQUEUE("? >| buffering Q_RESET_HANDLE");
558 queue_send(&buffering_queue, Q_RESET_HANDLE, handle_id);
559
560 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
561 queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
562
563 h->ridx = h->data;
564}
565
566static bool close_handle(int handle_id)
567{
568 struct memory_handle *h = find_handle(handle_id);
569 if (!h)
570 return false;
571
572 if (h->fd >= 0) {
573 close(h->fd);
574 h->fd = -1;
575 }
576
577 rm_handle(h);
578 return true;
579}
580
581/* Free buffer space by moving the handle struct right before the useful
582 part of its data buffer or by moving all the data. */
583static void shrink_handle(int handle_id)
584{
585 struct memory_handle *h = find_handle(handle_id);
586 if (!h)
587 return;
588
589 size_t delta;
590 /* The value of delta might change for alignment reasons */
591
592 if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
593 h->type == TYPE_IMAGE) && h->filerem == 0 )
594 {
595 /* metadata handle: we can move all of it */
596 delta = RINGBUF_SUB( (unsigned)((void *)h->next - (void *)buffer),
597 h->data) - h->available;
598 h = move_handle(h, &delta, h->available);
599 if (!h) return;
600
601 size_t olddata = h->data;
602 h->data = RINGBUF_ADD(h->data, delta);
603 h->ridx = RINGBUF_ADD(h->ridx, delta);
604 h->widx = RINGBUF_ADD(h->widx, delta);
605
606 /* when moving a struct mp3entry we need to readjust its pointers. */
607 if (h->type == TYPE_ID3 && h->filesize == sizeof(struct mp3entry)) {
608 adjust_mp3entry((struct mp3entry *)&buffer[h->data],
609 (void *)&buffer[h->data],
610 (void *)&buffer[olddata]);
611 }
612 }
613 else
614 {
615 /* only move the handle struct */
616 delta = RINGBUF_SUB(h->ridx, h->data);
617 h = move_handle(h, &delta, 0);
618 if (!h) return;
619 h->data = RINGBUF_ADD(h->data, delta);
620 h->available -= delta;
621 h->offset += delta;
622 }
623}
624
625/* Fill the buffer by buffering as much data as possible for handles that still
626 have data left to buffer */
627static void fill_buffer(void)
628{
629 logf("fill_buffer()");
630 struct memory_handle *m = first_handle;
631 while (queue_empty(&buffering_queue) && m) {
632 if (m->filerem > 0) {
633 buffer_handle(m->id);
634 }
635 m = m->next;
636 }
637
638#ifndef SIMULATOR
639 if (queue_empty(&buffering_queue)) {
640 /* only spin the disk down if the filling wasn't interrupted by an
641 event arriving in the queue. */
642 ata_sleep();
643 }
644#endif
645}
646
647/* Check whether it's safe to add a new handle and reserve space to let the
648 current one finish buffering its data. Used by bufopen and bufalloc as
649 a preliminary check before even trying to physically add the handle.
650 Returns true if it's ok to add a new handle, false if not.
651*/
652static bool can_add_handle(void)
653{
654 if (cur_handle && cur_handle->filerem > 0) {
655 /* the current handle hasn't finished buffering. We can only add
656 a new one if there is already enough free space to finish
657 the buffering. */
658 if (cur_handle->filerem < (buffer_len - BUF_USED)) {
659 /* Before adding the new handle we reserve some space for the
660 current one to finish buffering its data. */
661 buf_widx = RINGBUF_ADD(buf_widx, cur_handle->filerem);
662 } else {
663 return false;
664 }
665 }
666
667 return true;
668}
669
670void update_data_counters(void)
671{
672 struct memory_handle *m = find_handle(base_handle_id);
673 if (!m)
674 base_handle_id = 0;
675
676 memset(&data_counters, 0, sizeof(data_counters));
677
678 m = first_handle;
679 while (m) {
680 data_counters.buffered += m->available;
681 data_counters.wasted += RINGBUF_SUB(m->ridx, m->data);
682 data_counters.remaining += m->filerem;
683
684 if (m->id >= base_handle_id)
685 data_counters.useful += RINGBUF_SUB(m->widx, m->ridx);
686
687 m = m->next;
688 }
689}
690
691
692/*
693MAIN BUFFERING API CALLS
694========================
695
696bufopen : Request the opening of a new handle for a file
697bufalloc : Open a new handle for data other than a file.
698bufclose : Close an open handle
699bufseek : Set the read pointer in a handle
700bufadvance : Move the read pointer in a handle
701bufread : Copy data from a handle into a given buffer
702bufgetdata : Give a pointer to the handle's data
703
704These functions are exported, to allow interaction with the buffer.
705They take care of the content of the structs, and rely on the linked list
706management functions for all the actual handle management work.
707*/
708
709
710/* Reserve space in the buffer for a file.
711 filename: name of the file to open
712 offset: offset at which to start buffering the file, useful when the first
713 (offset-1) bytes of the file aren't needed.
714 return value: <0 if the file cannot be opened, or one file already
715 queued to be opened, otherwise the handle for the file in the buffer
716*/
717int bufopen(const char *file, size_t offset, enum data_type type)
718{
719 if (!can_add_handle())
720 return -2;
721
722 int fd = open(file, O_RDONLY);
723 if (fd < 0)
724 return -1;
725
726 size_t size = filesize(fd) - offset;
727
728 if (type != TYPE_AUDIO &&
729 size + sizeof(struct memory_handle) > buffer_len - buf_widx)
730 {
731 /* for types other than audio, the data can't wrap, so we force it */
732 buf_widx = 0;
733 }
734
735 struct memory_handle *h = add_handle(&size);
736 if (!h)
737 {
738 DEBUGF("bufopen: failed to add handle\n");
739 close(fd);
740 return -2;
741 }
742
743 strncpy(h->path, file, MAX_PATH);
744 h->fd = -1;
745 h->filesize = filesize(fd);
746 h->filerem = h->filesize - offset;
747 h->offset = offset;
748 h->ridx = buf_widx;
749 h->widx = buf_widx;
750 h->data = buf_widx;
751 h->available = 0;
752 h->type = type;
753
754 close(fd);
755
756 if (type == TYPE_CODEC || type == TYPE_CUESHEET || type == TYPE_IMAGE) {
757 /* Immediately buffer those */
758 LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE");
759 queue_send(&buffering_queue, Q_BUFFER_HANDLE, h->id);
760 }
761
762 logf("bufopen: new hdl %d", h->id);
763 return h->id;
764}
765
766/* Open a new handle from data that needs to be copied from memory.
767 src is the source buffer from which to copy data. It can be NULL to simply
768 reserve buffer space.
769 size is the requested size. The call will only be successful if the
770 requested amount of data can entirely fit in the buffer without wrapping.
771 Return value is the handle id for success or <0 for failure.
772*/
773int bufalloc(const void *src, size_t size, enum data_type type)
774{
775 if (!can_add_handle())
776 return -2;
777
778 if (buf_widx + size + sizeof(struct memory_handle) > buffer_len) {
779 /* The data would need to wrap. */
780 DEBUGF("bufalloc: data wrap\n");
781 return -2;
782 }
783
784 size_t allocsize = size;
785 struct memory_handle *h = add_handle(&allocsize);
786
787 if (!h || allocsize != size)
788 return -2;
789
790 if (src) {
791 if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) {
792 /* specially take care of struct mp3entry */
793 copy_mp3entry((struct mp3entry *)&buffer[buf_widx],
794 (struct mp3entry *)src);
795 } else {
796 memcpy(&buffer[buf_widx], src, size);
797 }
798 }
799
800 h->fd = -1;
801 *h->path = 0;
802 h->filesize = size;
803 h->filerem = 0;
804 h->offset = 0;
805 h->ridx = buf_widx;
806 h->widx = buf_widx + size; /* this is safe because the data doesn't wrap */
807 h->data = buf_widx;
808 h->available = size;
809 h->type = type;
810
811 buf_widx += size; /* safe too */
812
813 logf("bufalloc: new hdl %d", h->id);
814 return h->id;
815}
816
817/* Close the handle. Return true for success and false for failure */
818bool bufclose(int handle_id)
819{
820 logf("bufclose(%d)", handle_id);
821
822 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE");
823 return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id);
824}
825
826/* Set reading index in handle (relatively to the start of the file).
827 Access before the available data will trigger a rebuffer.
828 Return 0 for success and < 0 for failure:
829 -1 if the handle wasn't found
830 -2 if the new requested position was beyond the end of the file
831*/
832int bufseek(int handle_id, size_t newpos)
833{
834 struct memory_handle *h = find_handle(handle_id);
835 if (!h)
836 return -1;
837
838 if (newpos > h->filesize) {
839 /* access beyond the end of the file */
840 return -3;
841 }
842 else if (newpos < h->offset || h->offset + h->available < newpos) {
843 /* access before or after buffered data. A rebuffer is needed. */
844 rebuffer_handle(handle_id, newpos);
845 }
846 else {
847 h->ridx = RINGBUF_ADD(h->data, newpos - h->offset);
848 }
849 return 0;
850}
851
852/* Advance the reading index in a handle (relatively to its current position).
853 Return 0 for success and < 0 for failure */
854int bufadvance(int handle_id, off_t offset)
855{
856 struct memory_handle *h = find_handle(handle_id);
857 if (!h)
858 return -1;
859
860 size_t newpos = h->offset + RINGBUF_SUB(h->ridx, h->data) + offset;
861 return bufseek(handle_id, newpos);
862}
863
864/* Copy data from the given handle to the dest buffer.
865 Return the number of bytes copied or < 0 for failure. */
866ssize_t bufread(int handle_id, size_t size, void *dest)
867{
868 struct memory_handle *h = find_handle(handle_id);
869 if (!h)
870 return -1;
871
872 size_t ret;
873 size_t copy_n = RINGBUF_SUB(h->widx, h->ridx);
874
875 if (size == 0 && h->filerem > 0 && copy_n == 0)
876 /* Data isn't ready */
877 return -2;
878
879 if (copy_n < size && h->filerem > 0)
880 /* Data isn't ready */
881 return -2;
882
883 if (copy_n == 0 && h->filerem == 0)
884 /* File is finished reading */
885 return 0;
886
887 ret = MIN(size, copy_n);
888
889 if (h->ridx + ret > buffer_len)
890 {
891 /* the data wraps around the end of the buffer */
892 size_t read = buffer_len - h->ridx;
893 memcpy(dest, &buffer[h->ridx], read);
894 memcpy(dest+read, buffer, ret - read);
895 }
896 else
897 {
898 memcpy(dest, &buffer[h->ridx], ret);
899 }
900
901 return ret;
902}
903
904/* Update the "data" pointer to make the handle's data available to the caller.
905 Return the length of the available linear data or < 0 for failure.
906 size is the amount of linear data requested. it can be 0 to get as
907 much as possible.
908 The guard buffer may be used to provide the requested size */
909ssize_t bufgetdata(int handle_id, size_t size, void **data)
910{
911 struct memory_handle *h = find_handle(handle_id);
912 if (!h)
913 return -1;
914
915 ssize_t ret;
916 size_t copy_n = RINGBUF_SUB(h->widx, h->ridx);
917
918 if (size == 0 && h->filerem > 0 && copy_n == 0)
919 /* Data isn't ready */
920 return -2;
921
922 if (copy_n < size && h->filerem > 0)
923 /* Data isn't ready */
924 return -2;
925
926 if (copy_n == 0 && h->filerem == 0)
927 /* File is finished reading */
928 return 0;
929
930 if (h->ridx + size > buffer_len && copy_n >= size)
931 {
932 /* the data wraps around the end of the buffer :
933 use the guard buffer to provide the requested amount of data. */
934 size_t copy_n = MIN(h->ridx + size - buffer_len, GUARD_BUFSIZE);
935 memcpy(guard_buffer, (unsigned char *)buffer, copy_n);
936 ret = buffer_len - h->ridx + copy_n;
937 }
938 else
939 {
940 ret = MIN(copy_n, buffer_len - h->ridx);
941 }
942
943 *data = &buffer[h->ridx];
944 return ret;
945}
946
947/*
948SECONDARY EXPORTED FUNCTIONS
949============================
950
951buf_get_offset
952buf_handle_offset
953buf_request_buffer_handle
954buf_set_base_handle
955buf_used
956register_buffer_low_callback
957unregister_buffer_low_callback
958
959These functions are exported, to allow interaction with the buffer.
960They take care of the content of the structs, and rely on the linked list
961management functions for all the actual handle management work.
962*/
963
964/* Get a handle offset from a pointer */
965ssize_t buf_get_offset(int handle_id, void *ptr)
966{
967 struct memory_handle *h = find_handle(handle_id);
968 if (!h)
969 return -1;
970
971 return (size_t)ptr - (size_t)&buffer[h->ridx];
972}
973
974ssize_t buf_handle_offset(int handle_id)
975{
976 struct memory_handle *h = find_handle(handle_id);
977 if (!h)
978 return -1;
979 return h->offset;
980}
981
982void buf_request_buffer_handle(int handle_id)
983{
984 LOGFQUEUE("buffering >| buffering Q_BUFFER_HANDLE");
985 queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id);
986}
987
988void buf_set_base_handle(int handle_id)
989{
990 LOGFQUEUE("buffering >| buffering Q_BUFFER_HANDLE");
991 queue_post(&buffering_queue, Q_BASE_HANDLE, handle_id);
992}
993
994/* Return the amount of buffer space used */
995size_t buf_used(void)
996{
997 return BUF_USED;
998}
999
1000void buf_set_conf(int setting, size_t value)
1001{
1002 int msg;
1003 switch (setting)
1004 {
1005 case BUFFERING_SET_WATERMARK:
1006 msg = Q_SET_WATERMARK;
1007 break;
1008
1009 case BUFFERING_SET_CHUNKSIZE:
1010 msg = Q_SET_CHUNKSIZE;
1011 break;
1012
1013 case BUFFERING_SET_PRESEEK:
1014 msg = Q_SET_PRESEEK;
1015 break;
1016
1017 default:
1018 return;
1019 }
1020 queue_post(&buffering_queue, msg, value);
1021}
1022
1023bool register_buffer_low_callback(buffer_low_callback func)
1024{
1025 int i;
1026 if (buffer_callback_count >= MAX_BUF_CALLBACKS)
1027 return false;
1028 for (i = 0; i < MAX_BUF_CALLBACKS; i++)
1029 {
1030 if (buffer_low_callback_funcs[i] == NULL)
1031 {
1032 buffer_low_callback_funcs[i] = func;
1033 buffer_callback_count++;
1034 return true;
1035 }
1036 else if (buffer_low_callback_funcs[i] == func)
1037 return true;
1038 }
1039 return false;
1040}
1041
1042void unregister_buffer_low_callback(buffer_low_callback func)
1043{
1044 int i;
1045 for (i = 0; i < MAX_BUF_CALLBACKS; i++)
1046 {
1047 if (buffer_low_callback_funcs[i] == func)
1048 {
1049 buffer_low_callback_funcs[i] = NULL;
1050 buffer_callback_count--;
1051 }
1052 }
1053 return;
1054}
1055
1056static void call_buffer_low_callbacks(void)
1057{
1058 int i;
1059 for (i = 0; i < MAX_BUF_CALLBACKS; i++)
1060 {
1061 if (buffer_low_callback_funcs[i])
1062 {
1063 buffer_low_callback_funcs[i]();
1064 buffer_low_callback_funcs[i] = NULL;
1065 buffer_callback_count--;
1066 }
1067 }
1068}
1069
1070void buffering_thread(void)
1071{
1072 struct queue_event ev;
1073
1074 while (true)
1075 {
1076 queue_wait_w_tmo(&buffering_queue, &ev, HZ/2);
1077
1078 switch (ev.id)
1079 {
1080 case Q_BUFFER_HANDLE:
1081 LOGFQUEUE("buffering < Q_BUFFER_HANDLE");
1082 queue_reply(&buffering_queue, 1);
1083 buffer_handle((int)ev.data);
1084 break;
1085
1086 case Q_RESET_HANDLE:
1087 LOGFQUEUE("buffering < Q_RESET_HANDLE");
1088 queue_reply(&buffering_queue, 1);
1089 reset_handle((int)ev.data);
1090 break;
1091
1092 case Q_CLOSE_HANDLE:
1093 LOGFQUEUE("buffering < Q_CLOSE_HANDLE");
1094 queue_reply(&buffering_queue, close_handle((int)ev.data));
1095 break;
1096
1097 case Q_BASE_HANDLE:
1098 LOGFQUEUE("buffering < Q_BASE_HANDLE");
1099 base_handle_id = (int)ev.data;
1100 break;
1101
1102 case Q_SET_WATERMARK:
1103 LOGFQUEUE("buffering < Q_SET_WATERMARK");
1104 conf_watermark = (size_t)ev.data;
1105 break;
1106
1107 case Q_SET_CHUNKSIZE:
1108 LOGFQUEUE("buffering < Q_SET_CHUNKSIZE");
1109 conf_filechunk = (size_t)ev.data;
1110 break;
1111
1112 case Q_SET_PRESEEK:
1113 LOGFQUEUE("buffering < Q_SET_PRESEEK");
1114 conf_preseek = (size_t)ev.data;
1115 break;
1116
1117#ifndef SIMULATOR
1118 case SYS_USB_CONNECTED:
1119 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
1120 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1121 usb_wait_for_disconnect(&buffering_queue);
1122 break;
1123#endif
1124
1125 case SYS_TIMEOUT:
1126 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1127 break;
1128 }
1129
1130 update_data_counters();
1131
1132 /* If the buffer is low, call the callbacks to get new data */
1133 if (num_handles > 0 && data_counters.useful < conf_watermark)
1134 {
1135 call_buffer_low_callbacks();
1136 }
1137
1138#if MEM > 8
1139 /* If the disk is spinning, take advantage by filling the buffer */
1140 if (ata_disk_is_active() && queue_empty(&buffering_queue) &&
1141 data_counters.remaining > 0 &&
1142 data_counters.buffered < high_watermark)
1143 {
1144 fill_buffer();
1145 }
1146
1147 if (ata_disk_is_active() && queue_empty(&buffering_queue) &&
1148 num_handles > 0 && data_counters.useful < high_watermark)
1149 {
1150 call_buffer_low_callbacks();
1151 }
1152#endif
1153
1154 if (ev.id == SYS_TIMEOUT && queue_empty(&buffering_queue))
1155 {
1156 if (data_counters.remaining > 0 &&
1157 data_counters.wasted > data_counters.buffered/2)
1158 {
1159 /* free buffer from outdated audio data */
1160 struct memory_handle *m = first_handle;
1161 while (m) {
1162 if (m->type == TYPE_AUDIO)
1163 shrink_handle(m->id);
1164 m = m->next;
1165 }
1166
1167 /* free buffer by moving metadata */
1168 m = first_handle;
1169 while (m) {
1170 if (m->type != TYPE_AUDIO)
1171 shrink_handle(m->id);
1172 m = m->next;
1173 }
1174
1175 update_data_counters();
1176 }
1177
1178 if (data_counters.remaining > 0 &&
1179 data_counters.buffered < conf_watermark)
1180 {
1181 fill_buffer();
1182 }
1183 }
1184 }
1185}
1186
1187/* Initialise the buffering subsystem */
1188bool buffering_init(char *buf, size_t buflen)
1189{
1190 if (!buf || !buflen)
1191 return false;
1192
1193 buffer = buf;
1194 buffer_len = buflen;
1195 guard_buffer = buf + buflen;
1196
1197 buf_widx = 0;
1198 buf_ridx = 0;
1199
1200 first_handle = NULL;
1201 num_handles = 0;
1202
1203 buffer_callback_count = 0;
1204 memset(buffer_low_callback_funcs, 0, sizeof(buffer_low_callback_funcs));
1205
1206 mutex_init(&llist_mutex);
1207
1208 conf_filechunk = BUFFERING_DEFAULT_FILECHUNK;
1209 conf_watermark = BUFFERING_DEFAULT_WATERMARK;
1210
1211 /* Set the high watermark as 75% full...or 25% empty :) */
1212#if MEM > 8
1213 high_watermark = 3*buflen / 4;
1214#endif
1215
1216 if (buffering_thread_p == NULL)
1217 {
1218 buffering_thread_p = create_thread( buffering_thread, buffering_stack,
1219 sizeof(buffering_stack), 0,
1220 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING)
1221 IF_COP(, CPU));
1222
1223 queue_init(&buffering_queue, true);
1224 queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list);
1225 }
1226
1227 return true;
1228}
1229
1230void buffering_get_debugdata(struct buffering_debug *dbgdata)
1231{
1232 update_data_counters();
1233 dbgdata->num_handles = num_handles;
1234 dbgdata->data_rem = data_counters.remaining;
1235 dbgdata->wasted_space = data_counters.wasted;
1236 dbgdata->buffered_data = data_counters.buffered;
1237 dbgdata->useful_data = data_counters.useful;
1238}
diff --git a/apps/buffering.h b/apps/buffering.h
new file mode 100644
index 0000000000..a5ad1e283b
--- /dev/null
+++ b/apps/buffering.h
@@ -0,0 +1,120 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Nicolas Pennequin
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef _BUFFERING_H_
21#define _BUFFERING_H_
22
23#include <sys/types.h>
24#include <stdbool.h>
25
26
27enum data_type {
28 TYPE_CODEC,
29 TYPE_AUDIO,
30 TYPE_STREAM,
31 TYPE_ID3,
32 TYPE_CUESHEET,
33 TYPE_IMAGE,
34 TYPE_BUFFER,
35 TYPE_UNKNOWN,
36};
37
38
39/* Initialise the buffering subsystem */
40bool buffering_init(char *buf, size_t buflen);
41
42
43/***************************************************************************
44 * MAIN BUFFERING API CALLS
45 * ========================
46 *
47 * bufopen : Reserve space in the buffer for a given file
48 * bufalloc : Open a new handle from data that needs to be copied from memory
49 * bufclose : Close an open handle
50 * bufseek : Set handle reading index, relatively to the start of the file
51 * bufadvance: Move handle reading index, relatively to current position
52 * bufread : Copy data from a handle to a buffer
53 * bufgetdata: Obtain a pointer for linear access to a "size" amount of data
54 ****************************************************************************/
55
56int bufopen(const char *file, size_t offset, enum data_type type);
57int bufalloc(const void *src, size_t size, enum data_type type);
58bool bufclose(int handle_id);
59int bufseek(int handle_id, size_t newpos);
60int bufadvance(int handle_id, off_t offset);
61ssize_t bufread(int handle_id, size_t size, void *dest);
62ssize_t bufgetdata(int handle_id, size_t size, void **data);
63
64
65/***************************************************************************
66 * SECONDARY FUNCTIONS
67 * ===================
68 *
69 * buf_get_offset: Get a handle offset from a pointer
70 * buf_handle_offset: Get the offset of the first buffered byte from the file
71 * buf_request_buffer_handle: Request buffering of a handle
72 * buf_set_base_handle: Tell the buffering thread which handle is currently read
73 * buf_used: Total amount of buffer space used (including allocated space)
74 ****************************************************************************/
75
76ssize_t buf_get_offset(int handle_id, void *ptr);
77ssize_t buf_handle_offset(int handle_id);
78void buf_request_buffer_handle(int handle_id);
79void buf_set_base_handle(int handle_id);
80size_t buf_used(void);
81
82
83/***************************************************************************
84 * CALLBACK UTILITIES
85 * ==================
86 *
87 * register_buffer_low_callback, unregister_buffer_low_callback:
88 *
89 * Register/Unregister callback functions that will get executed when the buffer
90 * goes below the low watermark. They are executed once, then forgotten.
91 *
92 * NOTE: The callbacks are called from the buffering thread, so don't make them
93 * do too much. Ideally they should just post an event to a queue and return.
94 ****************************************************************************/
95
96#define MAX_BUF_CALLBACKS 4
97typedef void (*buffer_low_callback)(void);
98bool register_buffer_low_callback(buffer_low_callback func);
99void unregister_buffer_low_callback(buffer_low_callback func);
100
101/* Settings */
102enum {
103 BUFFERING_SET_WATERMARK = 1,
104 BUFFERING_SET_CHUNKSIZE,
105 BUFFERING_SET_PRESEEK,
106};
107void buf_set_conf(int setting, size_t value);
108
109
110/* Debugging */
111struct buffering_debug {
112 int num_handles;
113 size_t buffered_data;
114 size_t wasted_space;
115 size_t data_rem;
116 size_t useful_data;
117};
118void buffering_get_debugdata(struct buffering_debug *dbgdata);
119
120#endif
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index de40226758..c9d962ece4 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -75,6 +75,7 @@
75#include "logfdisp.h" 75#include "logfdisp.h"
76#if CONFIG_CODEC == SWCODEC 76#if CONFIG_CODEC == SWCODEC
77#include "pcmbuf.h" 77#include "pcmbuf.h"
78#include "buffering.h"
78#if defined(HAVE_SPDIF_OUT) || defined(HAVE_SPDIF_IN) 79#if defined(HAVE_SPDIF_OUT) || defined(HAVE_SPDIF_IN)
79#include "spdif.h" 80#include "spdif.h"
80#endif 81#endif
@@ -261,7 +262,7 @@ static void dbg_audio_task(void)
261 ticks++; 262 ticks++;
262} 263}
263 264
264static bool dbg_audio_thread(void) 265static bool dbg_buffering_thread(void)
265{ 266{
266 char buf[32]; 267 char buf[32];
267 int button; 268 int button;
@@ -270,6 +271,7 @@ static bool dbg_audio_thread(void)
270 size_t bufused; 271 size_t bufused;
271 size_t bufsize = pcmbuf_get_bufsize(); 272 size_t bufsize = pcmbuf_get_bufsize();
272 int pcmbufdescs = pcmbuf_descs(); 273 int pcmbufdescs = pcmbuf_descs();
274 struct buffering_debug d;
273 275
274 ticks = boost_ticks = 0; 276 ticks = boost_ticks = 0;
275 277
@@ -292,6 +294,9 @@ static bool dbg_audio_thread(void)
292 done = true; 294 done = true;
293 break; 295 break;
294 } 296 }
297
298 buffering_get_debugdata(&d);
299
295 line = 0; 300 line = 0;
296 lcd_clear_display(); 301 lcd_clear_display();
297 302
@@ -300,19 +305,45 @@ static bool dbg_audio_thread(void)
300 snprintf(buf, sizeof(buf), "pcm: %7ld/%7ld", (long) bufused, (long) bufsize); 305 snprintf(buf, sizeof(buf), "pcm: %7ld/%7ld", (long) bufused, (long) bufsize);
301 lcd_puts(0, line++, buf); 306 lcd_puts(0, line++, buf);
302 307
303 /* Playable space left */ 308 gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6,
304 gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6, bufsize, 0, bufused, HORIZONTAL); 309 bufsize, 0, bufused, HORIZONTAL);
305 line++; 310 line++;
306 311
307 snprintf(buf, sizeof(buf), "codec: %8ld/%8ld", audio_filebufused(), (long) filebuflen); 312 snprintf(buf, sizeof(buf), "alloc: %8ld/%8ld", audio_filebufused(),
313 (long) filebuflen);
308 lcd_puts(0, line++, buf); 314 lcd_puts(0, line++, buf);
309 315
310 /* Playable space left */ 316#if LCD_HEIGHT > 80
311 gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6, filebuflen, 0, 317 gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6,
312 audio_filebufused(), HORIZONTAL); 318 filebuflen, 0, audio_filebufused(), HORIZONTAL);
319 line++;
320
321 snprintf(buf, sizeof(buf), "real: %8ld/%8ld", (long)d.buffered_data,
322 (long)filebuflen);
323 lcd_puts(0, line++, buf);
324
325 gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6,
326 filebuflen, 0, (long)d.buffered_data, HORIZONTAL);
327 line++;
328#endif
329
330 snprintf(buf, sizeof(buf), "usefl: %8ld/%8ld", (long)(d.useful_data),
331 (long)filebuflen);
332 lcd_puts(0, line++, buf);
333
334#if LCD_HEIGHT > 80
335 gui_scrollbar_draw(&screens[SCREEN_MAIN],0, line*8, LCD_WIDTH, 6,
336 filebuflen, 0, d.useful_data, HORIZONTAL);
313 line++; 337 line++;
338#endif
314 339
315 snprintf(buf, sizeof(buf), "track count: %2d", audio_track_count()); 340 snprintf(buf, sizeof(buf), "data_rem: %ld", (long)d.data_rem);
341 lcd_puts(0, line++, buf);
342
343 snprintf(buf, sizeof(buf), "track count: %2d", audio_track_count()-1);
344 lcd_puts(0, line++, buf);
345
346 snprintf(buf, sizeof(buf), "handle count: %d", (int)d.num_handles);
316 lcd_puts(0, line++, buf); 347 lcd_puts(0, line++, buf);
317 348
318#ifndef SIMULATOR 349#ifndef SIMULATOR
@@ -2241,7 +2272,9 @@ static const struct the_menu_item menuitems[] = {
2241 { "View database info", dbg_tagcache_info }, 2272 { "View database info", dbg_tagcache_info },
2242#endif 2273#endif
2243#ifdef HAVE_LCD_BITMAP 2274#ifdef HAVE_LCD_BITMAP
2244#if CONFIG_CODEC == SWCODEC || !defined(SIMULATOR) 2275#if CONFIG_CODEC == SWCODEC
2276 { "View buffering thread", dbg_buffering_thread },
2277#elif !defined(SIMULATOR)
2245 { "View audio thread", dbg_audio_thread }, 2278 { "View audio thread", dbg_audio_thread },
2246#endif 2279#endif
2247#ifdef PM_DEBUG 2280#ifdef PM_DEBUG
diff --git a/apps/playback.c b/apps/playback.c
index 03bbb9ddd2..0cda680c0b 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -46,6 +46,7 @@
46#include "settings.h" 46#include "settings.h"
47#include "codecs.h" 47#include "codecs.h"
48#include "audio.h" 48#include "audio.h"
49#include "buffering.h"
49#include "mp3_playback.h" 50#include "mp3_playback.h"
50#include "usb.h" 51#include "usb.h"
51#include "status.h" 52#include "status.h"
@@ -91,8 +92,6 @@
91#define AUDIO_DEFAULT_WATERMARK (1024*512) 92#define AUDIO_DEFAULT_WATERMARK (1024*512)
92/* amount of data to read in one read() call */ 93/* amount of data to read in one read() call */
93#define AUDIO_DEFAULT_FILECHUNK (1024*32) 94#define AUDIO_DEFAULT_FILECHUNK (1024*32)
94/* point at which the file buffer will fight for CPU time */
95#define AUDIO_FILEBUF_CRITICAL (1024*128)
96/* amount of guess-space to allow for codecs that must hunt and peck 95/* amount of guess-space to allow for codecs that must hunt and peck
97 * for their correct seeek target, 32k seems a good size */ 96 * for their correct seeek target, 32k seems a good size */
98#define AUDIO_REBUFFER_GUESS_SIZE (1024*32) 97#define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
@@ -135,16 +134,12 @@ enum {
135 Q_AUDIO_SKIP, 134 Q_AUDIO_SKIP,
136 Q_AUDIO_PRE_FF_REWIND, 135 Q_AUDIO_PRE_FF_REWIND,
137 Q_AUDIO_FF_REWIND, 136 Q_AUDIO_FF_REWIND,
138 Q_AUDIO_REBUFFER_SEEK,
139 Q_AUDIO_CHECK_NEW_TRACK, 137 Q_AUDIO_CHECK_NEW_TRACK,
140 Q_AUDIO_FLUSH, 138 Q_AUDIO_FLUSH,
141 Q_AUDIO_TRACK_CHANGED, 139 Q_AUDIO_TRACK_CHANGED,
142 Q_AUDIO_DIR_SKIP, 140 Q_AUDIO_DIR_SKIP,
143 Q_AUDIO_POSTINIT, 141 Q_AUDIO_POSTINIT,
144 Q_AUDIO_FILL_BUFFER, 142 Q_AUDIO_FILL_BUFFER,
145#if MEM > 8
146 Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
147#endif
148 Q_CODEC_REQUEST_COMPLETE, 143 Q_CODEC_REQUEST_COMPLETE,
149 Q_CODEC_REQUEST_FAILED, 144 Q_CODEC_REQUEST_FAILED,
150 145
@@ -196,7 +191,6 @@ bool audio_is_initialized = false;
196static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */ 191static volatile bool audio_codec_loaded NOCACHEBSS_ATTR = false; /* Codec loaded? (C/A-) */
197static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */ 192static volatile bool playing NOCACHEBSS_ATTR = false; /* Is audio playing? (A) */
198static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */ 193static volatile bool paused NOCACHEBSS_ATTR = false; /* Is audio paused? (A/C-) */
199static volatile bool filling IDATA_ATTR = false; /* Is file buffer refilling? (A/C-) */
200 194
201/* Ring buffer where compressed audio and codecs are loaded */ 195/* Ring buffer where compressed audio and codecs are loaded */
202static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ 196static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
@@ -204,8 +198,6 @@ static unsigned char *malloc_buf = NULL; /* Start of malloc buffer (A/C-) */
204/* FIXME: make filebuflen static */ 198/* FIXME: make filebuflen static */
205size_t filebuflen = 0; /* Size of buffer (A/C-) */ 199size_t filebuflen = 0; /* Size of buffer (A/C-) */
206/* FIXME: make buf_ridx (C/A-) */ 200/* FIXME: make buf_ridx (C/A-) */
207static volatile size_t buf_ridx IDATA_ATTR = 0; /* Buffer read position (A/C)*/
208static volatile size_t buf_widx IDATA_ATTR = 0; /* Buffer write position (A/C-) */
209 201
210/* Possible arrangements of the buffer */ 202/* Possible arrangements of the buffer */
211#define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */ 203#define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
@@ -213,29 +205,18 @@ static volatile size_t buf_widx IDATA_ATTR = 0; /* Buffer write position (A/C-)
213#define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */ 205#define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
214static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */ 206static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
215 207
216/* Compressed ring buffer helper macros */ 208static struct mp3entry prevtrack_id3;
217/* Buffer pointer (p) plus value (v), wrapped if necessary */ 209static struct mp3entry curtrack_id3;
218#define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen) 210static struct mp3entry nexttrack_id3;
219/* Buffer pointer (p) minus value (v), wrapped if necessary */
220#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
221/* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
222#define RINGBUF_ADD_CROSS(p1,v,p2) \
223 ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
224/* Bytes available in the buffer */
225#define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx)
226 211
227/* Track info structure about songs in the file buffer (A/C-) */ 212/* Track info structure about songs in the file buffer (A/C-) */
228struct track_info { 213struct track_info {
229 struct mp3entry id3; /* TAG metadata */ 214 int audio_hid; /* The ID for the track's buffer handle */
230 char *codecbuf; /* Pointer to codec buffer */ 215 int id3_hid; /* The ID for the track's metadata handle */
231 size_t codecsize; /* Codec length in bytes */ 216 int codec_hid; /* The ID for the track's codec handle */
232 bool has_codec; /* Does this track have a codec on the buffer */
233 217
234 size_t buf_idx; /* Pointer to the track's buffer */ 218 size_t codecsize; /* Codec length in bytes */
235 size_t filerem; /* Remaining bytes of file NOT in buffer */
236 size_t filesize; /* File total length */ 219 size_t filesize; /* File total length */
237 size_t start_pos; /* Position to first bytes of file in buffer */
238 volatile size_t available; /* Available bytes to read from buffer */
239 220
240 bool taginfo_ready; /* Is metadata read */ 221 bool taginfo_ready; /* Is metadata read */
241 222
@@ -246,7 +227,6 @@ static struct track_info tracks[MAX_TRACK];
246static volatile int track_ridx = 0; /* Track being decoded (A/C-) */ 227static volatile int track_ridx = 0; /* Track being decoded (A/C-) */
247static int track_widx = 0; /* Track being buffered (A) */ 228static int track_widx = 0; /* Track being buffered (A) */
248 229
249static struct track_info *prev_ti = NULL; /* Previous track info pointer (A/C-) */
250#define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */ 230#define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
251 231
252/* Set by the audio thread when the current track information has updated 232/* Set by the audio thread when the current track information has updated
@@ -256,8 +236,6 @@ static bool track_changed = false;
256/* Information used only for filling the buffer */ 236/* Information used only for filling the buffer */
257/* Playlist steps from playing track to next track to be buffered (A) */ 237/* Playlist steps from playing track to next track to be buffered (A) */
258static int last_peek_offset = 0; 238static int last_peek_offset = 0;
259/* Partially loaded track file handle to continue buffering (A) */
260static int current_fd = -1;
261 239
262/* Scrobbler support */ 240/* Scrobbler support */
263static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/ 241static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
@@ -278,19 +256,12 @@ void (*track_buffer_callback)(struct mp3entry *id3, bool last_track) = NULL;
278/* When a track's buffer has been overwritten or cleared */ 256/* When a track's buffer has been overwritten or cleared */
279void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track) = NULL; 257void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track) = NULL;
280 258
281/* Configuration */
282static size_t conf_watermark = 0; /* Level to trigger filebuf fill (A/C) FIXME */
283static size_t conf_filechunk = 0; /* Largest chunk the codec accepts (A/C) FIXME */
284static size_t conf_preseek = 0; /* Codec pre-seek margin (A/C) FIXME */
285static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */ 259static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
286#if MEM > 8
287static size_t high_watermark = 0; /* High watermark for rebuffer (A/V/other) */
288#endif
289 260
290/* Multiple threads */ 261/* Multiple threads */
291static void set_current_codec(int codec_idx); 262static void set_current_codec(int codec_idx);
292/* Set the watermark to trigger buffer fill (A/C) FIXME */ 263/* Set the watermark to trigger buffer fill (A/C) FIXME */
293static void set_filebuf_watermark(int seconds); 264static void set_filebuf_watermark(int seconds, size_t max);
294 265
295/* Audio thread */ 266/* Audio thread */
296static struct event_queue audio_queue NOCACHEBSS_ATTR; 267static struct event_queue audio_queue NOCACHEBSS_ATTR;
@@ -306,6 +277,7 @@ static void audio_reset_buffer(void);
306/* Codec thread */ 277/* Codec thread */
307extern struct codec_api ci; 278extern struct codec_api ci;
308static struct event_queue codec_queue NOCACHEBSS_ATTR; 279static struct event_queue codec_queue NOCACHEBSS_ATTR;
280static struct queue_sender_list codec_queue_sender_list;
309static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 281static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
310IBSS_ATTR; 282IBSS_ATTR;
311static const char codec_thread_name[] = "codec"; 283static const char codec_thread_name[] = "codec";
@@ -372,6 +344,73 @@ static void voice_stop(void);
372 344
373#endif /* PLAYBACK_VOICE */ 345#endif /* PLAYBACK_VOICE */
374 346
347
348/* --- Helper functions --- */
349
350struct mp3entry *bufgetid3(int handle_id)
351{
352 if (handle_id < 0)
353 return NULL;
354
355 struct mp3entry *id3;
356 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
357
358 if (ret < 0 || ret != sizeof(struct mp3entry))
359 return NULL;
360
361 return id3;
362}
363
364void *bufgetcodec(struct track_info *track)
365{
366 void *ptr;
367 ssize_t ret = bufgetdata(track->codec_hid, track->codecsize, &ptr);
368
369 if (ret == -2) {
370 buf_request_buffer_handle(CUR_TI->audio_hid);
371 }
372
373 while (ret == -2) {
374 sleep(1);
375 ret = bufgetdata(track->codec_hid, track->codecsize, &ptr);
376 }
377
378 if (ret < 0)
379 return NULL;
380 else
381 return ptr;
382}
383
384bool clear_track_info(struct track_info *track)
385{
386 if (!track)
387 return false;
388
389 if (track->codec_hid > 0) {
390 if (bufclose(track->codec_hid))
391 track->codec_hid = 0;
392 else
393 return false;
394 }
395
396 if (track->id3_hid > 0) {
397 if (bufclose(track->id3_hid))
398 track->id3_hid = 0;
399 else
400 return false;
401 }
402
403 if (track->audio_hid > 0) {
404 if (bufclose(track->audio_hid))
405 track->audio_hid = 0;
406 else
407 return false;
408 }
409
410 memset(track, 0, sizeof(struct track_info));
411 return true;
412}
413
375/* --- External interfaces --- */ 414/* --- External interfaces --- */
376 415
377void mp3_play_data(const unsigned char* start, int size, 416void mp3_play_data(const unsigned char* start, int size,
@@ -620,8 +659,12 @@ struct mp3entry* audio_current_track(void)
620 cur_idx = track_ridx + offset; 659 cur_idx = track_ridx + offset;
621 cur_idx &= MAX_TRACK_MASK; 660 cur_idx &= MAX_TRACK_MASK;
622 661
623 if (tracks[cur_idx].taginfo_ready) 662 if (cur_idx == track_ridx && *curtrack_id3.path)
624 return &tracks[cur_idx].id3; 663 return &curtrack_id3;
664 else if (offset == -1 && *prevtrack_id3.path)
665 return &prevtrack_id3;
666 else if (tracks[cur_idx].id3_hid > 0)
667 return bufgetid3(tracks[cur_idx].id3_hid);
625 668
626 memset(&temp_id3, 0, sizeof(struct mp3entry)); 669 memset(&temp_id3, 0, sizeof(struct mp3entry));
627 670
@@ -653,13 +696,16 @@ struct mp3entry* audio_next_track(void)
653 if (!audio_have_tracks()) 696 if (!audio_have_tracks())
654 return NULL; 697 return NULL;
655 698
699 if (wps_offset == -1 && *prevtrack_id3.path)
700 return &curtrack_id3;
701
656 next_idx++; 702 next_idx++;
657 next_idx &= MAX_TRACK_MASK; 703 next_idx &= MAX_TRACK_MASK;
658 704
659 if (!tracks[next_idx].taginfo_ready) 705 if (tracks[next_idx].id3_hid <= 0)
660 return NULL; 706 return NULL;
661 707
662 return &tracks[next_idx].id3; 708 return &nexttrack_id3;
663} 709}
664 710
665bool audio_has_changed_track(void) 711bool audio_has_changed_track(void)
@@ -818,8 +864,8 @@ void audio_set_buffer_margin(int setting)
818{ 864{
819 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600}; 865 static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
820 buffer_margin = lookup[setting]; 866 buffer_margin = lookup[setting];
821 logf("buffer margin: %ld", buffer_margin); 867 logf("buffer margin: %d", buffer_margin);
822 set_filebuf_watermark(buffer_margin); 868 set_filebuf_watermark(buffer_margin, 0);
823} 869}
824#endif 870#endif
825 871
@@ -851,7 +897,7 @@ void audio_set_crossfade(int enable)
851 if (was_playing) 897 if (was_playing)
852 { 898 {
853 /* Store the track resume position */ 899 /* Store the track resume position */
854 offset = CUR_TI->id3.offset; 900 offset = curtrack_id3.offset;
855 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK)); 901 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK));
856 } 902 }
857 903
@@ -997,16 +1043,16 @@ void voice_wait(void)
997#endif 1043#endif
998} 1044}
999 1045
1000static void set_filebuf_watermark(int seconds) 1046static void set_filebuf_watermark(int seconds, size_t max)
1001{ 1047{
1002 size_t bytes; 1048 size_t bytes;
1003 1049
1004 if (!filebuf) 1050 if (!filebuf)
1005 return; /* Audio buffers not yet set up */ 1051 return; /* Audio buffers not yet set up */
1006 1052
1007 bytes = MAX(CUR_TI->id3.bitrate * seconds * (1000/8), conf_watermark); 1053 bytes = MAX(curtrack_id3.bitrate * seconds * (1000/8), max);
1008 bytes = MIN(bytes, filebuflen / 2); 1054 bytes = MIN(bytes, filebuflen / 2);
1009 conf_watermark = bytes; 1055 buf_set_conf(BUFFERING_SET_WATERMARK, bytes);
1010} 1056}
1011 1057
1012const char * get_codec_filename(int cod_spec) 1058const char * get_codec_filename(int cod_spec)
@@ -1422,15 +1468,15 @@ static void codec_pcmbuf_position_callback(size_t size)
1422{ 1468{
1423 /* This is called from an ISR, so be quick */ 1469 /* This is called from an ISR, so be quick */
1424 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + 1470 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
1425 prev_ti->id3.elapsed; 1471 prevtrack_id3.elapsed;
1426 1472
1427 if (time >= prev_ti->id3.length) 1473 if (time >= prevtrack_id3.length)
1428 { 1474 {
1429 pcmbuf_set_position_callback(NULL); 1475 pcmbuf_set_position_callback(NULL);
1430 prev_ti->id3.elapsed = prev_ti->id3.length; 1476 prevtrack_id3.elapsed = prevtrack_id3.length;
1431 } 1477 }
1432 else 1478 else
1433 prev_ti->id3.elapsed = time; 1479 prevtrack_id3.elapsed = time;
1434} 1480}
1435 1481
1436static void codec_set_elapsed_callback(unsigned int value) 1482static void codec_set_elapsed_callback(unsigned int value)
@@ -1445,11 +1491,11 @@ static void codec_set_elapsed_callback(unsigned int value)
1445 1491
1446 latency = pcmbuf_get_latency(); 1492 latency = pcmbuf_get_latency();
1447 if (value < latency) 1493 if (value < latency)
1448 CUR_TI->id3.elapsed = 0; 1494 curtrack_id3.elapsed = 0;
1449 else if (value - latency > CUR_TI->id3.elapsed || 1495 else if (value - latency > curtrack_id3.elapsed ||
1450 value - latency < CUR_TI->id3.elapsed - 2) 1496 value - latency < curtrack_id3.elapsed - 2)
1451 { 1497 {
1452 CUR_TI->id3.elapsed = value - latency; 1498 curtrack_id3.elapsed = value - latency;
1453 } 1499 }
1454} 1500}
1455 1501
@@ -1460,68 +1506,48 @@ static void codec_set_offset_callback(size_t value)
1460 if (ci.seek_time) 1506 if (ci.seek_time)
1461 return; 1507 return;
1462 1508
1463 latency = pcmbuf_get_latency() * CUR_TI->id3.bitrate / 8; 1509 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8;
1464 if (value < latency) 1510 if (value < latency)
1465 CUR_TI->id3.offset = 0; 1511 curtrack_id3.offset = 0;
1466 else 1512 else
1467 CUR_TI->id3.offset = value - latency; 1513 curtrack_id3.offset = value - latency;
1468} 1514}
1469 1515
1470static void codec_advance_buffer_counters(size_t amount) 1516static void codec_advance_buffer_counters(size_t amount)
1471{ 1517{
1472 buf_ridx = RINGBUF_ADD(buf_ridx, amount); 1518 bufadvance(CUR_TI->audio_hid, amount);
1473 ci.curpos += amount; 1519 ci.curpos += amount;
1474 CUR_TI->available -= amount;
1475
1476 /* Start buffer filling as necessary. */
1477 if (!pcmbuf_is_lowdata() && !filling)
1478 {
1479 if (FILEBUFUSED < conf_watermark && playing && !playlist_end)
1480 {
1481 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1482 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1483 }
1484 }
1485} 1520}
1486 1521
1487/* copy up-to size bytes into ptr and return the actual size copied */ 1522/* copy up-to size bytes into ptr and return the actual size copied */
1488static size_t codec_filebuf_callback(void *ptr, size_t size) 1523static size_t codec_filebuf_callback(void *ptr, size_t size)
1489{ 1524{
1490 char *buf = (char *)ptr; 1525 ssize_t copy_n;
1491 size_t copy_n;
1492 size_t part_n;
1493 1526
1494 if (ci.stop_codec || !playing) 1527 if (ci.stop_codec || !playing)
1495 return 0; 1528 return 0;
1496 1529
1497 /* The ammount to copy is the lesser of the requested amount and the 1530 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1498 * amount left of the current track (both on disk and already loaded) */
1499 copy_n = MIN(size, CUR_TI->available + CUR_TI->filerem);
1500 1531
1501 /* Nothing requested OR nothing left */ 1532 /* Nothing requested OR nothing left */
1502 if (copy_n == 0) 1533 if (copy_n == 0)
1503 return 0; 1534 return 0;
1504 1535
1536
1537 if (copy_n == -2)
1538 {
1539 buf_request_buffer_handle(CUR_TI->audio_hid);
1540 }
1541
1505 /* Let the disk buffer catch fill until enough data is available */ 1542 /* Let the disk buffer catch fill until enough data is available */
1506 while (copy_n > CUR_TI->available) 1543 while (copy_n == -2)
1507 { 1544 {
1508 if (!filling)
1509 {
1510 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1511 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1512 }
1513
1514 sleep(1); 1545 sleep(1);
1546
1515 if (ci.stop_codec || ci.new_track) 1547 if (ci.stop_codec || ci.new_track)
1516 return 0; 1548 return 0;
1517 }
1518 1549
1519 /* Copy as much as possible without wrapping */ 1550 copy_n = bufread(CUR_TI->audio_hid, size, ptr);
1520 part_n = MIN(copy_n, filebuflen - buf_ridx);
1521 memcpy(buf, &filebuf[buf_ridx], part_n);
1522 /* Copy the rest in the case of a wrap */
1523 if (part_n < copy_n) {
1524 memcpy(&buf[part_n], &filebuf[0], copy_n - part_n);
1525 } 1551 }
1526 1552
1527 /* Update read and other position pointers */ 1553 /* Update read and other position pointers */
@@ -1533,7 +1559,9 @@ static size_t codec_filebuf_callback(void *ptr, size_t size)
1533 1559
1534static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) 1560static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1535{ 1561{
1536 size_t short_n, copy_n, buf_rem; 1562 size_t copy_n = reqsize;
1563 ssize_t ret;
1564 void *ptr;
1537 1565
1538 if (!playing) 1566 if (!playing)
1539 { 1567 {
@@ -1541,48 +1569,38 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
1541 return NULL; 1569 return NULL;
1542 } 1570 }
1543 1571
1544 copy_n = MIN(reqsize, CUR_TI->available + CUR_TI->filerem); 1572 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1545 if (copy_n == 0) 1573 if (ret >= 0)
1574 copy_n = MIN((size_t)ret, reqsize);
1575
1576 if (copy_n == 0)
1546 { 1577 {
1547 *realsize = 0; 1578 *realsize = 0;
1548 return NULL; 1579 return NULL;
1549 } 1580 }
1550 1581
1551 while (copy_n > CUR_TI->available) 1582 if (ret == -2)
1583 {
1584 buf_request_buffer_handle(CUR_TI->audio_hid);
1585 }
1586
1587 /* Let the disk buffer catch fill until enough data is available */
1588 while (ret == -2)
1552 { 1589 {
1553 if (!filling)
1554 {
1555 LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
1556 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
1557 }
1558
1559 sleep(1); 1590 sleep(1);
1591
1560 if (ci.stop_codec || ci.new_track) 1592 if (ci.stop_codec || ci.new_track)
1561 { 1593 {
1562 *realsize = 0; 1594 *realsize = 0;
1563 return NULL; 1595 return NULL;
1564 } 1596 }
1597 ret = bufgetdata(CUR_TI->audio_hid, reqsize, &ptr);
1565 } 1598 }
1566 1599 copy_n = MIN((size_t)ret, reqsize);
1567 /* How much is left at the end of the file buffer before wrap? */
1568 buf_rem = filebuflen - buf_ridx;
1569
1570 /* If we can't satisfy the request without wrapping */
1571 if (buf_rem < copy_n)
1572 {
1573 /* How short are we? */
1574 short_n = copy_n - buf_rem;
1575
1576 /* If we can fudge it with the guardbuf */
1577 if (short_n < GUARD_BUFSIZE)
1578 memcpy(&filebuf[filebuflen], &filebuf[0], short_n);
1579 else
1580 copy_n = buf_rem;
1581 }
1582 1600
1583 *realsize = copy_n; 1601 *realsize = copy_n;
1584 1602
1585 return (char *)&filebuf[buf_ridx]; 1603 return ptr;
1586} /* codec_request_buffer_callback */ 1604} /* codec_request_buffer_callback */
1587 1605
1588static int get_codec_base_type(int type) 1606static int get_codec_base_type(int type)
@@ -1599,50 +1617,13 @@ static int get_codec_base_type(int type)
1599 1617
1600static void codec_advance_buffer_callback(size_t amount) 1618static void codec_advance_buffer_callback(size_t amount)
1601{ 1619{
1602 if (amount > CUR_TI->available + CUR_TI->filerem)
1603 amount = CUR_TI->available + CUR_TI->filerem;
1604
1605 while (amount > CUR_TI->available && filling)
1606 sleep(1);
1607
1608 if (amount > CUR_TI->available)
1609 {
1610 intptr_t result = Q_CODEC_REQUEST_FAILED;
1611
1612 if (!ci.stop_codec)
1613 {
1614 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1615 result = queue_send(&audio_queue, Q_AUDIO_REBUFFER_SEEK,
1616 ci.curpos + amount);
1617 }
1618
1619 switch (result)
1620 {
1621 case Q_CODEC_REQUEST_FAILED:
1622 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1623 ci.stop_codec = true;
1624 return;
1625
1626 case Q_CODEC_REQUEST_COMPLETE:
1627 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1628 return;
1629
1630 default:
1631 LOGFQUEUE("codec |< default");
1632 ci.stop_codec = true;
1633 return;
1634 }
1635 }
1636
1637 codec_advance_buffer_counters(amount); 1620 codec_advance_buffer_counters(amount);
1638
1639 codec_set_offset_callback(ci.curpos); 1621 codec_set_offset_callback(ci.curpos);
1640} 1622}
1641 1623
1642static void codec_advance_buffer_loc_callback(void *ptr) 1624static void codec_advance_buffer_loc_callback(void *ptr)
1643{ 1625{
1644 size_t amount = (size_t)ptr - (size_t)&filebuf[buf_ridx]; 1626 size_t amount = buf_get_offset(CUR_TI->audio_hid, ptr);
1645
1646 codec_advance_buffer_callback(amount); 1627 codec_advance_buffer_callback(amount);
1647} 1628}
1648 1629
@@ -1705,7 +1686,7 @@ static off_t codec_mp3_get_filepos_callback(int newtime)
1705{ 1686{
1706 off_t newpos; 1687 off_t newpos;
1707 1688
1708 CUR_TI->id3.elapsed = newtime; 1689 curtrack_id3.elapsed = newtime;
1709 newpos = codec_get_file_pos(); 1690 newpos = codec_get_file_pos();
1710 1691
1711 return newpos; 1692 return newpos;
@@ -1729,79 +1710,31 @@ static void codec_seek_complete_callback(void)
1729 1710
1730static bool codec_seek_buffer_callback(size_t newpos) 1711static bool codec_seek_buffer_callback(size_t newpos)
1731{ 1712{
1732 int difference;
1733
1734 logf("codec_seek_buffer_callback"); 1713 logf("codec_seek_buffer_callback");
1735 1714
1736 if (newpos >= CUR_TI->filesize) 1715 int ret = bufseek(CUR_TI->audio_hid, newpos);
1737 newpos = CUR_TI->filesize - 1; 1716 if (ret == 0) {
1738 1717 ci.curpos = newpos;
1739 difference = newpos - ci.curpos;
1740 if (difference >= 0)
1741 {
1742 /* Seeking forward */
1743 logf("seek: +%d", difference);
1744 codec_advance_buffer_callback(difference);
1745 return true; 1718 return true;
1746 } 1719 }
1747 1720 else {
1748 /* Seeking backward */ 1721 return false;
1749 difference = -difference;
1750 if (ci.curpos - difference < 0)
1751 difference = ci.curpos;
1752
1753 /* We need to reload the song. */
1754 if (newpos < CUR_TI->start_pos)
1755 {
1756 intptr_t result = Q_CODEC_REQUEST_FAILED;
1757
1758 if (!ci.stop_codec)
1759 {
1760 LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
1761 result = queue_send(&audio_queue, Q_AUDIO_REBUFFER_SEEK,
1762 newpos);
1763 }
1764
1765 switch (result)
1766 {
1767 case Q_CODEC_REQUEST_COMPLETE:
1768 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1769 return true;
1770
1771 case Q_CODEC_REQUEST_FAILED:
1772 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1773 ci.stop_codec = true;
1774 return false;
1775
1776 default:
1777 LOGFQUEUE("codec |< default");
1778 return false;
1779 }
1780 } 1722 }
1781
1782 /* Seeking inside buffer space. */
1783 logf("seek: -%d", difference);
1784 CUR_TI->available += difference;
1785 buf_ridx = RINGBUF_SUB(buf_ridx, (unsigned)difference);
1786 ci.curpos -= difference;
1787
1788 return true;
1789} 1723}
1790 1724
1791static void codec_configure_callback(int setting, intptr_t value) 1725static void codec_configure_callback(int setting, intptr_t value)
1792{ 1726{
1793 switch (setting) { 1727 switch (setting) {
1794 case CODEC_SET_FILEBUF_WATERMARK: 1728 case CODEC_SET_FILEBUF_WATERMARK:
1795 conf_watermark = value; 1729 set_filebuf_watermark(buffer_margin, value);
1796 set_filebuf_watermark(buffer_margin);
1797 break; 1730 break;
1798 1731
1799 case CODEC_SET_FILEBUF_CHUNKSIZE: 1732 case CODEC_SET_FILEBUF_CHUNKSIZE:
1800 conf_filechunk = value; 1733 buf_set_conf(BUFFERING_SET_CHUNKSIZE, value);
1801 break; 1734 break;
1802 1735
1803 case CODEC_SET_FILEBUF_PRESEEK: 1736 case CODEC_SET_FILEBUF_PRESEEK:
1804 conf_preseek = value; 1737 buf_set_conf(BUFFERING_SET_PRESEEK, value);
1805 break; 1738 break;
1806 1739
1807 default: 1740 default:
@@ -1811,7 +1744,6 @@ static void codec_configure_callback(int setting, intptr_t value)
1811 1744
1812static void codec_track_changed(void) 1745static void codec_track_changed(void)
1813{ 1746{
1814 automatic_skip = false;
1815 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED"); 1747 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1816 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); 1748 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1817} 1749}
@@ -1824,28 +1756,12 @@ static void codec_pcmbuf_track_changed_callback(void)
1824 1756
1825static void codec_discard_codec_callback(void) 1757static void codec_discard_codec_callback(void)
1826{ 1758{
1827 if (CUR_TI->has_codec) 1759 if (CUR_TI->codec_hid > 0)
1828 { 1760 {
1829 CUR_TI->has_codec = false; 1761 bufclose(CUR_TI->codec_hid);
1830 buf_ridx = RINGBUF_ADD(buf_ridx, CUR_TI->codecsize); 1762 CUR_TI->codec_hid = 0;
1763 CUR_TI->codecsize = 0;
1831 } 1764 }
1832
1833#if 0
1834 /* Check if a buffer desync has happened, log it and stop playback. */
1835 if (buf_ridx != CUR_TI->buf_idx)
1836 {
1837 int offset = CUR_TI->buf_idx - buf_ridx;
1838 size_t new_used = FILEBUFUSED - offset;
1839
1840 logf("Buf off :%d=%d-%d", offset, CUR_TI->buf_idx, buf_ridx);
1841 logf("Used off:%d",FILEBUFUSED - new_used);
1842
1843 /* This is a fatal internal error and it's not safe to
1844 * continue playback. */
1845 ci.stop_codec = true;
1846 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
1847 }
1848#endif
1849} 1765}
1850 1766
1851static inline void codec_gapless_track_change(void) { 1767static inline void codec_gapless_track_change(void) {
@@ -1899,7 +1815,7 @@ static bool codec_load_next_track(void)
1899{ 1815{
1900 intptr_t result = Q_CODEC_REQUEST_FAILED; 1816 intptr_t result = Q_CODEC_REQUEST_FAILED;
1901 1817
1902 prev_track_elapsed = CUR_TI->id3.elapsed; 1818 prev_track_elapsed = curtrack_id3.elapsed;
1903 1819
1904 if (ci.seek_time) 1820 if (ci.seek_time)
1905 codec_seek_complete_callback(); 1821 codec_seek_complete_callback();
@@ -1950,13 +1866,18 @@ static bool codec_request_next_track_callback(void)
1950 if (ci.stop_codec || !playing) 1866 if (ci.stop_codec || !playing)
1951 return false; 1867 return false;
1952 1868
1953 prev_codectype = get_codec_base_type(CUR_TI->id3.codectype); 1869 prev_codectype = get_codec_base_type(curtrack_id3.codectype);
1954 1870
1955 if (!codec_load_next_track()) 1871 if (!codec_load_next_track())
1956 return false; 1872 return false;
1957 1873
1874 /* Seek to the beginning of the new track because if the struct mp3entry was
1875 buffered, "elapsed" might not be zero (if the track has been played
1876 already but not unbuffered) */
1877 codec_seek_buffer_callback(0);
1878
1958 /* Check if the next codec is the same file. */ 1879 /* Check if the next codec is the same file. */
1959 if (prev_codectype == get_codec_base_type(CUR_TI->id3.codectype)) 1880 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype))
1960 { 1881 {
1961 logf("New track loaded"); 1882 logf("New track loaded");
1962 codec_discard_codec_callback(); 1883 codec_discard_codec_callback();
@@ -1964,7 +1885,7 @@ static bool codec_request_next_track_callback(void)
1964 } 1885 }
1965 else 1886 else
1966 { 1887 {
1967 logf("New codec:%d/%d", CUR_TI->id3.codectype, prev_codectype); 1888 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype);
1968 return false; 1889 return false;
1969 } 1890 }
1970} 1891}
@@ -1982,6 +1903,7 @@ static void codec_thread(void)
1982 switch (ev.id) { 1903 switch (ev.id) {
1983 case Q_CODEC_LOAD_DISK: 1904 case Q_CODEC_LOAD_DISK:
1984 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK"); 1905 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1906 queue_reply(&codec_queue, 1);
1985 audio_codec_loaded = true; 1907 audio_codec_loaded = true;
1986#ifdef PLAYBACK_VOICE 1908#ifdef PLAYBACK_VOICE
1987 /* Don't sent messages to voice codec if it's already swapped 1909 /* Don't sent messages to voice codec if it's already swapped
@@ -2004,7 +1926,7 @@ static void codec_thread(void)
2004 1926
2005 case Q_CODEC_LOAD: 1927 case Q_CODEC_LOAD:
2006 LOGFQUEUE("codec < Q_CODEC_LOAD"); 1928 LOGFQUEUE("codec < Q_CODEC_LOAD");
2007 if (!CUR_TI->has_codec) { 1929 if (CUR_TI->codec_hid <= 0) {
2008 logf("Codec slot is empty!"); 1930 logf("Codec slot is empty!");
2009 /* Wait for the pcm buffer to go empty */ 1931 /* Wait for the pcm buffer to go empty */
2010 while (pcm_is_playing()) 1932 while (pcm_is_playing())
@@ -2028,8 +1950,8 @@ static void codec_thread(void)
2028#endif 1950#endif
2029 set_current_codec(CODEC_IDX_AUDIO); 1951 set_current_codec(CODEC_IDX_AUDIO);
2030 ci.stop_codec = false; 1952 ci.stop_codec = false;
2031 wrap = (size_t)&filebuf[filebuflen] - (size_t)CUR_TI->codecbuf; 1953 wrap = (size_t)&filebuf[filebuflen] - (size_t)bufgetcodec(CUR_TI);
2032 status = codec_load_ram(CUR_TI->codecbuf, CUR_TI->codecsize, 1954 status = codec_load_ram(bufgetcodec(CUR_TI), CUR_TI->codecsize,
2033 &filebuf[0], wrap, &ci); 1955 &filebuf[0], wrap, &ci);
2034#ifdef PLAYBACK_VOICE 1956#ifdef PLAYBACK_VOICE
2035 semaphore_release(&sem_codecthread); 1957 semaphore_release(&sem_codecthread);
@@ -2098,7 +2020,7 @@ static void codec_thread(void)
2098 logf("Codec failure"); 2020 logf("Codec failure");
2099 gui_syncsplash(HZ*2, "Codec failure"); 2021 gui_syncsplash(HZ*2, "Codec failure");
2100 } 2022 }
2101 2023
2102 if (!codec_load_next_track()) 2024 if (!codec_load_next_track())
2103 { 2025 {
2104 LOGFQUEUE("codec > audio Q_AUDIO_STOP"); 2026 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
@@ -2116,8 +2038,8 @@ static void codec_thread(void)
2116 * triggering the WPS exit */ 2038 * triggering the WPS exit */
2117 while(pcm_is_playing()) 2039 while(pcm_is_playing())
2118 { 2040 {
2119 CUR_TI->id3.elapsed = 2041 curtrack_id3.elapsed =
2120 CUR_TI->id3.length - pcmbuf_get_latency(); 2042 curtrack_id3.length - pcmbuf_get_latency();
2121 sleep(1); 2043 sleep(1);
2122 } 2044 }
2123 LOGFQUEUE("codec > audio Q_AUDIO_STOP"); 2045 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
@@ -2126,8 +2048,8 @@ static void codec_thread(void)
2126 break; 2048 break;
2127 } 2049 }
2128 } 2050 }
2129 2051
2130 if (CUR_TI->has_codec) 2052 if (CUR_TI->codec_hid > 0)
2131 { 2053 {
2132 LOGFQUEUE("codec > codec Q_CODEC_LOAD"); 2054 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2133 queue_post(&codec_queue, Q_CODEC_LOAD, 0); 2055 queue_post(&codec_queue, Q_CODEC_LOAD, 0);
@@ -2135,7 +2057,7 @@ static void codec_thread(void)
2135 else 2057 else
2136 { 2058 {
2137 const char *codec_fn = 2059 const char *codec_fn =
2138 get_codec_filename(CUR_TI->id3.codectype); 2060 get_codec_filename(curtrack_id3.codectype);
2139 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 2061 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2140 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, 2062 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
2141 (intptr_t)codec_fn); 2063 (intptr_t)codec_fn);
@@ -2171,11 +2093,6 @@ static void codec_thread(void)
2171 2093
2172/* --- Audio thread --- */ 2094/* --- Audio thread --- */
2173 2095
2174static bool audio_filebuf_is_lowdata(void)
2175{
2176 return FILEBUFUSED < AUDIO_FILEBUF_CRITICAL;
2177}
2178
2179static bool audio_have_tracks(void) 2096static bool audio_have_tracks(void)
2180{ 2097{
2181 return track_ridx != track_widx || CUR_TI->filesize; 2098 return track_ridx != track_widx || CUR_TI->filesize;
@@ -2208,142 +2125,41 @@ int audio_track_count(void)
2208 2125
2209long audio_filebufused(void) 2126long audio_filebufused(void)
2210{ 2127{
2211 return (long) FILEBUFUSED; 2128 return (long) buf_used();
2212}
2213
2214/* Count the data BETWEEN the selected tracks */
2215static size_t audio_buffer_count_tracks(int from_track, int to_track)
2216{
2217 size_t amount = 0;
2218 bool need_wrap = to_track < from_track;
2219
2220 while (1)
2221 {
2222 if (++from_track >= MAX_TRACK)
2223 {
2224 from_track -= MAX_TRACK;
2225 need_wrap = false;
2226 }
2227
2228 if (from_track >= to_track && !need_wrap)
2229 break;
2230
2231 amount += tracks[from_track].codecsize + tracks[from_track].filesize;
2232 }
2233 return amount;
2234}
2235
2236static bool audio_buffer_wind_forward(int new_track_ridx, int old_track_ridx)
2237{
2238 size_t amount;
2239
2240 /* Start with the remainder of the previously playing track */
2241 amount = tracks[old_track_ridx].filesize - ci.curpos;
2242 /* Then collect all data from tracks in between them */
2243 amount += audio_buffer_count_tracks(old_track_ridx, new_track_ridx);
2244 logf("bwf:%ldB", (long) amount);
2245
2246 if (amount > FILEBUFUSED)
2247 return false;
2248
2249 /* Wind the buffer to the beginning of the target track or its codec */
2250 buf_ridx = RINGBUF_ADD(buf_ridx, amount);
2251
2252 return true;
2253} 2129}
2254 2130
2255static bool audio_buffer_wind_backward(int new_track_ridx, int old_track_ridx) 2131static void audio_update_trackinfo(void)
2256{ 2132{
2257 /* Available buffer data */ 2133 if (CUR_TI->id3_hid > 0)
2258 size_t buf_back; 2134 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid));
2259 /* Start with the previously playing track's data and our data */
2260 size_t amount;
2261
2262 amount = ci.curpos;
2263 buf_back = RINGBUF_SUB(buf_ridx, buf_widx);
2264
2265 /* If we're not just resetting the current track */
2266 if (new_track_ridx != old_track_ridx)
2267 {
2268 /* Need to wind to before the old track's codec and our filesize */
2269 amount += tracks[old_track_ridx].codecsize;
2270 amount += tracks[new_track_ridx].filesize;
2271 2135
2272 /* Rewind the old track to its beginning */ 2136 CUR_TI->taginfo_ready = (CUR_TI->id3_hid > 0);
2273 tracks[old_track_ridx].available =
2274 tracks[old_track_ridx].filesize - tracks[old_track_ridx].filerem;
2275 }
2276
2277 /* If the codec was ever buffered */
2278 if (tracks[new_track_ridx].codecsize)
2279 {
2280 /* Add the codec to the needed size */
2281 amount += tracks[new_track_ridx].codecsize;
2282 tracks[new_track_ridx].has_codec = true;
2283 }
2284
2285 /* Then collect all data from tracks between new and old */
2286 amount += audio_buffer_count_tracks(new_track_ridx, old_track_ridx);
2287
2288 /* Do we have space to make this skip? */
2289 if (amount > buf_back)
2290 return false;
2291 2137
2292 logf("bwb:%ldB",amount); 2138 int next_idx = track_ridx + 1;
2293 2139 next_idx &= MAX_TRACK_MASK;
2294 /* Rewind the buffer to the beginning of the target track or its codec */
2295 buf_ridx = RINGBUF_SUB(buf_ridx, amount);
2296 2140
2297 /* Reset to the beginning of the new track */ 2141 if (tracks[next_idx].id3_hid > 0)
2298 tracks[new_track_ridx].available = tracks[new_track_ridx].filesize; 2142 copy_mp3entry(&nexttrack_id3, bufgetid3(tracks[next_idx].id3_hid));
2299 2143
2300 return true; 2144 tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid > 0);
2301}
2302 2145
2303static void audio_update_trackinfo(void)
2304{
2305 ci.filesize = CUR_TI->filesize; 2146 ci.filesize = CUR_TI->filesize;
2306 CUR_TI->id3.elapsed = 0; 2147 curtrack_id3.elapsed = 0;
2307 CUR_TI->id3.offset = 0; 2148 curtrack_id3.offset = 0;
2308 ci.id3 = &CUR_TI->id3; 2149 ci.id3 = &curtrack_id3;
2309 ci.curpos = 0; 2150 ci.curpos = 0;
2310 ci.taginfo_ready = &CUR_TI->taginfo_ready; 2151 ci.taginfo_ready = &CUR_TI->taginfo_ready;
2311} 2152}
2312 2153
2313/* Yield to codecs for as long as possible if they are in need of data
2314 * return true if the caller should break to let the audio thread process
2315 * new events */
2316static bool audio_yield_codecs(void)
2317{
2318 yield();
2319
2320 if (!queue_empty(&audio_queue))
2321 return true;
2322
2323 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
2324 && !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
2325 {
2326 if (filling)
2327 yield();
2328 else
2329 sleep(2);
2330
2331 if (!queue_empty(&audio_queue))
2332 return true;
2333 }
2334
2335 return false;
2336}
2337
2338static void audio_clear_track_entries(bool clear_unbuffered) 2154static void audio_clear_track_entries(bool clear_unbuffered)
2339{ 2155{
2340 int cur_idx = track_widx; 2156 int cur_idx = track_widx;
2341 int last_idx = -1; 2157 int last_idx = -1;
2342 2158
2343 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered); 2159 logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
2344 2160
2345 /* Loop over all tracks from write-to-read */ 2161 /* Loop over all tracks from write-to-read */
2346 while (1) 2162 while (1)
2347 { 2163 {
2348 cur_idx++; 2164 cur_idx++;
2349 cur_idx &= MAX_TRACK_MASK; 2165 cur_idx &= MAX_TRACK_MASK;
@@ -2353,21 +2169,21 @@ static void audio_clear_track_entries(bool clear_unbuffered)
2353 2169
2354 /* If the track is buffered, conditionally clear/notify, 2170 /* If the track is buffered, conditionally clear/notify,
2355 * otherwise clear the track if that option is selected */ 2171 * otherwise clear the track if that option is selected */
2356 if (tracks[cur_idx].event_sent) 2172 if (tracks[cur_idx].event_sent)
2357 { 2173 {
2358 if (last_idx >= 0) 2174 if (last_idx >= 0)
2359 { 2175 {
2360 /* If there is an unbuffer callback, call it, otherwise, 2176 /* If there is an unbuffer callback, call it, otherwise,
2361 * just clear the track */ 2177 * just clear the track */
2362 if (track_unbuffer_callback) 2178 if (track_unbuffer_callback && tracks[last_idx].id3_hid > 0)
2363 track_unbuffer_callback(&tracks[last_idx].id3, false); 2179 track_unbuffer_callback(bufgetid3(tracks[last_idx].id3_hid), false);
2364 2180
2365 memset(&tracks[last_idx], 0, sizeof(struct track_info)); 2181 clear_track_info(&tracks[last_idx]);
2366 } 2182 }
2367 last_idx = cur_idx; 2183 last_idx = cur_idx;
2368 } 2184 }
2369 else if (clear_unbuffered) 2185 else if (clear_unbuffered)
2370 memset(&tracks[cur_idx], 0, sizeof(struct track_info)); 2186 clear_track_info(&tracks[cur_idx]);
2371 } 2187 }
2372 2188
2373 /* We clear the previous instance of a buffered track throughout 2189 /* We clear the previous instance of a buffered track throughout
@@ -2375,203 +2191,51 @@ static void audio_clear_track_entries(bool clear_unbuffered)
2375 * the last track here */ 2191 * the last track here */
2376 if (last_idx >= 0) 2192 if (last_idx >= 0)
2377 { 2193 {
2378 if (track_unbuffer_callback) 2194 if (track_unbuffer_callback && tracks[last_idx].id3_hid > 0)
2379 track_unbuffer_callback(&tracks[last_idx].id3, true); 2195 track_unbuffer_callback(bufgetid3(tracks[last_idx].id3_hid), true);
2380 memset(&tracks[last_idx], 0, sizeof(struct track_info)); 2196 clear_track_info(&tracks[last_idx]);
2381 } 2197 }
2382} 2198}
2383 2199
2384/* FIXME: This code should be made more generic and move to metadata.c */ 2200static bool audio_release_tracks(void)
2385static void audio_strip_tags(void)
2386{ 2201{
2387 int i; 2202 int i, cur_idx;
2388 static const unsigned char tag[] = "TAG";
2389 static const unsigned char apetag[] = "APETAGEX";
2390 size_t tag_idx;
2391 size_t cur_idx;
2392 size_t len, version;
2393 2203
2394 tag_idx = RINGBUF_SUB(buf_widx, 128); 2204 logf("releasing all tracks");
2395 2205
2396 if (FILEBUFUSED > 128 && tag_idx > buf_ridx) 2206 for(i = 0; i < MAX_TRACKS; i++)
2397 { 2207 {
2398 cur_idx = tag_idx; 2208 cur_idx = (track_ridx + i) & MAX_TRACK_MASK;
2399 for(i = 0;i < 3;i++) 2209 if (!clear_track_info(&tracks[cur_idx]))
2400 { 2210 return false;
2401 if(filebuf[cur_idx] != tag[i])
2402 goto strip_ape_tag;
2403
2404 cur_idx = RINGBUF_ADD(cur_idx, 1);
2405 }
2406
2407 /* Skip id3v1 tag */
2408 logf("Skipping ID3v1 tag");
2409 buf_widx = tag_idx;
2410 tracks[track_widx].available -= 128;
2411 tracks[track_widx].filesize -= 128;
2412 }
2413
2414strip_ape_tag:
2415 /* Check for APE tag (look for the APE tag footer) */
2416 tag_idx = RINGBUF_SUB(buf_widx, 32);
2417
2418 if (FILEBUFUSED > 32 && tag_idx > buf_ridx)
2419 {
2420 cur_idx = tag_idx;
2421 for(i = 0;i < 8;i++)
2422 {
2423 if(filebuf[cur_idx] != apetag[i])
2424 return;
2425
2426 cur_idx = RINGBUF_ADD(cur_idx, 1);
2427 }
2428
2429 /* Read the version and length from the footer */
2430 version = filebuf[tag_idx+8] | (filebuf[tag_idx+9] << 8) |
2431 (filebuf[tag_idx+10] << 16) | (filebuf[tag_idx+11] << 24);
2432 len = filebuf[tag_idx+12] | (filebuf[tag_idx+13] << 8) |
2433 (filebuf[tag_idx+14] << 16) | (filebuf[tag_idx+15] << 24);
2434 if (version == 2000)
2435 len += 32; /* APEv2 has a 32 byte header */
2436
2437 /* Skip APE tag */
2438 if (FILEBUFUSED > len)
2439 {
2440 logf("Skipping APE tag (%ldB)", len);
2441 buf_widx = RINGBUF_SUB(buf_widx, len);
2442 tracks[track_widx].available -= len;
2443 tracks[track_widx].filesize -= len;
2444 }
2445 }
2446}
2447
2448/* Returns true if a whole file is read, false otherwise */
2449static bool audio_read_file(size_t minimum)
2450{
2451 bool ret_val = false;
2452
2453 /* If we're called and no file is open, this is an error */
2454 if (current_fd < 0)
2455 {
2456 logf("Bad fd in arf");
2457 /* Give some hope of miraculous recovery by forcing a track reload */
2458 tracks[track_widx].filesize = 0;
2459 /* Stop this buffering run */
2460 return ret_val;
2461 }
2462
2463 trigger_cpu_boost();
2464 while (tracks[track_widx].filerem > 0)
2465 {
2466 size_t copy_n;
2467 int overlap;
2468 int rc;
2469
2470 /* copy_n is the largest chunk that is safe to read */
2471 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
2472
2473 /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
2474 if (RINGBUF_ADD_CROSS(buf_widx,copy_n,buf_ridx) >= 0)
2475 break;
2476
2477 /* rc is the actual amount read */
2478 rc = read(current_fd, &filebuf[buf_widx], copy_n);
2479
2480 if (rc < 0)
2481 {
2482 logf("File ended %ldB early", tracks[track_widx].filerem);
2483 tracks[track_widx].filesize -= tracks[track_widx].filerem;
2484 tracks[track_widx].filerem = 0;
2485 break;
2486 }
2487
2488 /* How much of the playing track did we overwrite */
2489 if (buf_widx == CUR_TI->buf_idx)
2490 {
2491 /* Special handling; zero or full overlap? */
2492 if (track_widx == track_ridx && CUR_TI->available == 0)
2493 overlap = 0;
2494 else
2495 overlap = rc;
2496 }
2497 else
2498 overlap = RINGBUF_ADD_CROSS(buf_widx,rc,CUR_TI->buf_idx);
2499
2500 if ((unsigned)rc > tracks[track_widx].filerem)
2501 {
2502 logf("Bad: rc-filerem=%ld, fixing", rc-tracks[track_widx].filerem);
2503 tracks[track_widx].filesize += rc - tracks[track_widx].filerem;
2504 tracks[track_widx].filerem = rc;
2505 }
2506
2507 /* Advance buffer */
2508 buf_widx = RINGBUF_ADD(buf_widx, rc);
2509 tracks[track_widx].available += rc;
2510 tracks[track_widx].filerem -= rc;
2511
2512 /* If we write into the playing track, adjust it's buffer info */
2513 if (overlap > 0)
2514 {
2515 CUR_TI->buf_idx += overlap;
2516 CUR_TI->start_pos += overlap;
2517 }
2518
2519 /* For a rebuffer, fill at least this minimum */
2520 if (minimum > (unsigned)rc)
2521 minimum -= rc;
2522 /* Let the codec process up to the watermark */
2523 /* Break immediately if this is a quick buffer, or there is an event */
2524 else if (minimum || audio_yield_codecs())
2525 {
2526 /* Exit quickly, but don't stop the overall buffering process */
2527 ret_val = true;
2528 break;
2529 }
2530 } 2211 }
2531 2212
2532 if (tracks[track_widx].filerem == 0) 2213 return true;
2533 {
2534 logf("Finished buf:%ldB", tracks[track_widx].filesize);
2535 close(current_fd);
2536 current_fd = -1;
2537 audio_strip_tags();
2538
2539 track_widx++;
2540 track_widx &= MAX_TRACK_MASK;
2541
2542 tracks[track_widx].filesize = 0;
2543 return true;
2544 }
2545 else
2546 {
2547 logf("%s buf:%ldB", ret_val?"Quick":"Partially",
2548 tracks[track_widx].filesize - tracks[track_widx].filerem);
2549 return ret_val;
2550 }
2551} 2214}
2552 2215
2553static bool audio_loadcodec(bool start_play) 2216static bool audio_loadcodec(bool start_play)
2554{ 2217{
2555 size_t size = 0;
2556 int fd; 2218 int fd;
2557 int rc;
2558 size_t copy_n;
2559 int prev_track; 2219 int prev_track;
2560 char codec_path[MAX_PATH]; /* Full path to codec */ 2220 char codec_path[MAX_PATH]; /* Full path to codec */
2561 2221
2222 if (tracks[track_widx].id3_hid <= 0) {
2223 return false;
2224 }
2225
2562 const char * codec_fn = 2226 const char * codec_fn =
2563 get_codec_filename(tracks[track_widx].id3.codectype); 2227 get_codec_filename(bufgetid3(tracks[track_widx].id3_hid)->codectype);
2564 if (codec_fn == NULL) 2228 if (codec_fn == NULL)
2565 return false; 2229 return false;
2566 2230
2567 tracks[track_widx].has_codec = false; 2231 tracks[track_widx].codec_hid = 0;
2568 2232
2569 if (start_play) 2233 if (start_play)
2570 { 2234 {
2571 /* Load the codec directly from disk and save some memory. */ 2235 /* Load the codec directly from disk and save some memory. */
2572 track_ridx = track_widx; 2236 track_ridx = track_widx;
2573 ci.filesize = CUR_TI->filesize; 2237 ci.filesize = CUR_TI->filesize;
2574 ci.id3 = &CUR_TI->id3; 2238 ci.id3 = &curtrack_id3;
2575 ci.taginfo_ready = &CUR_TI->taginfo_ready; 2239 ci.taginfo_ready = &CUR_TI->taginfo_ready;
2576 ci.curpos = 0; 2240 ci.curpos = 0;
2577 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 2241 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
@@ -2584,11 +2248,13 @@ static bool audio_loadcodec(bool start_play)
2584 if (track_widx != track_ridx) 2248 if (track_widx != track_ridx)
2585 { 2249 {
2586 prev_track = (track_widx - 1) & MAX_TRACK_MASK; 2250 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
2587 2251
2588 /* If the previous codec is the same as this one, there is no need 2252 /* If the previous codec is the same as this one, there is no need
2589 * to put another copy of it on the file buffer */ 2253 * to put another copy of it on the file buffer */
2590 if (get_codec_base_type(tracks[track_widx].id3.codectype) == 2254 if (get_codec_base_type(
2591 get_codec_base_type(tracks[prev_track].id3.codectype) 2255 bufgetid3(tracks[track_widx].id3_hid)->codectype) ==
2256 get_codec_base_type(
2257 bufgetid3(tracks[prev_track].id3_hid)->codectype)
2592 && audio_codec_loaded) 2258 && audio_codec_loaded)
2593 { 2259 {
2594 logf("Reusing prev. codec"); 2260 logf("Reusing prev. codec");
@@ -2607,39 +2273,17 @@ static bool audio_loadcodec(bool start_play)
2607 } 2273 }
2608 2274
2609 tracks[track_widx].codecsize = filesize(fd); 2275 tracks[track_widx].codecsize = filesize(fd);
2610 2276
2611 /* Never load a partial codec */ 2277 tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC);
2612 if (RINGBUF_ADD_CROSS(buf_widx,tracks[track_widx].codecsize,buf_ridx) >= 0) 2278 if (tracks[track_widx].codec_hid < 0)
2613 { 2279 {
2614 logf("Not enough space"); 2280 logf("Not enough space");
2615 close(fd); 2281 close(fd);
2616 return false; 2282 return false;
2617 } 2283 }
2618 2284
2619 while (size < tracks[track_widx].codecsize)
2620 {
2621 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
2622 rc = read(fd, &filebuf[buf_widx], copy_n);
2623 if (rc < 0)
2624 {
2625 close(fd);
2626 /* This is an error condition, likely the codec file is corrupt */
2627 logf("Partial codec loaded");
2628 /* Must undo the buffer write of the partial codec */
2629 buf_widx = RINGBUF_SUB(buf_widx, size);
2630 tracks[track_widx].codecsize = 0;
2631 return false;
2632 }
2633
2634 buf_widx = RINGBUF_ADD(buf_widx, rc);
2635
2636 size += rc;
2637 }
2638
2639 tracks[track_widx].has_codec = true;
2640
2641 close(fd); 2285 close(fd);
2642 logf("Done: %ldB", size); 2286 logf("Loaded codec");
2643 2287
2644 return true; 2288 return true;
2645} 2289}
@@ -2700,94 +2344,99 @@ static void audio_set_elapsed(struct mp3entry* id3)
2700 } 2344 }
2701} 2345}
2702 2346
2703static bool audio_load_track(int offset, bool start_play, bool rebuffer) 2347/* Load one track by making the appropriate bufopen calls. Return true if
2348 everything required was loaded correctly, false if not. */
2349static bool audio_load_track(int offset, bool start_play)
2704{ 2350{
2705 char *trackname; 2351 char *trackname;
2706 off_t size;
2707 char msgbuf[80]; 2352 char msgbuf[80];
2353 int fd = -1;
2354 int file_offset = 0;
2355 struct mp3entry id3;
2708 2356
2709 /* Stop buffer filling if there is no free track entries. 2357 /* Stop buffer filling if there is no free track entries.
2710 Don't fill up the last track entry (we wan't to store next track 2358 Don't fill up the last track entry (we wan't to store next track
2711 metadata there). */ 2359 metadata there). */
2712 if (!audio_have_free_tracks()) 2360 if (!audio_have_free_tracks())
2713 { 2361 {
2714 logf("No free tracks"); 2362 logf("No free tracks");
2715 return false; 2363 return false;
2716 } 2364 }
2717 2365
2718 if (current_fd >= 0)
2719 {
2720 logf("Nonzero fd in alt");
2721 close(current_fd);
2722 current_fd = -1;
2723 }
2724
2725 last_peek_offset++; 2366 last_peek_offset++;
2726 peek_again: 2367 peek_again:
2727 logf("Buffering track:%d/%d", track_widx, track_ridx); 2368 logf("Buffering track:%d/%d", track_widx, track_ridx);
2728 /* Get track name from current playlist read position. */ 2369 /* Get track name from current playlist read position. */
2729 while ((trackname = playlist_peek(last_peek_offset)) != NULL) 2370 while ((trackname = playlist_peek(last_peek_offset)) != NULL)
2730 { 2371 {
2731 /* Handle broken playlists. */ 2372 /* Handle broken playlists. */
2732 current_fd = open(trackname, O_RDONLY); 2373 fd = open(trackname, O_RDONLY);
2733 if (current_fd < 0) 2374 if (fd < 0)
2734 { 2375 {
2735 logf("Open failed"); 2376 logf("Open failed");
2736 /* Skip invalid entry from playlist. */ 2377 /* Skip invalid entry from playlist. */
2737 playlist_skip_entry(NULL, last_peek_offset); 2378 playlist_skip_entry(NULL, last_peek_offset);
2738 } 2379 }
2739 else 2380 else
2740 break; 2381 break;
2741 } 2382 }
2742 2383
2743 if (!trackname) 2384 if (!trackname)
2744 { 2385 {
2745 logf("End-of-playlist"); 2386 logf("End-of-playlist");
2746 playlist_end = true; 2387 playlist_end = true;
2747 return false; 2388 return false;
2748 } 2389 }
2749 2390
2750 /* Initialize track entry. */ 2391 tracks[track_widx].filesize = filesize(fd);
2751 size = filesize(current_fd);
2752 tracks[track_widx].filerem = size;
2753 tracks[track_widx].filesize = size;
2754 tracks[track_widx].available = 0;
2755 2392
2756 /* Set default values */ 2393 /* Set default values */
2757 if (start_play) 2394 if (start_play)
2758 { 2395 {
2759 int last_codec = current_codec; 2396 int last_codec = current_codec;
2760 2397
2761 set_current_codec(CODEC_IDX_AUDIO); 2398 set_current_codec(CODEC_IDX_AUDIO);
2762 conf_watermark = AUDIO_DEFAULT_WATERMARK; 2399 buf_set_conf(BUFFERING_SET_WATERMARK, AUDIO_DEFAULT_WATERMARK);
2763 conf_filechunk = AUDIO_DEFAULT_FILECHUNK; 2400 buf_set_conf(BUFFERING_SET_CHUNKSIZE, AUDIO_DEFAULT_FILECHUNK);
2764 conf_preseek = AUDIO_REBUFFER_GUESS_SIZE; 2401 buf_set_conf(BUFFERING_SET_PRESEEK, AUDIO_REBUFFER_GUESS_SIZE);
2765 dsp_configure(DSP_RESET, 0); 2402 dsp_configure(DSP_RESET, 0);
2766 set_current_codec(last_codec); 2403 set_current_codec(last_codec);
2404
2405 track_changed = true;
2406 playlist_update_resume_info(audio_current_track());
2767 } 2407 }
2768 2408
2769 /* Get track metadata if we don't already have it. */ 2409 /* Get track metadata if we don't already have it. */
2770 if (!tracks[track_widx].taginfo_ready) 2410 if (tracks[track_widx].id3_hid <= 0)
2771 { 2411 {
2772 if (get_metadata(&(tracks[track_widx].id3),current_fd,trackname)) 2412 if (get_metadata(&id3, fd, trackname))
2773 { 2413 {
2774 tracks[track_widx].taginfo_ready = true; 2414 tracks[track_widx].id3_hid = bufalloc(&id3, sizeof(struct mp3entry),
2775 if (start_play) 2415 TYPE_ID3);
2416 tracks[track_widx].taginfo_ready = (tracks[track_widx].id3_hid > 0);
2417
2418 if (tracks[track_widx].id3_hid <= 0)
2419 {
2420 last_peek_offset--;
2421 close(fd);
2422 return false;
2423 }
2424
2425 if (track_widx == track_ridx)
2426 copy_mp3entry(&curtrack_id3, &id3);
2427 else if (track_widx == ((track_ridx + 1) & MAX_TRACK_MASK))
2428 copy_mp3entry(&nexttrack_id3, &id3);
2429
2430 if (start_play)
2776 { 2431 {
2777 track_changed = true; 2432 track_changed = true;
2778 playlist_update_resume_info(audio_current_track()); 2433 playlist_update_resume_info(audio_current_track());
2779 } 2434 }
2780 } 2435 }
2781 else 2436 else
2782 { 2437 {
2783 logf("mde:%s!",trackname); 2438 logf("mde:%s!",trackname);
2784 2439
2785 /* Set filesize to zero to indicate no file was loaded. */
2786 tracks[track_widx].filesize = 0;
2787 tracks[track_widx].filerem = 0;
2788 close(current_fd);
2789 current_fd = -1;
2790
2791 /* Skip invalid entry from playlist. */ 2440 /* Skip invalid entry from playlist. */
2792 playlist_skip_entry(NULL, last_peek_offset); 2441 playlist_skip_entry(NULL, last_peek_offset);
2793 tracks[track_widx].taginfo_ready = false; 2442 tracks[track_widx].taginfo_ready = false;
@@ -2796,6 +2445,9 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2796 2445
2797 } 2446 }
2798 2447
2448 close(fd);
2449
2450#if 0
2799 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1) 2451 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1)
2800 { 2452 {
2801 char cuepath[MAX_PATH]; 2453 char cuepath[MAX_PATH];
@@ -2810,17 +2462,11 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2810 cue_spoof_id3(curr_cue, &tracks[track_widx].id3); 2462 cue_spoof_id3(curr_cue, &tracks[track_widx].id3);
2811 } 2463 }
2812 } 2464 }
2465#endif
2813 2466
2814 /* Load the codec. */ 2467 /* Load the codec. */
2815 tracks[track_widx].codecbuf = &filebuf[buf_widx]; 2468 if (!audio_loadcodec(start_play))
2816 if (!audio_loadcodec(start_play))
2817 { 2469 {
2818 /* Set filesize to zero to indicate no file was loaded. */
2819 tracks[track_widx].filesize = 0;
2820 tracks[track_widx].filerem = 0;
2821 close(current_fd);
2822 current_fd = -1;
2823
2824 if (tracks[track_widx].codecsize) 2470 if (tracks[track_widx].codecsize)
2825 { 2471 {
2826 /* No space for codec on buffer, not an error */ 2472 /* No space for codec on buffer, not an error */
@@ -2839,32 +2485,35 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2839 goto peek_again; 2485 goto peek_again;
2840 } 2486 }
2841 2487
2842 tracks[track_widx].start_pos = 0; 2488 struct mp3entry *track_id3;
2843 set_filebuf_watermark(buffer_margin);
2844 tracks[track_widx].id3.elapsed = 0;
2845 2489
2846 if (offset > 0) 2490 if (track_widx == track_ridx)
2491 track_id3 = &curtrack_id3;
2492 else if (track_widx == ((track_ridx + 1) & MAX_TRACK_MASK))
2493 track_id3 = &nexttrack_id3;
2494 else
2495 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
2496
2497 set_filebuf_watermark(buffer_margin, 0);
2498 track_id3->elapsed = 0;
2499
2500 if (offset > 0)
2847 { 2501 {
2848 switch (tracks[track_widx].id3.codectype) { 2502 switch (track_id3->codectype) {
2849 case AFMT_MPA_L1: 2503 case AFMT_MPA_L1:
2850 case AFMT_MPA_L2: 2504 case AFMT_MPA_L2:
2851 case AFMT_MPA_L3: 2505 case AFMT_MPA_L3:
2852 lseek(current_fd, offset, SEEK_SET); 2506 file_offset = offset;
2853 tracks[track_widx].id3.offset = offset; 2507 track_id3->offset = offset;
2854 audio_set_elapsed(&tracks[track_widx].id3); 2508 audio_set_elapsed(track_id3);
2855 tracks[track_widx].filerem = size - offset;
2856 ci.curpos = offset; 2509 ci.curpos = offset;
2857 tracks[track_widx].start_pos = offset;
2858 break; 2510 break;
2859 2511
2860 case AFMT_WAVPACK: 2512 case AFMT_WAVPACK:
2861 lseek(current_fd, offset, SEEK_SET); 2513 file_offset = offset;
2862 tracks[track_widx].id3.offset = offset; 2514 track_id3->offset = offset;
2863 tracks[track_widx].id3.elapsed = 2515 track_id3->elapsed = track_id3->length / 2;
2864 tracks[track_widx].id3.length / 2;
2865 tracks[track_widx].filerem = size - offset;
2866 ci.curpos = offset; 2516 ci.curpos = offset;
2867 tracks[track_widx].start_pos = offset;
2868 break; 2517 break;
2869 2518
2870 case AFMT_OGG_VORBIS: 2519 case AFMT_OGG_VORBIS:
@@ -2875,57 +2524,27 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2875 case AFMT_AAC: 2524 case AFMT_AAC:
2876 case AFMT_MPC: 2525 case AFMT_MPC:
2877 case AFMT_APE: 2526 case AFMT_APE:
2878 tracks[track_widx].id3.offset = offset; 2527 track_id3->offset = offset;
2879 break; 2528 break;
2880 } 2529 }
2881 } 2530 }
2882
2883 logf("alt:%s", trackname);
2884 tracks[track_widx].buf_idx = buf_widx;
2885
2886 return audio_read_file(rebuffer);
2887}
2888 2531
2889static bool audio_read_next_metadata(void) 2532 logf("alt:%s", trackname);
2890{
2891 int fd;
2892 char *trackname;
2893 int next_idx;
2894 int status;
2895
2896 next_idx = track_widx;
2897 if (tracks[next_idx].taginfo_ready)
2898 {
2899 next_idx++;
2900 next_idx &= MAX_TRACK_MASK;
2901
2902 if (tracks[next_idx].taginfo_ready)
2903 return true;
2904 }
2905 2533
2906 trackname = playlist_peek(last_peek_offset + 1); 2534 tracks[track_widx].audio_hid = bufopen(trackname, file_offset, TYPE_AUDIO);
2907 if (!trackname)
2908 return false;
2909 2535
2910 fd = open(trackname, O_RDONLY); 2536 if (tracks[track_widx].audio_hid <= 0)
2911 if (fd < 0)
2912 return false; 2537 return false;
2913 2538
2914 status = get_metadata(&(tracks[next_idx].id3),fd,trackname); 2539 if (start_play)
2915 /* Preload the glyphs in the tags */
2916 if (status)
2917 { 2540 {
2918 tracks[next_idx].taginfo_ready = true; 2541 buf_request_buffer_handle(tracks[track_widx].audio_hid);
2919 if (tracks[next_idx].id3.title)
2920 lcd_getstringsize(tracks[next_idx].id3.title, NULL, NULL);
2921 if (tracks[next_idx].id3.artist)
2922 lcd_getstringsize(tracks[next_idx].id3.artist, NULL, NULL);
2923 if (tracks[next_idx].id3.album)
2924 lcd_getstringsize(tracks[next_idx].id3.album, NULL, NULL);
2925 } 2542 }
2926 close(fd);
2927 2543
2928 return status; 2544 track_widx++;
2545 track_widx &= MAX_TRACK_MASK;
2546
2547 return true;
2929} 2548}
2930 2549
2931/* Send callback events to notify about new tracks. */ 2550/* Send callback events to notify about new tracks. */
@@ -2939,7 +2558,7 @@ static void audio_generate_postbuffer_events(void)
2939 if (audio_have_tracks()) 2558 if (audio_have_tracks())
2940 { 2559 {
2941 cur_idx = track_ridx; 2560 cur_idx = track_ridx;
2942 2561
2943 while (1) { 2562 while (1) {
2944 if (!tracks[cur_idx].event_sent) 2563 if (!tracks[cur_idx].event_sent)
2945 { 2564 {
@@ -2947,8 +2566,8 @@ static void audio_generate_postbuffer_events(void)
2947 { 2566 {
2948 /* Mark the event 'sent' even if we don't really send one */ 2567 /* Mark the event 'sent' even if we don't really send one */
2949 tracks[last_idx].event_sent = true; 2568 tracks[last_idx].event_sent = true;
2950 if (track_buffer_callback) 2569 if (track_buffer_callback && tracks[last_idx].id3_hid > 0)
2951 track_buffer_callback(&tracks[last_idx].id3, false); 2570 track_buffer_callback(bufgetid3(tracks[last_idx].id3_hid), false);
2952 } 2571 }
2953 last_idx = cur_idx; 2572 last_idx = cur_idx;
2954 } 2573 }
@@ -2961,35 +2580,19 @@ static void audio_generate_postbuffer_events(void)
2961 if (last_idx >= 0 && !tracks[last_idx].event_sent) 2580 if (last_idx >= 0 && !tracks[last_idx].event_sent)
2962 { 2581 {
2963 tracks[last_idx].event_sent = true; 2582 tracks[last_idx].event_sent = true;
2964 if (track_buffer_callback) 2583 if (track_buffer_callback && tracks[last_idx].id3_hid > 0)
2965 track_buffer_callback(&tracks[last_idx].id3, true); 2584 track_buffer_callback(bufgetid3(tracks[last_idx].id3_hid), true);
2966 } 2585 }
2967 } 2586 }
2968} 2587}
2969 2588
2970static bool audio_initialize_buffer_fill(bool clear_tracks) 2589static void low_buffer_callback(void)
2971{ 2590{
2972 /* Don't initialize if we're already initialized */ 2591 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
2973 if (filling) 2592 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
2974 return true;
2975
2976 logf("Starting buffer fill");
2977
2978 /* Set the filling flag true before calling audio_clear_tracks as that
2979 * function can yield and we start looping. */
2980 filling = true;
2981
2982 if (clear_tracks)
2983 audio_clear_track_entries(false);
2984
2985 /* Save the current resume position once. */
2986 playlist_update_resume_info(audio_current_track());
2987
2988 return true;
2989} 2593}
2990 2594
2991static void audio_fill_file_buffer( 2595static void audio_fill_file_buffer(bool start_play, size_t offset)
2992 bool start_play, bool rebuffer, size_t offset)
2993{ 2596{
2994 bool had_next_track = audio_next_track() != NULL; 2597 bool had_next_track = audio_next_track() != NULL;
2995 bool continue_buffering; 2598 bool continue_buffering;
@@ -3000,61 +2603,49 @@ static void audio_fill_file_buffer(
3000 if (buffer_state != BUFFER_STATE_INITIALIZED) 2603 if (buffer_state != BUFFER_STATE_INITIALIZED)
3001 audio_reset_buffer(); 2604 audio_reset_buffer();
3002 2605
3003 if (!audio_initialize_buffer_fill(!start_play)) 2606 logf("Starting buffer fill");
3004 return ;
3005 2607
3006 /* If we have a partially buffered track, continue loading, 2608 if (!start_play)
3007 * otherwise load a new track */ 2609 audio_clear_track_entries(false);
3008 if (tracks[track_widx].filesize > 0)
3009 continue_buffering = audio_read_file(rebuffer);
3010 else
3011 continue_buffering = audio_load_track(offset, start_play, rebuffer);
3012 2610
3013 if (!had_next_track && audio_next_track()) 2611 /* Save the current resume position once. */
3014 track_changed = true; 2612 playlist_update_resume_info(audio_current_track());
3015 2613
3016 /* If we're done buffering */ 2614 do {
3017 if (!continue_buffering) 2615 continue_buffering = audio_load_track(offset, start_play);
3018 { 2616 start_play = false;
3019 audio_read_next_metadata(); 2617 offset = 0;
2618 sleep(1);
2619 } while (continue_buffering);
3020 2620
3021 audio_generate_postbuffer_events(); 2621 if (!had_next_track && audio_next_track())
3022 filling = false; 2622 track_changed = true;
3023 }
3024#ifndef SIMULATOR
3025 ata_sleep();
3026#endif
3027 2623
2624 audio_generate_postbuffer_events();
2625 register_buffer_low_callback(low_buffer_callback);
3028} 2626}
3029 2627
3030static void audio_rebuffer(void) 2628static void audio_rebuffer(void)
3031{ 2629{
3032 logf("Forcing rebuffer"); 2630 logf("Forcing rebuffer");
3033 2631
3034 /* Stop in progress fill, and clear open file descriptor */ 2632 clear_track_info(CUR_TI);
3035 if (current_fd >= 0)
3036 {
3037 close(current_fd);
3038 current_fd = -1;
3039 }
3040 filling = false;
3041 2633
3042 /* Reset buffer and track pointers */ 2634 /* Reset track pointers */
3043 CUR_TI->buf_idx = buf_ridx = buf_widx = 0;
3044 track_widx = track_ridx; 2635 track_widx = track_ridx;
3045 audio_clear_track_entries(true); 2636 audio_clear_track_entries(true);
3046 CUR_TI->available = 0; 2637
2638 /* Just to make sure none were forgotten */
2639 audio_release_tracks();
3047 2640
3048 /* Fill the buffer */ 2641 /* Fill the buffer */
3049 last_peek_offset = -1; 2642 last_peek_offset = -1;
3050 CUR_TI->filesize = 0;
3051 CUR_TI->start_pos = 0;
3052 ci.curpos = 0; 2643 ci.curpos = 0;
3053 2644
3054 if (!CUR_TI->taginfo_ready) 2645 if (!CUR_TI->taginfo_ready)
3055 memset(&CUR_TI->id3, 0, sizeof(struct mp3entry)); 2646 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
3056 2647
3057 audio_fill_file_buffer(false, true, 0); 2648 audio_fill_file_buffer(false, 0);
3058} 2649}
3059 2650
3060static int audio_check_new_track(void) 2651static int audio_check_new_track(void)
@@ -3069,7 +2660,6 @@ static int audio_check_new_track(void)
3069 if (playlist_next_dir(ci.new_track)) 2660 if (playlist_next_dir(ci.new_track))
3070 { 2661 {
3071 ci.new_track = 0; 2662 ci.new_track = 0;
3072 CUR_TI->taginfo_ready = false;
3073 audio_rebuffer(); 2663 audio_rebuffer();
3074 goto skip_done; 2664 goto skip_done;
3075 } 2665 }
@@ -3115,22 +2705,34 @@ static int audio_check_new_track(void)
3115 } 2705 }
3116 2706
3117 /* Save the old track */ 2707 /* Save the old track */
3118 prev_ti = CUR_TI; 2708 copy_mp3entry(&prevtrack_id3, &curtrack_id3);
2709
2710 int i, idx;
2711 for (i = 0; i < ci.new_track; i++)
2712 {
2713 idx = (track_ridx + i) & MAX_TRACK_MASK;
2714 if (buf_handle_offset(tracks[idx].audio_hid) > 0)
2715 clear_track_info(&tracks[idx]);
2716 }
3119 2717
3120 /* Move to the new track */ 2718 /* Move to the new track */
3121 track_ridx += ci.new_track; 2719 track_ridx += ci.new_track;
3122 track_ridx &= MAX_TRACK_MASK; 2720 track_ridx &= MAX_TRACK_MASK;
3123 2721
2722 buf_set_base_handle(CUR_TI->audio_hid);
2723
3124 if (automatic_skip) 2724 if (automatic_skip)
2725 {
3125 playlist_end = false; 2726 playlist_end = false;
2727 wps_offset = -ci.new_track;
2728 }
3126 2729
3127 track_changed = !automatic_skip; 2730 track_changed = true;
3128 2731
3129 /* If it is not safe to even skip this many track entries */ 2732 /* If it is not safe to even skip this many track entries */
3130 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK) 2733 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
3131 { 2734 {
3132 ci.new_track = 0; 2735 ci.new_track = 0;
3133 CUR_TI->taginfo_ready = false;
3134 audio_rebuffer(); 2736 audio_rebuffer();
3135 goto skip_done; 2737 goto skip_done;
3136 } 2738 }
@@ -3146,18 +2748,13 @@ static int audio_check_new_track(void)
3146 } 2748 }
3147 2749
3148 /* The track may be in memory, see if it really is */ 2750 /* The track may be in memory, see if it really is */
3149 if (forward) 2751 if (!forward)
3150 {
3151 if (!audio_buffer_wind_forward(track_ridx, old_track_ridx))
3152 audio_rebuffer();
3153 }
3154 else
3155 { 2752 {
3156 int cur_idx = track_ridx; 2753 int cur_idx = track_ridx;
3157 bool taginfo_ready = true; 2754 bool taginfo_ready = true;
3158 bool wrap = track_ridx > old_track_ridx; 2755 bool wrap = track_ridx > old_track_ridx;
3159 2756
3160 while (1) 2757 while (1)
3161 { 2758 {
3162 cur_idx++; 2759 cur_idx++;
3163 cur_idx &= MAX_TRACK_MASK; 2760 cur_idx &= MAX_TRACK_MASK;
@@ -3170,19 +2767,9 @@ static int audio_check_new_track(void)
3170 taginfo_ready = false; 2767 taginfo_ready = false;
3171 break; 2768 break;
3172 } 2769 }
3173
3174 tracks[cur_idx].available = tracks[cur_idx].filesize;
3175 if (tracks[cur_idx].codecsize)
3176 tracks[cur_idx].has_codec = true;
3177 }
3178 if (taginfo_ready)
3179 {
3180 if (!audio_buffer_wind_backward(track_ridx, old_track_ridx))
3181 audio_rebuffer();
3182 } 2770 }
3183 else 2771 if (!taginfo_ready)
3184 { 2772 {
3185 CUR_TI->taginfo_ready = false;
3186 audio_rebuffer(); 2773 audio_rebuffer();
3187 } 2774 }
3188 } 2775 }
@@ -3193,66 +2780,6 @@ skip_done:
3193 return Q_CODEC_REQUEST_COMPLETE; 2780 return Q_CODEC_REQUEST_COMPLETE;
3194} 2781}
3195 2782
3196static int audio_rebuffer_and_seek(size_t newpos)
3197{
3198 size_t real_preseek;
3199 int fd;
3200 char *trackname;
3201
3202 /* (Re-)open current track's file handle. */
3203 trackname = playlist_peek(0);
3204 fd = open(trackname, O_RDONLY);
3205 if (fd < 0)
3206 {
3207 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
3208 return Q_CODEC_REQUEST_FAILED;
3209 }
3210
3211 if (current_fd >= 0)
3212 close(current_fd);
3213 current_fd = fd;
3214
3215 playlist_end = false;
3216
3217 ci.curpos = newpos;
3218
3219 /* Clear codec buffer. */
3220 track_widx = track_ridx;
3221 tracks[track_widx].buf_idx = buf_widx = buf_ridx = 0;
3222
3223 last_peek_offset = 0;
3224 filling = false;
3225 audio_initialize_buffer_fill(true);
3226
3227 /* This may have been tweaked by the id3v1 code */
3228 CUR_TI->filesize=filesize(fd);
3229 if (newpos > conf_preseek)
3230 {
3231 CUR_TI->start_pos = newpos - conf_preseek;
3232 lseek(current_fd, CUR_TI->start_pos, SEEK_SET);
3233 CUR_TI->filerem = CUR_TI->filesize - CUR_TI->start_pos;
3234 real_preseek = conf_preseek;
3235 }
3236 else
3237 {
3238 CUR_TI->start_pos = 0;
3239 CUR_TI->filerem = CUR_TI->filesize;
3240 real_preseek = newpos;
3241 }
3242
3243 CUR_TI->available = 0;
3244
3245 audio_read_file(real_preseek);
3246
3247 /* Account for the data we just read that is 'behind' us now */
3248 CUR_TI->available -= real_preseek;
3249
3250 buf_ridx = RINGBUF_ADD(buf_ridx, real_preseek);
3251
3252 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
3253 return Q_CODEC_REQUEST_COMPLETE;
3254}
3255
3256void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, 2783void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
3257 bool last_track)) 2784 bool last_track))
3258{ 2785{
@@ -3309,7 +2836,7 @@ static void audio_stop_playback(void)
3309 /* Save the current playing spot, or NULL if the playlist has ended */ 2836 /* Save the current playing spot, or NULL if the playlist has ended */
3310 playlist_update_resume_info(id3); 2837 playlist_update_resume_info(id3);
3311 2838
3312 prev_track_elapsed = CUR_TI->id3.elapsed; 2839 prev_track_elapsed = curtrack_id3.elapsed;
3313 2840
3314 /* Increment index so runtime info is saved in audio_clear_track_entries(). 2841 /* Increment index so runtime info is saved in audio_clear_track_entries().
3315 * Done here, as audio_stop_playback() may be called more than once. 2842 * Done here, as audio_stop_playback() may be called more than once.
@@ -3324,19 +2851,18 @@ static void audio_stop_playback(void)
3324 } 2851 }
3325 } 2852 }
3326 2853
3327 filling = false;
3328 paused = false; 2854 paused = false;
3329 audio_stop_codec_flush(); 2855 audio_stop_codec_flush();
3330 playing = false; 2856 playing = false;
3331 2857
3332 if (current_fd >= 0) 2858 /* Close all tracks */
3333 { 2859 audio_release_tracks();
3334 close(current_fd);
3335 current_fd = -1;
3336 }
3337 2860
3338 /* Mark all entries null. */ 2861 /* Mark all entries null. */
3339 audio_clear_track_entries(false); 2862 audio_clear_track_entries(false);
2863
2864 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2865 memset(&nexttrack_id3, 0, sizeof(struct mp3entry));
3340} 2866}
3341 2867
3342static void audio_play_start(size_t offset) 2868static void audio_play_start(size_t offset)
@@ -3358,26 +2884,19 @@ static void audio_play_start(size_t offset)
3358 ci.new_track = 0; 2884 ci.new_track = 0;
3359 ci.seek_time = 0; 2885 ci.seek_time = 0;
3360 wps_offset = 0; 2886 wps_offset = 0;
3361
3362 if (current_fd >= 0)
3363 {
3364 close(current_fd);
3365 current_fd = -1;
3366 }
3367 2887
3368 sound_set_volume(global_settings.volume); 2888 sound_set_volume(global_settings.volume);
3369 track_widx = track_ridx = 0; 2889 track_widx = track_ridx = 0;
3370 buf_ridx = buf_widx = 0;
3371 2890
3372 /* Mark all entries null. */ 2891 /* Mark all entries null. */
3373 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK); 2892 memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
3374 2893
3375 last_peek_offset = -1; 2894 last_peek_offset = -1;
3376 2895
3377 /* Officially playing */ 2896 /* Officially playing */
3378 queue_reply(&audio_queue, 1); 2897 queue_reply(&audio_queue, 1);
3379 2898
3380 audio_fill_file_buffer(true, false, offset); 2899 audio_fill_file_buffer(true, offset);
3381 2900
3382 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED"); 2901 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
3383 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); 2902 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
@@ -3387,7 +2906,7 @@ static void audio_play_start(size_t offset)
3387/* Invalidates all but currently playing track. */ 2906/* Invalidates all but currently playing track. */
3388static void audio_invalidate_tracks(void) 2907static void audio_invalidate_tracks(void)
3389{ 2908{
3390 if (audio_have_tracks()) 2909 if (audio_have_tracks())
3391 { 2910 {
3392 last_peek_offset = 0; 2911 last_peek_offset = 0;
3393 playlist_end = false; 2912 playlist_end = false;
@@ -3396,13 +2915,9 @@ static void audio_invalidate_tracks(void)
3396 /* Mark all other entries null (also buffered wrong metadata). */ 2915 /* Mark all other entries null (also buffered wrong metadata). */
3397 audio_clear_track_entries(true); 2916 audio_clear_track_entries(true);
3398 2917
3399 /* If the current track is fully buffered, advance the write pointer */ 2918 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
3400 if (tracks[track_widx].filerem == 0)
3401 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
3402 2919
3403 buf_widx = RINGBUF_ADD(buf_ridx, CUR_TI->available); 2920 audio_fill_file_buffer(false, 0);
3404
3405 audio_read_next_metadata();
3406 } 2921 }
3407} 2922}
3408 2923
@@ -3421,18 +2936,10 @@ static void audio_new_playlist(void)
3421 track_widx++; 2936 track_widx++;
3422 track_widx &= MAX_TRACK_MASK; 2937 track_widx &= MAX_TRACK_MASK;
3423 2938
3424 /* Stop reading the current track */
3425 CUR_TI->filerem = 0;
3426 close(current_fd);
3427 current_fd = -1;
3428
3429 /* Mark the current track as invalid to prevent skipping back to it */ 2939 /* Mark the current track as invalid to prevent skipping back to it */
3430 CUR_TI->taginfo_ready = false; 2940 CUR_TI->taginfo_ready = false;
3431
3432 /* Invalidate the buffer other than the playing track */
3433 buf_widx = RINGBUF_ADD(buf_ridx, CUR_TI->available);
3434 } 2941 }
3435 2942
3436 /* Signal the codec to initiate a track change forward */ 2943 /* Signal the codec to initiate a track change forward */
3437 new_playlist = true; 2944 new_playlist = true;
3438 ci.new_track = 1; 2945 ci.new_track = 1;
@@ -3440,7 +2947,7 @@ static void audio_new_playlist(void)
3440 /* Officially playing */ 2947 /* Officially playing */
3441 queue_reply(&audio_queue, 1); 2948 queue_reply(&audio_queue, 1);
3442 2949
3443 audio_fill_file_buffer(false, true, 0); 2950 audio_fill_file_buffer(false, 0);
3444} 2951}
3445 2952
3446static void audio_initiate_track_change(long direction) 2953static void audio_initiate_track_change(long direction)
@@ -3551,10 +3058,7 @@ static void audio_reset_buffer(void)
3551 will already be line aligned */ 3058 will already be line aligned */
3552 filebuflen &= ~3; 3059 filebuflen &= ~3;
3553 3060
3554 /* Set the high watermark as 75% full...or 25% empty :) */ 3061 buffering_init(filebuf, filebuflen);
3555#if MEM > 8
3556 high_watermark = 3*filebuflen / 4;
3557#endif
3558 3062
3559 /* Clear any references to the file buffer */ 3063 /* Clear any references to the file buffer */
3560 buffer_state = BUFFER_STATE_INITIALIZED; 3064 buffer_state = BUFFER_STATE_INITIALIZED;
@@ -3588,16 +3092,6 @@ static void audio_reset_buffer(void)
3588#endif 3092#endif
3589} 3093}
3590 3094
3591#if MEM > 8
3592/* we dont want this rebuffering on targets with little ram
3593 because the disk may never spin down */
3594static bool ata_fillbuffer_callback(void)
3595{
3596 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, 0);
3597 return true;
3598}
3599#endif
3600
3601static void audio_thread(void) 3095static void audio_thread(void)
3602{ 3096{
3603 struct queue_event ev; 3097 struct queue_event ev;
@@ -3618,41 +3112,17 @@ static void audio_thread(void)
3618 invalid when an audio codec is loaded */ 3112 invalid when an audio codec is loaded */
3619 wait_for_voice_swap_in(); 3113 wait_for_voice_swap_in();
3620#endif 3114#endif
3621 3115
3622 while (1) 3116 while (1)
3623 { 3117 {
3624 if (filling) 3118 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
3625 {
3626 queue_wait_w_tmo(&audio_queue, &ev, 0);
3627 if (ev.id == SYS_TIMEOUT)
3628 ev.id = Q_AUDIO_FILL_BUFFER;
3629 }
3630 else
3631 {
3632 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
3633#if MEM > 8
3634 if (playing && (ev.id == SYS_TIMEOUT) &&
3635 (FILEBUFUSED < high_watermark))
3636 register_ata_idle_func(ata_fillbuffer_callback);
3637#endif
3638 }
3639 3119
3640 switch (ev.id) { 3120 switch (ev.id) {
3641#if MEM > 8
3642 case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA:
3643 /* only fill if the disk is still spining */
3644#ifndef SIMULATOR
3645 if (!ata_disk_is_active())
3646 break;
3647#endif
3648#endif /* MEM > 8 */
3649 /* else fall through to Q_AUDIO_FILL_BUFFER */
3650 case Q_AUDIO_FILL_BUFFER: 3121 case Q_AUDIO_FILL_BUFFER:
3651 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER"); 3122 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3652 if (!filling) 3123 if (!playing || playlist_end || ci.stop_codec)
3653 if (!playing || playlist_end || ci.stop_codec) 3124 break;
3654 break; 3125 audio_fill_file_buffer(false, 0);
3655 audio_fill_file_buffer(false, false, 0);
3656 break; 3126 break;
3657 3127
3658 case Q_AUDIO_PLAY: 3128 case Q_AUDIO_PLAY:
@@ -3704,11 +3174,6 @@ static void audio_thread(void)
3704 ci.seek_time = (long)ev.data+1; 3174 ci.seek_time = (long)ev.data+1;
3705 break; 3175 break;
3706 3176
3707 case Q_AUDIO_REBUFFER_SEEK:
3708 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
3709 queue_reply(&audio_queue, audio_rebuffer_and_seek(ev.data));
3710 break;
3711
3712 case Q_AUDIO_CHECK_NEW_TRACK: 3177 case Q_AUDIO_CHECK_NEW_TRACK:
3713 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK"); 3178 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3714 queue_reply(&audio_queue, audio_check_new_track()); 3179 queue_reply(&audio_queue, audio_check_new_track());
@@ -3727,8 +3192,14 @@ static void audio_thread(void)
3727 3192
3728 case Q_AUDIO_TRACK_CHANGED: 3193 case Q_AUDIO_TRACK_CHANGED:
3729 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED"); 3194 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3195 if (automatic_skip)
3196 {
3197 wps_offset = 0;
3198 automatic_skip = false;
3199 prevtrack_id3.path[0] = 0;
3200 }
3730 if (track_changed_callback) 3201 if (track_changed_callback)
3731 track_changed_callback(&CUR_TI->id3); 3202 track_changed_callback(&curtrack_id3);
3732 track_changed = true; 3203 track_changed = true;
3733 playlist_update_resume_info(audio_current_track()); 3204 playlist_update_resume_info(audio_current_track());
3734 break; 3205 break;
@@ -3740,6 +3211,8 @@ static void audio_thread(void)
3740 audio_stop_playback(); 3211 audio_stop_playback();
3741 usb_acknowledge(SYS_USB_CONNECTED_ACK); 3212 usb_acknowledge(SYS_USB_CONNECTED_ACK);
3742 usb_wait_for_disconnect(&audio_queue); 3213 usb_wait_for_disconnect(&audio_queue);
3214 /* release tracks to make sure all handles are closed */
3215 audio_release_tracks();
3743 break; 3216 break;
3744#endif 3217#endif
3745 3218
@@ -3749,6 +3222,7 @@ static void audio_thread(void)
3749 3222
3750 default: 3223 default:
3751 LOGFQUEUE("audio < default"); 3224 LOGFQUEUE("audio < default");
3225 break;
3752 } /* end switch */ 3226 } /* end switch */
3753 } /* end while */ 3227 } /* end while */
3754} 3228}
@@ -3796,6 +3270,7 @@ void audio_init(void)
3796 queue_init(&audio_queue, true); 3270 queue_init(&audio_queue, true);
3797 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list); 3271 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
3798 queue_init(&codec_queue, true); 3272 queue_init(&codec_queue, true);
3273 queue_enable_queue_send(&codec_queue, &codec_queue_sender_list);
3799 3274
3800 pcm_init(); 3275 pcm_init();
3801 3276
@@ -3858,7 +3333,7 @@ void audio_init(void)
3858 3333
3859 audio_thread_p = create_thread(audio_thread, audio_stack, 3334 audio_thread_p = create_thread(audio_thread, audio_stack,
3860 sizeof(audio_stack), CREATE_THREAD_FROZEN, 3335 sizeof(audio_stack), CREATE_THREAD_FROZEN,
3861 audio_thread_name IF_PRIO(, PRIORITY_BUFFERING) 3336 audio_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
3862 IF_COP(, CPU)); 3337 IF_COP(, CPU));
3863 3338
3864#ifdef PLAYBACK_VOICE 3339#ifdef PLAYBACK_VOICE
diff --git a/apps/playback.h b/apps/playback.h
index 43cdd5972f..9088af9b6e 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -32,9 +32,9 @@
32#define CODEC_SET_AUDIOBUF_WATERMARK 4 32#define CODEC_SET_AUDIOBUF_WATERMARK 4
33 33
34#if MEM > 1 34#if MEM > 1
35#define MAX_TRACK 32 35#define MAX_TRACK 128
36#else 36#else
37#define MAX_TRACK 8 37#define MAX_TRACK 32
38#endif 38#endif
39 39
40#define MAX_TRACK_MASK (MAX_TRACK-1) 40#define MAX_TRACK_MASK (MAX_TRACK-1)
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index 867c587794..94c228b9ef 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -43,7 +43,7 @@
43#define PRIORITY_BACKGROUND 8 /* Normal application threads */ 43#define PRIORITY_BACKGROUND 8 /* Normal application threads */
44 44
45#if CONFIG_CODEC == SWCODEC 45#if CONFIG_CODEC == SWCODEC
46#define MAXTHREADS 16 46#define MAXTHREADS 17
47#else 47#else
48#define MAXTHREADS 11 48#define MAXTHREADS 11
49#endif 49#endif