summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/playback.c176
1 files changed, 105 insertions, 71 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 6baf683342..ce80ee515c 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -85,9 +85,9 @@ static volatile bool paused;
85#define CODEC_AIFF "/.rockbox/codecs/aiff.codec" 85#define CODEC_AIFF "/.rockbox/codecs/aiff.codec"
86 86
87#define AUDIO_DEFAULT_FIRST_LIMIT (1024*1024*10) 87#define AUDIO_DEFAULT_FIRST_LIMIT (1024*1024*10)
88#define AUDIO_FILL_CYCLE (1024*256)
89#define AUDIO_DEFAULT_WATERMARK (1024*512) 88#define AUDIO_DEFAULT_WATERMARK (1024*512)
90#define AUDIO_DEFAULT_FILECHUNK (1024*32) 89#define AUDIO_DEFAULT_FILECHUNK (1024*32)
90#define AUDIO_FILEBUF_CRITICAL (1024*128)
91 91
92enum { 92enum {
93 Q_AUDIO_PLAY = 1, 93 Q_AUDIO_PLAY = 1,
@@ -104,7 +104,7 @@ enum {
104 Q_AUDIO_DIR_NEXT, 104 Q_AUDIO_DIR_NEXT,
105 Q_AUDIO_DIR_PREV, 105 Q_AUDIO_DIR_PREV,
106 Q_AUDIO_POSTINIT, 106 Q_AUDIO_POSTINIT,
107 Q_AUDIO_CHECK_BUFFER, 107 Q_AUDIO_FILL_BUFFER,
108 108
109 Q_CODEC_LOAD, 109 Q_CODEC_LOAD,
110 Q_CODEC_LOAD_DISK, 110 Q_CODEC_LOAD_DISK,
@@ -448,6 +448,11 @@ void codec_set_offset_callback(size_t value)
448 } 448 }
449} 449}
450 450
451static bool filebuf_is_lowdata(void)
452{
453 return filebufused < AUDIO_FILEBUF_CRITICAL;
454}
455
451static void advance_buffer_counters(size_t amount) { 456static void advance_buffer_counters(size_t amount) {
452 buf_ridx += amount; 457 buf_ridx += amount;
453 if (buf_ridx >= filebuflen) 458 if (buf_ridx >= filebuflen)
@@ -456,8 +461,10 @@ static void advance_buffer_counters(size_t amount) {
456 cur_ti->available -= amount; 461 cur_ti->available -= amount;
457 filebufused -= amount; 462 filebufused -= amount;
458 463
459 if (!pcmbuf_is_lowdata() && !mutex_bufferfill.locked) 464 /* Start buffer filling as necessary. */
460 queue_post(&audio_queue, Q_AUDIO_CHECK_BUFFER, 0); 465 if (!pcmbuf_is_lowdata() && !filling)
466 if (conf_watermark && filebufused <= conf_watermark && playing)
467 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
461} 468}
462 469
463/* copy up-to size bytes into ptr and return the actual size copied */ 470/* copy up-to size bytes into ptr and return the actual size copied */
@@ -480,7 +487,7 @@ size_t codec_filebuf_callback(void *ptr, size_t size)
480 487
481 /* Let the disk buffer catch fill until enough data is available */ 488 /* Let the disk buffer catch fill until enough data is available */
482 while (copy_n > cur_ti->available) { 489 while (copy_n > cur_ti->available) {
483 queue_post(&audio_queue, Q_AUDIO_CHECK_BUFFER, 0); 490 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
484 yield(); 491 yield();
485 if (ci.stop_codec || ci.reload_codec) 492 if (ci.stop_codec || ci.reload_codec)
486 return 0; 493 return 0;
@@ -567,7 +574,7 @@ void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
567 } 574 }
568 575
569 while (copy_n > cur_ti->available) { 576 while (copy_n > cur_ti->available) {
570 queue_post(&audio_queue, Q_AUDIO_CHECK_BUFFER, 0); 577 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
571 yield(); 578 yield();
572 if (ci.stop_codec || ci.reload_codec) { 579 if (ci.stop_codec || ci.reload_codec) {
573 *realsize = 0; 580 *realsize = 0;
@@ -624,7 +631,7 @@ static bool rebuffer_and_seek(size_t newpos)
624 631
625 mutex_unlock(&mutex_bufferfill); 632 mutex_unlock(&mutex_bufferfill);
626 633
627 queue_post(&audio_queue, Q_AUDIO_CHECK_BUFFER, 0); 634 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
628 635
629 return true; 636 return true;
630} 637}
@@ -802,17 +809,26 @@ static void pcmbuf_track_changed_callback(void)
802 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); 809 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
803} 810}
804 811
805/* Give codecs or file buffering the right amount of processing time 812/* Yield to codecs for as long as possible if they are in need of data
806 to prevent pcm audio buffer from going empty. */ 813 * return true if the caller should break to let the audio thread process
807static void yield_codecs(void) 814 * new events */
815static bool yield_codecs(void)
808{ 816{
809 yield(); 817 yield();
818 /* This indicates that we are in the initial buffer fill mode, or the
819 * playback recently skipped */
810 if (!pcm_is_playing() && !pcm_is_paused()) 820 if (!pcm_is_playing() && !pcm_is_paused())
811 sleep(5); 821 sleep(5);
822
812 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) 823 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
813 && !ci.stop_codec && playing && queue_empty(&audio_queue) 824 && !ci.stop_codec && playing && !filebuf_is_lowdata())
814 && filebufused > (128*1024)) 825 {
815 sleep(1); 826 sleep(1);
827 if (!queue_empty(&audio_queue)) {
828 return true;
829 }
830 }
831 return false;
816} 832}
817 833
818/* FIXME: This code should be made more generic and move to metadata.c */ 834/* FIXME: This code should be made more generic and move to metadata.c */
@@ -855,9 +871,8 @@ void strip_id3v1_tag(void)
855 } 871 }
856} 872}
857 873
858static void audio_fill_file_buffer(void) 874static void audio_read_file(void)
859{ 875{
860 size_t size;
861 size_t copy_n; 876 size_t copy_n;
862 int rc; 877 int rc;
863 878
@@ -869,17 +884,24 @@ static void audio_fill_file_buffer(void)
869 tracks[track_widx].codecsize = 0; 884 tracks[track_widx].codecsize = 0;
870 885
871 mutex_lock(&mutex_bufferfill); 886 mutex_lock(&mutex_bufferfill);
872 size = MIN(tracks[track_widx].filerem, AUDIO_FILL_CYCLE); 887 while (tracks[track_widx].filerem > 0) {
873 while (size > 0) { 888 /* Let the codec process until it is out of the danger zone, or there
874 /* Give codecs some processing time. */ 889 * is an event to handle. In the latter case, break this fill cycle
875 yield_codecs(); 890 * immediately */
891 if (yield_codecs())
892 break;
876 893
877 if (fill_bytesleft == 0) 894 if (fill_bytesleft == 0)
878 break ; 895 break ;
896
897 /* copy_n is the largest chunk that is safe to read */
879 copy_n = MIN(conf_filechunk, filebuflen - buf_widx); 898 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
880 copy_n = MIN(copy_n, fill_bytesleft); 899 copy_n = MIN(copy_n, fill_bytesleft);
900 /* rc is the actual amount read */
881 rc = read(current_fd, &filebuf[buf_widx], copy_n); 901 rc = read(current_fd, &filebuf[buf_widx], copy_n);
902
882 if (rc <= 0) { 903 if (rc <= 0) {
904 /* Reached the end of the file */
883 tracks[track_widx].filerem = 0; 905 tracks[track_widx].filerem = 0;
884 break ; 906 break ;
885 } 907 }
@@ -892,15 +914,12 @@ static void audio_fill_file_buffer(void)
892 tracks[track_widx].filepos += rc; 914 tracks[track_widx].filepos += rc;
893 filebufused += rc; 915 filebufused += rc;
894 fill_bytesleft -= rc; 916 fill_bytesleft -= rc;
895 if ((unsigned)rc > size) {
896 rc = size;
897 logf("audio_fill_file_buffer read past end of file\n");
898 }
899 size -= rc;
900 } 917 }
901 918
902 if (tracks[track_widx].filerem == 0) { 919 if (tracks[track_widx].filerem == 0) {
903 strip_id3v1_tag(); 920 strip_id3v1_tag();
921 close(current_fd);
922 current_fd = -1;
904 } 923 }
905 924
906 mutex_unlock(&mutex_bufferfill); 925 mutex_unlock(&mutex_bufferfill);
@@ -986,18 +1005,8 @@ static bool loadcodec(bool start_play)
986 1005
987 tracks[track_widx].codecsize = 0; 1006 tracks[track_widx].codecsize = 0;
988 1007
989 if (!start_play) { 1008 if (start_play)
990 prev_track = track_widx - 1; 1009 {
991 if (prev_track < 0)
992 prev_track = MAX_TRACK-1;
993 if (track_count > 0 &&
994 get_codec_base_type(tracks[track_widx].id3.codectype) ==
995 get_codec_base_type(tracks[prev_track].id3.codectype))
996 {
997 logf("Reusing prev. codec");
998 return true;
999 }
1000 } else {
1001 /* Load the codec directly from disk and save some memory. */ 1010 /* Load the codec directly from disk and save some memory. */
1002 cur_ti = &tracks[track_widx]; 1011 cur_ti = &tracks[track_widx];
1003 ci.filesize = cur_ti->filesize; 1012 ci.filesize = cur_ti->filesize;
@@ -1009,14 +1018,31 @@ static bool loadcodec(bool start_play)
1009 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_path); 1018 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_path);
1010 return true; 1019 return true;
1011 } 1020 }
1021 else
1022 {
1023 /* If the previous codec is the same as this one, there is no need
1024 * to put another copy of it on the file buffer */
1025 prev_track = track_widx - 1;
1026 if (prev_track < 0)
1027 prev_track = MAX_TRACK-1;
1028 if (track_count > 0 &&
1029 get_codec_base_type(tracks[track_widx].id3.codectype) ==
1030 get_codec_base_type(tracks[prev_track].id3.codectype))
1031 {
1032 logf("Reusing prev. codec");
1033 return true;
1034 }
1035 }
1012 1036
1013 fd = open(codec_path, O_RDONLY); 1037 fd = open(codec_path, O_RDONLY);
1014 if (fd < 0) { 1038 if (fd < 0)
1039 {
1015 logf("Codec doesn't exist!"); 1040 logf("Codec doesn't exist!");
1016 return false; 1041 return false;
1017 } 1042 }
1018 1043
1019 size = filesize(fd); 1044 size = filesize(fd);
1045 /* Never load a partial codec */
1020 if (fill_bytesleft < size + conf_watermark) { 1046 if (fill_bytesleft < size + conf_watermark) {
1021 logf("Not enough space"); 1047 logf("Not enough space");
1022 /* Set codectype back to zero to indicate no codec was loaded. */ 1048 /* Set codectype back to zero to indicate no codec was loaded. */
@@ -1026,8 +1052,12 @@ static bool loadcodec(bool start_play)
1026 return false; 1052 return false;
1027 } 1053 }
1028 1054
1055 mutex_lock(&mutex_bufferfill);
1029 i = 0; 1056 i = 0;
1030 while (i < size) { 1057 while (i < size) {
1058 /* FIXME: This will spin around pretty quickly, but still requires
1059 * full read of the codec when an event is posted to the audio
1060 * queue during this loop */
1031 yield_codecs(); 1061 yield_codecs();
1032 1062
1033 copy_n = MIN(conf_filechunk, filebuflen - buf_widx); 1063 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
@@ -1041,6 +1071,8 @@ static bool loadcodec(bool start_play)
1041 buf_widx -= filebuflen; 1071 buf_widx -= filebuflen;
1042 i += rc; 1072 i += rc;
1043 } 1073 }
1074 mutex_unlock(&mutex_bufferfill);
1075
1044 close(fd); 1076 close(fd);
1045 logf("Done: %dB", i); 1077 logf("Done: %dB", i);
1046 1078
@@ -1115,10 +1147,10 @@ static bool audio_load_track(int offset, bool start_play, int peek_offset)
1115 return false; 1147 return false;
1116 1148
1117 peek_again: 1149 peek_again:
1118 /* Get track name from current playlist read position. */
1119 logf("Buffering track:%d/%d", track_widx, track_ridx); 1150 logf("Buffering track:%d/%d", track_widx, track_ridx);
1120 /* Handle broken playlists. */ 1151 /* Get track name from current playlist read position. */
1121 while ( (trackname = playlist_peek(peek_offset)) != NULL) { 1152 while ( (trackname = playlist_peek(peek_offset)) != NULL) {
1153 /* Handle broken playlists. */
1122 fd = open(trackname, O_RDONLY); 1154 fd = open(trackname, O_RDONLY);
1123 if (fd < 0) { 1155 if (fd < 0) {
1124 logf("Open failed"); 1156 logf("Open failed");
@@ -1141,13 +1173,9 @@ static bool audio_load_track(int offset, bool start_play, int peek_offset)
1141 tracks[track_widx].filesize = size; 1173 tracks[track_widx].filesize = size;
1142 tracks[track_widx].filepos = 0; 1174 tracks[track_widx].filepos = 0;
1143 tracks[track_widx].available = 0; 1175 tracks[track_widx].available = 0;
1144 //tracks[track_widx].taginfo_ready = false;
1145 tracks[track_widx].playlist_offset = peek_offset; 1176 tracks[track_widx].playlist_offset = peek_offset;
1146 last_peek_offset = peek_offset; 1177 last_peek_offset = peek_offset;
1147 1178
1148 if (buf_widx >= filebuflen)
1149 buf_widx -= filebuflen;
1150
1151 /* Set default values */ 1179 /* Set default values */
1152 if (start_play) { 1180 if (start_play) {
1153 int last_codec = current_codec; 1181 int last_codec = current_codec;
@@ -1239,22 +1267,20 @@ static bool audio_load_track(int offset, bool start_play, int peek_offset)
1239 } 1267 }
1240 current_fd = fd; 1268 current_fd = fd;
1241 1269
1242 audio_fill_file_buffer(); 1270 audio_read_file();
1243 1271
1244 if (!start_play) 1272 if (!start_play)
1245 track_count++; 1273 track_count++;
1246 1274
1247 /* Leave the file handle open for faster buffer refill. */ 1275 if (tracks[track_widx].filerem == 0) {
1248 if (tracks[track_widx].filerem != 0) {
1249 logf("Partially buf:%d", tracks[track_widx].available);
1250 } else {
1251 logf("Completely buf."); 1276 logf("Completely buf.");
1252 close(fd);
1253
1254 if (++track_widx >= MAX_TRACK) { 1277 if (++track_widx >= MAX_TRACK) {
1255 track_widx = 0; 1278 track_widx = 0;
1256 } 1279 }
1257 tracks[track_widx].filesize = 0; 1280 tracks[track_widx].filesize = 0;
1281 tracks[track_widx].filerem = 0;
1282 } else {
1283 logf("Partially buf:%d", tracks[track_widx].available);
1258 } 1284 }
1259 1285
1260 return true; 1286 return true;
@@ -1402,13 +1428,16 @@ static void initialize_buffer_fill(void)
1402 /* Save the current resume position once. */ 1428 /* Save the current resume position once. */
1403 playlist_update_resume_info(audio_current_track()); 1429 playlist_update_resume_info(audio_current_track());
1404 1430
1405 fill_bytesleft = filebuflen - filebufused;
1406 cur_ti->start_pos = ci.curpos; 1431 cur_ti->start_pos = ci.curpos;
1407 1432
1408 pcmbuf_set_boost_mode(true); 1433 pcmbuf_set_boost_mode(true);
1409 1434
1410 filling = true; 1435 filling = true;
1411 1436
1437 /* FIXME: This should be recalculated more often than once per fill cycle.
1438 * This way we only fill up to the read point when filling started. */
1439 fill_bytesleft = filebuflen - filebufused;
1440
1412 /* Calculate real track count after throwing away old tracks. */ 1441 /* Calculate real track count after throwing away old tracks. */
1413 cur_idx = track_ridx; 1442 cur_idx = track_ridx;
1414 for (i = 0; i < track_count; i++) { 1443 for (i = 0; i < track_count; i++) {
@@ -1431,21 +1460,19 @@ static void initialize_buffer_fill(void)
1431 audio_clear_track_entries(true); 1460 audio_clear_track_entries(true);
1432} 1461}
1433 1462
1434static void audio_check_buffer(void) 1463static void audio_fill_file_buffer(void)
1435{ 1464{
1436 /* Start buffer filling as necessary. */ 1465 if (!filling)
1437 if ((!conf_watermark || filebufused > conf_watermark || !playing 1466 if (ci.stop_codec || ci.reload_codec || playlist_end)
1438 || ci.stop_codec || ci.reload_codec || playlist_end) 1467 return;
1439 && !filling)
1440 return;
1441 1468
1442 mutex_lock(&mutex_bufferfill); 1469 mutex_lock(&mutex_bufferfill);
1443 initialize_buffer_fill(); 1470 initialize_buffer_fill();
1444 mutex_unlock(&mutex_bufferfill); 1471 mutex_unlock(&mutex_bufferfill);
1445 1472
1446 /* Limit buffering size at first run. */ 1473 /* Limit buffering size at first run. */
1447 if (conf_bufferlimit && fill_bytesleft > conf_bufferlimit 1474 if (conf_bufferlimit &&
1448 - filebufused) { 1475 fill_bytesleft > conf_bufferlimit - filebufused) {
1449 if (conf_bufferlimit > filebufused) 1476 if (conf_bufferlimit > filebufused)
1450 fill_bytesleft = conf_bufferlimit - filebufused; 1477 fill_bytesleft = conf_bufferlimit - filebufused;
1451 else 1478 else
@@ -1458,18 +1485,14 @@ static void audio_check_buffer(void)
1458 /* Try to load remainings of the file. */ 1485 /* Try to load remainings of the file. */
1459 if (tracks[track_widx].filerem > 0) 1486 if (tracks[track_widx].filerem > 0)
1460 { 1487 {
1461 audio_fill_file_buffer(); 1488 audio_read_file();
1462 } 1489 }
1490 /* The current track is done, increase the track pointer */
1463 if (tracks[track_widx].filerem == 0) { 1491 if (tracks[track_widx].filerem == 0) {
1464 if (++track_widx == MAX_TRACK) 1492 if (++track_widx == MAX_TRACK)
1465 track_widx = 0; 1493 track_widx = 0;
1466 tracks[track_widx].filesize = 0; 1494 tracks[track_widx].filesize = 0;
1467 } 1495 }
1468 else
1469 {
1470 /* Done filling, couldn't read that whole file */
1471 fill_bytesleft = 0;
1472 }
1473 } 1496 }
1474 /* Otherwise, load a new track */ 1497 /* Otherwise, load a new track */
1475 else if (audio_load_track(0, false, last_peek_offset + 1)) 1498 else if (audio_load_track(0, false, last_peek_offset + 1))
@@ -1797,19 +1820,30 @@ void audio_thread(void)
1797 1820
1798 while (1) { 1821 while (1) {
1799 if (play_pending) 1822 if (play_pending)
1823 {
1800 queue_wait_w_tmo(&audio_queue, &ev, 0); 1824 queue_wait_w_tmo(&audio_queue, &ev, 0);
1825 if (ev.id == SYS_TIMEOUT)
1826 {
1827 ev.id = Q_AUDIO_PLAY;
1828 ev.data = (bool *)1;
1829 }
1830 }
1831 else if (filling)
1832 {
1833 queue_wait_w_tmo(&audio_queue, &ev, 0);
1834 if (ev.id == SYS_TIMEOUT)
1835 {
1836 ev.id = Q_AUDIO_FILL_BUFFER;
1837 ev.data = (bool *)1;
1838 }
1839 }
1801 else 1840 else
1802 queue_wait(&audio_queue, &ev); 1841 queue_wait(&audio_queue, &ev);
1803 1842
1804 if (ev.id == SYS_TIMEOUT && play_pending)
1805 {
1806 ev.id = Q_AUDIO_PLAY;
1807 ev.data = (bool *)1;
1808 }
1809 1843
1810 switch (ev.id) { 1844 switch (ev.id) {
1811 case Q_AUDIO_CHECK_BUFFER: 1845 case Q_AUDIO_FILL_BUFFER:
1812 audio_check_buffer(); 1846 audio_fill_file_buffer();
1813 break; 1847 break;
1814 case Q_AUDIO_PLAY: 1848 case Q_AUDIO_PLAY:
1815 /* Don't start playing immediately if user is skipping tracks 1849 /* Don't start playing immediately if user is skipping tracks