summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c1291
1 files changed, 383 insertions, 908 deletions
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