summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
authorBrandon Low <lostlogic@rockbox.org>2006-04-06 16:21:31 +0000
committerBrandon Low <lostlogic@rockbox.org>2006-04-06 16:21:31 +0000
commit930785cd8f68e0906d2a8d892d1db1d17dfc77e9 (patch)
treef6f9cf0828847c769159b7361f17489b27b878a5 /apps/playback.c
parent993a20a2ca7627b1517f4843750081b33897e8f1 (diff)
downloadrockbox-930785cd8f68e0906d2a8d892d1db1d17dfc77e9.tar.gz
rockbox-930785cd8f68e0906d2a8d892d1db1d17dfc77e9.zip
Stop abusing the queuing features, and start treating them with respect. This seems to solve audio skipping and track skipping issues as well as seeking inside the disk buffer for me.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9534 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/playback.c')
-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