summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/debug_menu.c3
-rw-r--r--apps/playback.c322
-rw-r--r--firmware/export/audio.h1
3 files changed, 169 insertions, 157 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 9ad1c5f94c..fff124f779 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -211,7 +211,6 @@ bool dbg_audio_thread(void)
211extern size_t audiobuffer_free; 211extern size_t audiobuffer_free;
212extern int filebuflen; 212extern int filebuflen;
213extern int filebufused; 213extern int filebufused;
214extern int track_count;
215 214
216static unsigned int ticks, boost_ticks; 215static unsigned int ticks, boost_ticks;
217 216
@@ -276,7 +275,7 @@ bool dbg_audio_thread(void)
276 filebufused, HORIZONTAL); 275 filebufused, HORIZONTAL);
277 line++; 276 line++;
278 277
279 snprintf(buf, sizeof(buf), "track count: %2d", track_count); 278 snprintf(buf, sizeof(buf), "track count: %2d", audio_track_count());
280 lcd_puts(0, line++, buf); 279 lcd_puts(0, line++, buf);
281 280
282 snprintf(buf, sizeof(buf), "cpu freq: %3dMHz", 281 snprintf(buf, sizeof(buf), "cpu freq: %3dMHz",
diff --git a/apps/playback.c b/apps/playback.c
index 7889f120f7..ccdacedf85 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -88,6 +88,7 @@ static volatile bool paused;
88#define AUDIO_DEFAULT_WATERMARK (1024*512) 88#define AUDIO_DEFAULT_WATERMARK (1024*512)
89#define AUDIO_DEFAULT_FILECHUNK (1024*32) 89#define AUDIO_DEFAULT_FILECHUNK (1024*32)
90#define AUDIO_FILEBUF_CRITICAL (1024*128) 90#define AUDIO_FILEBUF_CRITICAL (1024*128)
91#define AUDIO_REBUFFER_GUESS_SIZE (1024*128)
91 92
92enum { 93enum {
93 Q_AUDIO_PLAY = 1, 94 Q_AUDIO_PLAY = 1,
@@ -96,6 +97,7 @@ enum {
96 Q_AUDIO_SKIP, 97 Q_AUDIO_SKIP,
97 Q_AUDIO_PRE_FF_REWIND, 98 Q_AUDIO_PRE_FF_REWIND,
98 Q_AUDIO_FF_REWIND, 99 Q_AUDIO_FF_REWIND,
100 Q_AUDIO_REBUFFER_SEEK,
99 Q_AUDIO_FLUSH_RELOAD, 101 Q_AUDIO_FLUSH_RELOAD,
100 Q_AUDIO_CODEC_DONE, 102 Q_AUDIO_CODEC_DONE,
101 Q_AUDIO_FLUSH, 103 Q_AUDIO_FLUSH,
@@ -138,8 +140,8 @@ static struct event_queue voice_codec_queue;
138static long voice_codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR; 140static long voice_codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR;
139static const char voice_codec_thread_name[] = "voice codec"; 141static const char voice_codec_thread_name[] = "voice codec";
140 142
141static struct mutex mutex_bufferfill;
142static struct mutex mutex_codecthread; 143static struct mutex mutex_codecthread;
144static struct mutex mutex_rebuffer;
143 145
144static struct mp3entry id3_voice; 146static struct mp3entry id3_voice;
145 147
@@ -178,7 +180,6 @@ static int last_peek_offset;
178 180
179/* Track information (count in file buffer, read/write indexes for 181/* Track information (count in file buffer, read/write indexes for
180 track ring structure. */ 182 track ring structure. */
181int track_count;
182static volatile int track_ridx; 183static volatile int track_ridx;
183static volatile int track_widx; 184static volatile int track_widx;
184static bool track_changed; 185static bool track_changed;
@@ -451,6 +452,38 @@ static bool filebuf_is_lowdata(void)
451 return filebufused < AUDIO_FILEBUF_CRITICAL; 452 return filebufused < AUDIO_FILEBUF_CRITICAL;
452} 453}
453 454
455static bool have_tracks(void)
456{
457 return track_ridx != track_widx || tracks[track_ridx].filesize;
458}
459
460static bool have_free_tracks(void)
461{
462 if (track_widx < track_ridx)
463 return track_widx + 1 < track_ridx;
464 else if (track_ridx == 0)
465 return track_widx < MAX_TRACK - 1;
466 else
467 return true;
468}
469
470int audio_track_count(void)
471{
472 int track_count = 0;
473 if (have_tracks())
474 {
475 int cur_idx = track_ridx;
476 track_count++;
477 while (cur_idx != track_widx)
478 {
479 track_count++;
480 if (++cur_idx > MAX_TRACK)
481 cur_idx -= MAX_TRACK;
482 }
483 }
484 return track_count;
485}
486
454static void advance_buffer_counters(size_t amount) { 487static void advance_buffer_counters(size_t amount) {
455 buf_ridx += amount; 488 buf_ridx += amount;
456 if (buf_ridx >= filebuflen) 489 if (buf_ridx >= filebuflen)
@@ -597,19 +630,23 @@ void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
597 return (char *)&filebuf[buf_ridx]; 630 return (char *)&filebuf[buf_ridx];
598} 631}
599 632
600static bool rebuffer_and_seek(size_t newpos) 633static void rebuffer_and_seek(size_t newpos)
601{ 634{
602 int fd; 635 int fd;
636 size_t filepos;
603 637
604 logf("Re-buffering song"); 638 /* Prevent multiple rebuffer calls on codecs that 'hunt' when seeking */
605 mutex_lock(&mutex_bufferfill); 639 if (newpos > AUDIO_REBUFFER_GUESS_SIZE)
640 filepos = newpos - AUDIO_REBUFFER_GUESS_SIZE;
641 else
642 filepos = 0;
606 643
607 /* (Re-)open current track's file handle. */ 644 /* (Re-)open current track's file handle. */
608 fd = open(playlist_peek(0), O_RDONLY); 645 fd = open(playlist_peek(0), O_RDONLY);
609 if (fd < 0) { 646 if (fd < 0) {
610 logf("Open failed!"); 647 logf("Open failed!");
611 mutex_unlock(&mutex_bufferfill); 648 mutex_unlock(&mutex_rebuffer);
612 return false; 649 return;
613 } 650 }
614 if (current_fd >= 0) 651 if (current_fd >= 0)
615 close(current_fd); 652 close(current_fd);
@@ -620,18 +657,15 @@ static bool rebuffer_and_seek(size_t newpos)
620 filebufused = 0; 657 filebufused = 0;
621 playlist_end = false; 658 playlist_end = false;
622 buf_ridx = buf_widx = 0; 659 buf_ridx = buf_widx = 0;
623 cur_ti->filerem = cur_ti->filesize - newpos; 660 cur_ti->filerem = cur_ti->filesize - filepos;
624 cur_ti->filepos = newpos; 661 cur_ti->filepos = filepos;
625 cur_ti->start_pos = newpos; 662 cur_ti->start_pos = filepos;
626 ci.curpos = newpos; 663 ci.curpos = newpos;
627 cur_ti->available = 0; 664 cur_ti->available = 0;
628 lseek(current_fd, newpos, SEEK_SET); 665 lseek(current_fd, filepos, SEEK_SET);
629
630 mutex_unlock(&mutex_bufferfill);
631 666
632 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); 667 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
633 668 mutex_unlock(&mutex_rebuffer);
634 return true;
635} 669}
636 670
637void codec_advance_buffer_callback(size_t amount) 671void codec_advance_buffer_callback(size_t amount)
@@ -653,8 +687,11 @@ void codec_advance_buffer_callback(size_t amount)
653 687
654 /* This should not happen */ 688 /* This should not happen */
655 if (amount > cur_ti->available) { 689 if (amount > cur_ti->available) {
656 if (!rebuffer_and_seek(ci.curpos + amount)) 690 mutex_lock(&mutex_rebuffer);
657 ci.stop_codec = true; 691 queue_post(&audio_queue,
692 Q_AUDIO_REBUFFER_SEEK, (void *)(ci.curpos + amount));
693 mutex_lock(&mutex_rebuffer);
694 mutex_unlock(&mutex_rebuffer);
658 return ; 695 return ;
659 } 696 }
660 697
@@ -722,7 +759,10 @@ bool codec_seek_buffer_callback(size_t newpos)
722 759
723 /* We need to reload the song. */ 760 /* We need to reload the song. */
724 if (newpos < cur_ti->start_pos) 761 if (newpos < cur_ti->start_pos)
725 return rebuffer_and_seek(newpos); 762 {
763 queue_post(&audio_queue, Q_AUDIO_REBUFFER_SEEK, (void *)newpos);
764 return true;
765 }
726 766
727 /* Seeking inside buffer space. */ 767 /* Seeking inside buffer space. */
728 logf("seek: -%d", difference); 768 logf("seek: -%d", difference);
@@ -878,8 +918,6 @@ static void audio_read_file(void)
878 return ; 918 return ;
879 } 919 }
880 920
881 mutex_lock(&mutex_bufferfill);
882
883 /* Throw away buffered codec. */ 921 /* Throw away buffered codec. */
884 if (tracks[track_widx].start_pos != 0) 922 if (tracks[track_widx].start_pos != 0)
885 tracks[track_widx].codecsize = 0; 923 tracks[track_widx].codecsize = 0;
@@ -931,8 +969,6 @@ static void audio_read_file(void)
931 } else { 969 } else {
932 logf("Partially buf:%d", tracks[track_widx].available); 970 logf("Partially buf:%d", tracks[track_widx].available);
933 } 971 }
934
935 mutex_unlock(&mutex_bufferfill);
936} 972}
937 973
938static int get_codec_base_type(int type) 974static int get_codec_base_type(int type)
@@ -1032,7 +1068,7 @@ static bool loadcodec(bool start_play)
1032 prev_track = track_widx - 1; 1068 prev_track = track_widx - 1;
1033 if (prev_track < 0) 1069 if (prev_track < 0)
1034 prev_track = MAX_TRACK-1; 1070 prev_track = MAX_TRACK-1;
1035 if (track_count > 0 && 1071 if (have_tracks() &&
1036 get_codec_base_type(tracks[track_widx].id3.codectype) == 1072 get_codec_base_type(tracks[track_widx].id3.codectype) ==
1037 get_codec_base_type(tracks[prev_track].id3.codectype)) 1073 get_codec_base_type(tracks[prev_track].id3.codectype))
1038 { 1074 {
@@ -1059,7 +1095,6 @@ static bool loadcodec(bool start_play)
1059 return false; 1095 return false;
1060 } 1096 }
1061 1097
1062 mutex_lock(&mutex_bufferfill);
1063 i = 0; 1098 i = 0;
1064 while (i < size) { 1099 while (i < size) {
1065 copy_n = MIN(conf_filechunk, filebuflen - buf_widx); 1100 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
@@ -1078,7 +1113,6 @@ static bool loadcodec(bool start_play)
1078 * queue during this loop */ 1113 * queue during this loop */
1079 yield_codecs(); 1114 yield_codecs();
1080 } 1115 }
1081 mutex_unlock(&mutex_bufferfill);
1082 1116
1083 close(fd); 1117 close(fd);
1084 logf("Done: %dB", i); 1118 logf("Done: %dB", i);
@@ -1142,9 +1176,8 @@ static bool audio_load_track(int offset, bool start_play, int peek_offset)
1142 /* Stop buffer filling if there is no free track entries. 1176 /* Stop buffer filling if there is no free track entries.
1143 Don't fill up the last track entry (we wan't to store next track 1177 Don't fill up the last track entry (we wan't to store next track
1144 metadata there). */ 1178 metadata there). */
1145 if (track_count >= MAX_TRACK - 1) { 1179 if (!have_free_tracks())
1146 return false; 1180 return false;
1147 }
1148 1181
1149 if (current_fd >= 0) 1182 if (current_fd >= 0)
1150 { 1183 {
@@ -1268,52 +1301,49 @@ static bool audio_load_track(int offset, bool start_play, int peek_offset)
1268 } 1301 }
1269 1302
1270 if (start_play) { 1303 if (start_play) {
1271 track_count++;
1272 codec_track_changed(); 1304 codec_track_changed();
1273 } 1305 }
1274 1306
1275 audio_read_file(); 1307 audio_read_file();
1276 1308
1277 if (!start_play)
1278 track_count++;
1279
1280 return true; 1309 return true;
1281} 1310}
1282 1311
1283static void audio_clear_track_entries(bool buffered_only) 1312static void audio_clear_track_entries(bool buffered_only)
1284{ 1313{
1285 int cur_idx, event_count; 1314 int cur_idx;
1286 int i; 1315 int last_idx = 0;
1287 1316
1317 /* Loop over all tracks from write index to read index. */
1288 cur_idx = track_widx; 1318 cur_idx = track_widx;
1289 event_count = 0; 1319 while (1) {
1290 for (i = 0; i < MAX_TRACK - track_count; i++) {
1291 if (++cur_idx >= MAX_TRACK) 1320 if (++cur_idx >= MAX_TRACK)
1292 cur_idx = 0; 1321 cur_idx = 0;
1322 if (cur_idx == track_ridx)
1323 break;
1293 1324
1294 if (tracks[cur_idx].event_sent) 1325 /* If the track is buffered, conditionally clear/notify,
1295 event_count++; 1326 * otherwise clear the track if that option is selected */
1296 1327 if (tracks[cur_idx].event_sent) {
1297 if (!track_unbuffer_callback) 1328 /* If there is an unbuffer callback, call it, otherwise, just
1329 * clear the track */
1330 if (track_unbuffer_callback)
1331 track_unbuffer_callback(&tracks[last_idx].id3, false);
1332
1333 memset(&tracks[last_idx], 0, sizeof(struct track_info));
1334 last_idx = cur_idx;
1335 } else if (!buffered_only)
1298 memset(&tracks[cur_idx], 0, sizeof(struct track_info)); 1336 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1299 } 1337 }
1300 1338
1301 if (!track_unbuffer_callback) 1339 /* We clear the previous instance of a buffered track throughout
1302 return ; 1340 * the above loop to facilitate 'last' detection. Clear/notify
1303 1341 * the last track here */
1304 cur_idx = track_widx; 1342 if (last_idx)
1305 for (i = 0; i < MAX_TRACK - track_count; i++) { 1343 {
1306 if (++cur_idx >= MAX_TRACK) 1344 if (track_unbuffer_callback)
1307 cur_idx = 0; 1345 track_unbuffer_callback(&tracks[last_idx].id3, true);
1308 1346 memset(&tracks[last_idx], 0, sizeof(struct track_info));
1309 /* Send an event to notify that track has finished. */
1310 if (tracks[cur_idx].event_sent) {
1311 event_count--;
1312 track_unbuffer_callback(&tracks[cur_idx].id3, event_count == 0);
1313 }
1314
1315 if (tracks[cur_idx].event_sent || !buffered_only)
1316 memset(&tracks[cur_idx], 0, sizeof(struct track_info));
1317 } 1347 }
1318} 1348}
1319 1349
@@ -1339,7 +1369,6 @@ static void audio_stop_playback(bool resume)
1339 current_fd = -1; 1369 current_fd = -1;
1340 } 1370 }
1341 1371
1342 track_count = 0;
1343 /* Mark all entries null. */ 1372 /* Mark all entries null. */
1344 audio_clear_track_entries(false); 1373 audio_clear_track_entries(false);
1345} 1374}
@@ -1353,14 +1382,12 @@ static void audio_play_start(size_t offset)
1353 current_fd = -1; 1382 current_fd = -1;
1354 } 1383 }
1355 1384
1356 memset(&tracks, 0, sizeof(struct track_info) * MAX_TRACK);
1357 sound_set_volume(global_settings.volume); 1385 sound_set_volume(global_settings.volume);
1358 track_count = 0; 1386 track_widx = track_ridx = 0;
1359 track_widx = 0; 1387 buf_ridx = buf_widx = 0;
1360 track_ridx = 0;
1361 buf_ridx = 0;
1362 buf_widx = 0;
1363 filebufused = 0; 1388 filebufused = 0;
1389
1390 memset(&tracks[0], 0, sizeof(struct track_info));
1364 1391
1365 last_peek_offset = -1; 1392 last_peek_offset = -1;
1366 1393
@@ -1373,81 +1400,69 @@ static void audio_play_start(size_t offset)
1373/* Send callback events to notify about new tracks. */ 1400/* Send callback events to notify about new tracks. */
1374static void generate_postbuffer_events(void) 1401static void generate_postbuffer_events(void)
1375{ 1402{
1376 int i; 1403 int cur_idx;
1377 int cur_ridx, event_count; 1404 int last_idx = 0;
1378 1405
1379 /* At first determine how many unsent events we have. */ 1406 if (have_tracks()) {
1380 cur_ridx = track_ridx; 1407 cur_idx = track_ridx;
1381 event_count = 0; 1408 while (1) {
1382 for (i = 0; i < track_count; i++) { 1409 if (!tracks[cur_idx].event_sent) {
1383 if (!tracks[cur_ridx].event_sent) 1410 if (last_idx) {
1384 event_count++; 1411 /* Mark the event 'sent' even if we don't really send one */
1385 if (++cur_ridx >= MAX_TRACK) 1412 tracks[last_idx].event_sent = true;
1386 cur_ridx -= MAX_TRACK; 1413 if (track_buffer_callback)
1387 } 1414 track_buffer_callback(&tracks[last_idx].id3, false);
1388 1415 }
1389 /* Now sent these events. */ 1416 last_idx = cur_idx;
1390 cur_ridx = track_ridx; 1417 }
1391 for (i = 0; i < track_count; i++) { 1418 if (cur_idx == track_widx)
1392 if (!tracks[cur_ridx].event_sent) { 1419 break;
1393 tracks[cur_ridx].event_sent = true; 1420 if (++cur_idx >= MAX_TRACK)
1394 event_count--; 1421 cur_idx -= MAX_TRACK;
1395 /* We still want to set event_sent flags even if not using 1422 }
1396 event callbacks. */ 1423
1424 if (last_idx) {
1425 tracks[last_idx].event_sent = true;
1397 if (track_buffer_callback) 1426 if (track_buffer_callback)
1398 track_buffer_callback(&tracks[cur_ridx].id3, event_count == 0); 1427 track_buffer_callback(&tracks[last_idx].id3, true);
1399 } 1428 }
1400 if (++cur_ridx >= MAX_TRACK)
1401 cur_ridx -= MAX_TRACK;
1402 } 1429 }
1403} 1430}
1404 1431
1405static void initialize_buffer_fill(bool start_play) 1432static void initialize_buffer_fill(bool start_play)
1406{ 1433{
1407 int cur_idx, i; 1434 if (start_play) {
1408 1435 filling_initial = true;
1409 if (!filling_initial && !start_play) 1436 fill_bytesleft = filebuflen >> 2;
1437 }
1438 else if (!filling_initial)
1410 { 1439 {
1411 fill_bytesleft = filebuflen - filebufused; 1440 /* Recalculate remaining bytes to buffer, but always leave extra
1412 cur_ti->start_pos = ci.curpos; 1441 * data for the currently playing codec to seek back into */
1442 size_t buf_bytesleft = filebuflen - filebufused;
1443
1444 if (buf_bytesleft > AUDIO_REBUFFER_GUESS_SIZE)
1445 fill_bytesleft = buf_bytesleft - AUDIO_REBUFFER_GUESS_SIZE;
1446 else
1447 fill_bytesleft = 0;
1448
1449 if (ci.curpos > AUDIO_REBUFFER_GUESS_SIZE)
1450 cur_ti->start_pos = ci.curpos - AUDIO_REBUFFER_GUESS_SIZE;
1451 else
1452 cur_ti->start_pos = 0;
1413 } 1453 }
1414 1454
1415 /* Initialize only once; do not truncate the tracks. */ 1455 /* Initialize only once; do not truncate the tracks. */
1416 if (filling) 1456 if (filling)
1417 return ; 1457 return ;
1418 1458
1419 /* Save the current resume position once. */
1420 playlist_update_resume_info(audio_current_track());
1421
1422 pcmbuf_set_boost_mode(true); 1459 pcmbuf_set_boost_mode(true);
1423 1460
1424 if (!start_play) { 1461 /* Mark all buffered entries null (not metadata for next track). */
1425 /* Calculate real track count after throwing away old tracks. */ 1462 audio_clear_track_entries(!start_play);
1426 cur_idx = track_ridx;
1427 for (i = 0; i < track_count; i++) {
1428 if (cur_idx == track_widx)
1429 break ;
1430
1431 if (++cur_idx >= MAX_TRACK)
1432 cur_idx = 0;
1433 }
1434
1435 track_count = i;
1436 if (tracks[track_widx].filesize == 0) {
1437 if (--track_widx < 0)
1438 track_widx = MAX_TRACK - 1;
1439 } else {
1440 track_count++;
1441 }
1442 1463
1443 /* Mark all buffered entries null (not metadata for next track). */ 1464 /* Save the current resume position once. */
1444 audio_clear_track_entries(true); 1465 playlist_update_resume_info(audio_current_track());
1445 }
1446 else
1447 {
1448 filling_initial = true;
1449 fill_bytesleft = filebuflen >> 2;
1450 }
1451 1466
1452 filling = true; 1467 filling = true;
1453 1468
@@ -1459,9 +1474,7 @@ static void audio_fill_file_buffer(bool start_play, size_t offset)
1459 if (ci.stop_codec || ci.reload_codec || playlist_end) 1474 if (ci.stop_codec || ci.reload_codec || playlist_end)
1460 return; 1475 return;
1461 1476
1462 mutex_lock(&mutex_bufferfill);
1463 initialize_buffer_fill(start_play); 1477 initialize_buffer_fill(start_play);
1464 mutex_unlock(&mutex_bufferfill);
1465 1478
1466 /* If we have a partially buffered track, continue loading, otherwise 1479 /* If we have a partially buffered track, continue loading, otherwise
1467 * load a new track */ 1480 * load a new track */
@@ -1602,7 +1615,7 @@ static int skip_previous_track(bool inside_codec_thread)
1602 track_ridx += MAX_TRACK; 1615 track_ridx += MAX_TRACK;
1603 1616
1604 if (tracks[track_ridx].filesize == 0 || 1617 if (tracks[track_ridx].filesize == 0 ||
1605 filebufused+ci.curpos + tracks[track_ridx].filesize > filebuflen) 1618 filebufused + ci.curpos + tracks[track_ridx].filesize > filebuflen)
1606 { 1619 {
1607 logf("Loading from disk..."); 1620 logf("Loading from disk...");
1608 ci.reload_codec = true; 1621 ci.reload_codec = true;
@@ -1729,24 +1742,27 @@ bool codec_request_next_track_callback(void)
1729/* Invalidates all but currently playing track. */ 1742/* Invalidates all but currently playing track. */
1730void audio_invalidate_tracks(void) 1743void audio_invalidate_tracks(void)
1731{ 1744{
1732 if (track_count == 0) { 1745 if (have_tracks()) {
1733 /* This call doesn't seem necessary anymore. Uncomment it 1746 playlist_end = false;
1734 if things break */ 1747 last_peek_offset = 0;
1735 /* queue_post(&audio_queue, Q_AUDIO_PLAY, 0); */
1736 return ;
1737 }
1738 1748
1739 playlist_end = false; 1749 track_widx = track_ridx;
1740 track_count = 1; 1750
1741 last_peek_offset = 0; 1751 audio_clear_track_entries(false);
1742 track_widx = track_ridx; 1752
1743 /* Mark all other entries null (also buffered wrong metadata). */ 1753 /* If the current track is fully buffered, advance the write pointer */
1744 audio_clear_track_entries(false); 1754 if (tracks[track_ridx].filerem == 0)
1745 filebufused = cur_ti->available; 1755 if (++track_widx >= MAX_TRACK)
1746 buf_widx = buf_ridx + cur_ti->available; 1756 track_widx -= MAX_TRACK;
1747 if (buf_widx >= filebuflen) 1757
1748 buf_widx -= filebuflen; 1758 /* Mark all other entries null (also buffered wrong metadata). */
1749 read_next_metadata(); 1759 filebufused = cur_ti->available;
1760 buf_widx = buf_ridx + cur_ti->available;
1761 if (buf_widx >= filebuflen)
1762 buf_widx -= filebuflen;
1763
1764 read_next_metadata();
1765 }
1750} 1766}
1751 1767
1752static void initiate_track_change(long peek_index) 1768static void initiate_track_change(long peek_index)
@@ -1816,7 +1832,6 @@ void audio_thread(void)
1816 case Q_AUDIO_PLAY: 1832 case Q_AUDIO_PLAY:
1817 /* Don't start playing immediately if user is skipping tracks 1833 /* Don't start playing immediately if user is skipping tracks
1818 * fast to prevent UI lag. */ 1834 * fast to prevent UI lag. */
1819 track_count = 0;
1820 last_peek_offset = 0; 1835 last_peek_offset = 0;
1821 track_changed = true; 1836 track_changed = true;
1822 playlist_end = false; 1837 playlist_end = false;
@@ -1881,6 +1896,11 @@ void audio_thread(void)
1881 ci.seek_time = (long)ev.data+1; 1896 ci.seek_time = (long)ev.data+1;
1882 break ; 1897 break ;
1883 1898
1899 case Q_AUDIO_REBUFFER_SEEK:
1900 logf("Re-buffering song");
1901 rebuffer_and_seek((size_t)ev.data);
1902 break;
1903
1884 case Q_AUDIO_DIR_SKIP: 1904 case Q_AUDIO_DIR_SKIP:
1885 logf("audio_dir_skip"); 1905 logf("audio_dir_skip");
1886 playlist_end = false; 1906 playlist_end = false;
@@ -2095,7 +2115,7 @@ struct mp3entry* audio_current_track(void)
2095 const char *p; 2115 const char *p;
2096 static struct mp3entry temp_id3; 2116 static struct mp3entry temp_id3;
2097 2117
2098 if (track_count > 0 && cur_ti->taginfo_ready) 2118 if (have_tracks() && cur_ti->taginfo_ready)
2099 return (struct mp3entry *)&cur_ti->id3; 2119 return (struct mp3entry *)&cur_ti->id3;
2100 2120
2101 memset(&temp_id3, 0, sizeof(struct mp3entry)); 2121 memset(&temp_id3, 0, sizeof(struct mp3entry));
@@ -2125,7 +2145,7 @@ struct mp3entry* audio_next_track(void)
2125{ 2145{
2126 int next_idx = track_ridx + 1; 2146 int next_idx = track_ridx + 1;
2127 2147
2128 if (track_count == 0) 2148 if (!have_tracks())
2129 return NULL; 2149 return NULL;
2130 2150
2131 if (next_idx >= MAX_TRACK) 2151 if (next_idx >= MAX_TRACK)
@@ -2198,10 +2218,6 @@ void audio_next(void)
2198 playlist_next(1); 2218 playlist_next(1);
2199 track_changed = true; 2219 track_changed = true;
2200 2220
2201 /* Force WPS to update even if audio thread is blocked spinning. */
2202 if (mutex_bufferfill.locked)
2203 cur_ti->taginfo_ready = false;
2204
2205 queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1); 2221 queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1);
2206} 2222}
2207 2223
@@ -2216,10 +2232,6 @@ void audio_prev(void)
2216 playlist_next(-1); 2232 playlist_next(-1);
2217 track_changed = true; 2233 track_changed = true;
2218 2234
2219 /* Force WPS to update even if audio thread is blocked spinning. */
2220 if (mutex_bufferfill.locked)
2221 cur_ti->taginfo_ready = false;
2222
2223 queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1); 2235 queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1);
2224} 2236}
2225 2237
@@ -2525,9 +2537,9 @@ static void playback_init(void)
2525 id3_voice.length = 1000000L; 2537 id3_voice.length = 1000000L;
2526 2538
2527 create_thread(codec_thread, codec_stack, sizeof(codec_stack), 2539 create_thread(codec_thread, codec_stack, sizeof(codec_stack),
2528 codec_thread_name); 2540 codec_thread_name);
2529 create_thread(voice_codec_thread, voice_codec_stack, 2541 create_thread(voice_codec_thread, voice_codec_stack,
2530 sizeof(voice_codec_stack), voice_codec_thread_name); 2542 sizeof(voice_codec_stack), voice_codec_thread_name);
2531 2543
2532 while (1) 2544 while (1)
2533 { 2545 {
@@ -2573,8 +2585,8 @@ void audio_preinit(void)
2573 /* Just to prevent cur_ti never be anything random. */ 2585 /* Just to prevent cur_ti never be anything random. */
2574 cur_ti = &tracks[0]; 2586 cur_ti = &tracks[0];
2575 2587
2576 mutex_init(&mutex_bufferfill);
2577 mutex_init(&mutex_codecthread); 2588 mutex_init(&mutex_codecthread);
2589 mutex_init(&mutex_rebuffer);
2578 2590
2579 queue_init(&audio_queue); 2591 queue_init(&audio_queue);
2580 queue_init(&codec_queue); 2592 queue_init(&codec_queue);
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index 0bc47c51f8..3ed1323701 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -70,6 +70,7 @@ void audio_resume(void);
70void audio_next(void); 70void audio_next(void);
71void audio_prev(void); 71void audio_prev(void);
72int audio_status(void); 72int audio_status(void);
73int audio_track_count(void); /* SWCODEC only */
73void audio_pre_ff_rewind(void); /* SWCODEC only */ 74void audio_pre_ff_rewind(void); /* SWCODEC only */
74void audio_ff_rewind(long newtime); 75void audio_ff_rewind(long newtime);
75void audio_flush_and_reload_tracks(void); 76void audio_flush_and_reload_tracks(void);