summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Giacomelli <giac2000@hotmail.com>2011-01-02 02:49:13 +0000
committerMichael Giacomelli <giac2000@hotmail.com>2011-01-02 02:49:13 +0000
commit66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3 (patch)
tree7db19ba9c1f166c1f35e0581cd69801d7dc7e234
parent4048cf27a24b93e76c4262974831669e79c71da8 (diff)
downloadrockbox-66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3.tar.gz
rockbox-66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3.zip
Commit part of FS#11748 by Michael Hohmuth. Adds support for automatically resuming any song that is not played to completion at any point later in time, regardless of how many intermediate tracks are played. This is accomplished by expanding the database to record incompletely played tracks. Currently, the feature is simply on or off, in which case all tracks automatically resume, or they do not. The remainder of patches in the task expand this feature by allowing only certain file to automatically resume, only resuming in certain circumstances, etc but are not included until we reach agreement on what should be included. Additionally, the manual will need to be updated once we agree on the available settings.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28942 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/lang/english.lang28
-rw-r--r--apps/menus/settings_menu.c10
-rw-r--r--apps/playback.c40
-rw-r--r--apps/settings.h1
-rw-r--r--apps/settings_list.c3
-rw-r--r--apps/tagcache.c10
-rw-r--r--apps/tagcache.h5
-rw-r--r--apps/tagtree.c84
8 files changed, 150 insertions, 31 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index b2e54da8e9..0fad5bf5b0 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -12685,3 +12685,31 @@
12685 *: "Filesize" 12685 *: "Filesize"
12686 </voice> 12686 </voice>
12687</phrase> 12687</phrase>
12688<phrase>
12689 id: LANG_AUTORESUME_ENABLE
12690 desc: resume settings menu
12691 user: core
12692 <source>
12693 *: "Enable automatic resume"
12694 </source>
12695 <dest>
12696 *: "Enable automatic resume"
12697 </dest>
12698 <voice>
12699 *: "Enable automatic resume"
12700 </voice>
12701</phrase>
12702<phrase>
12703 id: LANG_AUTORESUME_ENABLE_YES
12704 desc: resume settings menu
12705 user: core
12706 <source>
12707 *: "Yes (requires initialized database)"
12708 </source>
12709 <dest>
12710 *: "Yes (requires initialized database)"
12711 </dest>
12712 <voice>
12713 *: "Yes (requires initialized database)"
12714 </voice>
12715</phrase>
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 5de3a305f9..e609a4032e 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -424,6 +424,10 @@ MAKE_MENU(hotkey_menu, ID2P(LANG_HOTKEY), 0, Icon_NOICON,
424/***********************************/ 424/***********************************/
425/* SETTINGS MENU */ 425/* SETTINGS MENU */
426 426
427#ifdef HAVE_TAGCACHE
428MENUITEM_SETTING(autoresume_enable, &global_settings.autoresume_enable, NULL);
429#endif
430
427static struct browse_folder_info langs = { LANG_DIR, SHOW_LNG }; 431static struct browse_folder_info langs = { LANG_DIR, SHOW_LNG };
428 432
429MENUITEM_FUNCTION(browse_langs, MENU_FUNC_USEPARAM, ID2P(LANG_LANGUAGE), 433MENUITEM_FUNCTION(browse_langs, MENU_FUNC_USEPARAM, ID2P(LANG_LANGUAGE),
@@ -436,7 +440,11 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0,
436 &tagcache_menu, 440 &tagcache_menu,
437#endif 441#endif
438 &display_menu, &system_menu, 442 &display_menu, &system_menu,
439 &bookmark_settings_menu, &browse_langs, &voice_settings_menu, 443 &bookmark_settings_menu,
444#ifdef HAVE_TAGCACHE
445 &autoresume_enable,
446#endif
447 &browse_langs, &voice_settings_menu,
440#ifdef HAVE_HOTKEY 448#ifdef HAVE_HOTKEY
441 &hotkey_menu, 449 &hotkey_menu,
442#endif 450#endif
diff --git a/apps/playback.c b/apps/playback.c
index b18ba14e9f..e71e06b92c 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -992,13 +992,27 @@ long audio_filebufused(void)
992/* Update track info after successful a codec track change */ 992/* Update track info after successful a codec track change */
993static void audio_update_trackinfo(void) 993static void audio_update_trackinfo(void)
994{ 994{
995 bool resume = false;
996
995 /* Load the curent track's metadata into curtrack_id3 */ 997 /* Load the curent track's metadata into curtrack_id3 */
996 if (CUR_TI->id3_hid >= 0) 998 if (CUR_TI->id3_hid >= 0)
997 copy_mp3entry(thistrack_id3, bufgetid3(CUR_TI->id3_hid)); 999 copy_mp3entry(thistrack_id3, bufgetid3(CUR_TI->id3_hid));
998 1000
999 /* Reset current position */ 1001 /* Reset current position */
1000 thistrack_id3->elapsed = 0; 1002 thistrack_id3->elapsed = 0;
1001 thistrack_id3->offset = 0; 1003
1004#ifdef HAVE_TAGCACHE
1005 /* Resume all manually selected tracks if so configured */
1006 resume = global_settings.autoresume_enable && !automatic_skip;
1007#endif
1008
1009 if (!resume)
1010 {
1011 thistrack_id3->offset = 0;
1012 }
1013
1014 logf("audio_update_trackinfo: Set offset for %s to %lX\n",
1015 thistrack_id3->title, thistrack_id3->offset);
1002 1016
1003 /* Update the codec API */ 1017 /* Update the codec API */
1004 ci.filesize = CUR_TI->filesize; 1018 ci.filesize = CUR_TI->filesize;
@@ -1210,6 +1224,9 @@ static bool audio_load_track(size_t offset, bool start_play)
1210 { 1224 {
1211 copy_mp3entry(thistrack_id3, id3); 1225 copy_mp3entry(thistrack_id3, id3);
1212 thistrack_id3->offset = offset; 1226 thistrack_id3->offset = offset;
1227 logf("audio_load_track: set offset for %s to %lX\n",
1228 thistrack_id3->title,
1229 offset);
1213 } 1230 }
1214 else 1231 else
1215 memset(thistrack_id3, 0, sizeof(struct mp3entry)); 1232 memset(thistrack_id3, 0, sizeof(struct mp3entry));
@@ -1415,8 +1432,14 @@ static void audio_finish_load_track(void)
1415 return; 1432 return;
1416 } 1433 }
1417 1434
1418 /* All required data is now available for the codec. */ 1435 /* All required data is now available for the codec -- unless the
1419 tracks[track_widx].taginfo_ready = true; 1436 autoresume feature is in effect. In the latter case, the codec
1437 must wait until after PLAYBACK_EVENT_TRACK_BUFFER, which may
1438 generate a resume position. */
1439#ifdef HAVE_TAGCACHE
1440 if (! global_settings.autoresume_enable)
1441#endif
1442 tracks[track_widx].taginfo_ready = true;
1420 1443
1421 if (start_play) 1444 if (start_play)
1422 { 1445 {
@@ -1424,10 +1447,17 @@ static void audio_finish_load_track(void)
1424 buf_request_buffer_handle(tracks[track_widx].audio_hid); 1447 buf_request_buffer_handle(tracks[track_widx].audio_hid);
1425 } 1448 }
1426 1449
1427 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1428
1429 send_event(PLAYBACK_EVENT_TRACK_BUFFER, track_id3); 1450 send_event(PLAYBACK_EVENT_TRACK_BUFFER, track_id3);
1430 1451
1452#ifdef HAVE_TAGCACHE
1453 /* In case the autoresume feature has been enabled, finally all
1454 required data is available for the codec. */
1455 if (global_settings.autoresume_enable)
1456 tracks[track_widx].taginfo_ready = true;
1457#endif
1458
1459 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1460
1431 /* load next track */ 1461 /* load next track */
1432 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER"); 1462 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
1433 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); 1463 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
diff --git a/apps/settings.h b/apps/settings.h
index fac2c9634f..4c2875392b 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -576,6 +576,7 @@ struct user_settings
576 bool tagcache_ram; /* load tagcache to ram? */ 576 bool tagcache_ram; /* load tagcache to ram? */
577#endif 577#endif
578 bool tagcache_autoupdate; /* automatically keep tagcache in sync? */ 578 bool tagcache_autoupdate; /* automatically keep tagcache in sync? */
579 bool autoresume_enable; /* enable autoupdate feature? */
579 bool runtimedb; /* runtime database active? */ 580 bool runtimedb; /* runtime database active? */
580#endif /* HAVE_TAGCACHE */ 581#endif /* HAVE_TAGCACHE */
581 582
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 80000ab23f..3da5f1db62 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -1257,6 +1257,9 @@ const struct settings_list settings[] = {
1257 ID2P(LANG_RANDOM)), 1257 ID2P(LANG_RANDOM)),
1258 1258
1259#ifdef HAVE_TAGCACHE 1259#ifdef HAVE_TAGCACHE
1260 BOOL_SETTING(0, autoresume_enable, LANG_AUTORESUME_ENABLE, false,
1261 "autoresume enable", off_on,
1262 LANG_AUTORESUME_ENABLE_YES, LANG_SET_BOOL_NO, NULL),
1260 OFFON_SETTING(0, runtimedb, LANG_RUNTIMEDB_ACTIVE, false, 1263 OFFON_SETTING(0, runtimedb, LANG_RUNTIMEDB_ACTIVE, false,
1261 "gather runtime data", NULL), 1264 "gather runtime data", NULL),
1262#endif 1265#endif
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 0831bab32d..1d90eee24b 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -195,7 +195,7 @@ static const char *tagfile_entry_ec = "ll";
195/** 195/**
196 Note: This should be (1 + TAG_COUNT) amount of l's. 196 Note: This should be (1 + TAG_COUNT) amount of l's.
197 */ 197 */
198static const char *index_entry_ec = "lllllllllllllllllllll"; 198static const char *index_entry_ec = "llllllllllllllllllllll";
199 199
200static const char *tagcache_header_ec = "lll"; 200static const char *tagcache_header_ec = "lll";
201static const char *master_header_ec = "llllll"; 201static const char *master_header_ec = "llllll";
@@ -1695,6 +1695,13 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
1695 if (id3->bitrate == 0) 1695 if (id3->bitrate == 0)
1696 id3->bitrate = 1; 1696 id3->bitrate = 1;
1697 1697
1698 if (global_settings.autoresume_enable)
1699 {
1700 id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id);
1701 logf("tagcache_fill_tags: Set offset for %s to %lX\n",
1702 id3->title, id3->offset);
1703 }
1704
1698 return true; 1705 return true;
1699} 1706}
1700#endif 1707#endif
@@ -2315,6 +2322,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
2315 tmpdb_copy_tag(tag_playtime); 2322 tmpdb_copy_tag(tag_playtime);
2316 tmpdb_copy_tag(tag_lastplayed); 2323 tmpdb_copy_tag(tag_lastplayed);
2317 tmpdb_copy_tag(tag_commitid); 2324 tmpdb_copy_tag(tag_commitid);
2325 tmpdb_copy_tag(tag_lastoffset);
2318 2326
2319 /* Avoid processing this entry again. */ 2327 /* Avoid processing this entry again. */
2320 idx.flag |= FLAG_RESURRECTED; 2328 idx.flag |= FLAG_RESURRECTED;
diff --git a/apps/tagcache.h b/apps/tagcache.h
index b52da76a0f..4fffccae2f 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -32,7 +32,7 @@
32enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, 32enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
33 tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, 33 tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
34 tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, 34 tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating,
35 tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, 35 tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastoffset,
36 /* Real tags end here, count them. */ 36 /* Real tags end here, count them. */
37 TAG_COUNT, 37 TAG_COUNT,
38 /* Virtual tags */ 38 /* Virtual tags */
@@ -50,7 +50,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
50#define IDX_BUF_DEPTH 64 50#define IDX_BUF_DEPTH 64
51 51
52/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ 52/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
53#define TAGCACHE_MAGIC 0x5443480d 53#define TAGCACHE_MAGIC 0x5443480e
54 54
55/* How much to allocate extra space for ramcache. */ 55/* How much to allocate extra space for ramcache. */
56#define TAGCACHE_RESERVE 32768 56#define TAGCACHE_RESERVE 32768
@@ -103,6 +103,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
103 (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \ 103 (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \
104 (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \ 104 (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \
105 (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \ 105 (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \
106 (1LU << tag_lastoffset) | \
106 (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \ 107 (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \
107 (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \ 108 (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \
108 (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore)) 109 (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore))
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 75caab01d4..8ebac0b3a5 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -53,6 +53,8 @@
53#include "storage.h" 53#include "storage.h"
54#include "dir.h" 54#include "dir.h"
55 55
56#define str_or_empty(x) (x ? x : "(NULL)")
57
56#define FILE_SEARCH_INSTRUCTIONS ROCKBOX_DIR "/tagnavi.config" 58#define FILE_SEARCH_INSTRUCTIONS ROCKBOX_DIR "/tagnavi.config"
57 59
58static int tagtree_play_folder(struct tree_context* c); 60static int tagtree_play_folder(struct tree_context* c);
@@ -168,6 +170,8 @@ static int current_entry_count;
168 170
169static struct tree_context *tc; 171static struct tree_context *tc;
170 172
173extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */
174
171static int get_token_str(char *buf, int size) 175static int get_token_str(char *buf, int size)
172{ 176{
173 /* Find the start. */ 177 /* Find the start. */
@@ -239,6 +243,7 @@ static int get_tag(int *tag)
239 MATCH(tag, buf, "playcount", tag_playcount); 243 MATCH(tag, buf, "playcount", tag_playcount);
240 MATCH(tag, buf, "rating", tag_rating); 244 MATCH(tag, buf, "rating", tag_rating);
241 MATCH(tag, buf, "lastplayed", tag_lastplayed); 245 MATCH(tag, buf, "lastplayed", tag_lastplayed);
246 MATCH(tag, buf, "lastoffset", tag_lastoffset);
242 MATCH(tag, buf, "commitid", tag_commitid); 247 MATCH(tag, buf, "commitid", tag_commitid);
243 MATCH(tag, buf, "entryage", tag_virt_entryage); 248 MATCH(tag, buf, "entryage", tag_virt_entryage);
244 MATCH(tag, buf, "autoscore", tag_virt_autoscore); 249 MATCH(tag, buf, "autoscore", tag_virt_autoscore);
@@ -647,7 +652,7 @@ static void tagtree_buffer_event(void *data)
647 struct mp3entry *id3 = (struct mp3entry*)data; 652 struct mp3entry *id3 = (struct mp3entry*)data;
648 653
649 /* Do not gather data unless proper setting has been enabled. */ 654 /* Do not gather data unless proper setting has been enabled. */
650 if (!global_settings.runtimedb) 655 if (!global_settings.runtimedb && !global_settings.autoresume_enable)
651 return; 656 return;
652 657
653 logf("be:%s", id3->path); 658 logf("be:%s", id3->path);
@@ -661,12 +666,30 @@ static void tagtree_buffer_event(void *data)
661 return; 666 return;
662 } 667 }
663 668
664 id3->playcount = tagcache_get_numeric(&tcs, tag_playcount); 669 if (global_settings.runtimedb)
665 if (!id3->rating) 670 {
666 id3->rating = tagcache_get_numeric(&tcs, tag_rating); 671 id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
667 id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed); 672 if (!id3->rating)
668 id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10; 673 id3->rating = tagcache_get_numeric(&tcs, tag_rating);
669 id3->playtime = tagcache_get_numeric(&tcs, tag_playtime); 674 id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
675 id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10;
676 id3->playtime = tagcache_get_numeric(&tcs, tag_playtime);
677
678 logf("-> %ld/%ld", id3->playcount, id3->playtime);
679 }
680
681 if (global_settings.autoresume_enable)
682 {
683 /* Load current file resume offset if not already defined (by
684 another resume mechanism) */
685 if (id3->offset == 0)
686 {
687 id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset);
688
689 logf("tagtree_buffer_event: Set offset for %s to %lX\n",
690 str_or_empty(id3->title), id3->offset);
691 }
692 }
670 693
671 /* Store our tagcache index pointer. */ 694 /* Store our tagcache index pointer. */
672 id3->tagcache_idx = tcs.idx_id+1; 695 id3->tagcache_idx = tcs.idx_id+1;
@@ -676,16 +699,14 @@ static void tagtree_buffer_event(void *data)
676 699
677static void tagtree_track_finish_event(void *data) 700static void tagtree_track_finish_event(void *data)
678{ 701{
679 long playcount;
680 long playtime;
681 long lastplayed; 702 long lastplayed;
682 long tagcache_idx; 703 long tagcache_idx;
683 struct mp3entry *id3 = (struct mp3entry*)data; 704 struct mp3entry *id3 = (struct mp3entry*)data;
684 705
685 /* Do not gather data unless proper setting has been enabled. */ 706 /* Do not gather data unless proper setting has been enabled. */
686 if (!global_settings.runtimedb) 707 if (!global_settings.runtimedb && !global_settings.autoresume_enable)
687 { 708 {
688 logf("runtimedb gathering not enabled"); 709 logf("runtimedb gathering and autoresume not enabled");
689 return; 710 return;
690 } 711 }
691 712
@@ -704,7 +725,6 @@ static void tagtree_track_finish_event(void *data)
704 return; 725 return;
705 } 726 }
706 727
707 playcount = id3->playcount + 1;
708 lastplayed = tagcache_increase_serial(); 728 lastplayed = tagcache_increase_serial();
709 if (lastplayed < 0) 729 if (lastplayed < 0)
710 { 730 {
@@ -712,17 +732,37 @@ static void tagtree_track_finish_event(void *data)
712 return; 732 return;
713 } 733 }
714 734
715 /* Ignore the last 15s (crossfade etc.) */ 735 if (global_settings.runtimedb)
716 playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000); 736 {
717 737 long playcount;
718 logf("ube:%s", id3->path); 738 long playtime;
719 logf("-> %ld/%ld", playcount, playtime); 739
720 logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000)); 740 playcount = id3->playcount + 1;
741
742 /* Ignore the last 15s (crossfade etc.) */
743 playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000);
744
745 logf("ube:%s", id3->path);
746 logf("-> %ld/%ld", playcount, playtime);
747 logf("-> %ld/%ld/%ld", id3->elapsed, id3->length,
748 MIN(id3->length, id3->elapsed + 15 * 1000));
721 749
722 /* Queue the updates to the tagcache system. */ 750 /* Queue the updates to the tagcache system. */
723 tagcache_update_numeric(tagcache_idx, tag_playcount, playcount); 751 tagcache_update_numeric(tagcache_idx, tag_playcount, playcount);
724 tagcache_update_numeric(tagcache_idx, tag_playtime, playtime); 752 tagcache_update_numeric(tagcache_idx, tag_playtime, playtime);
725 tagcache_update_numeric(tagcache_idx, tag_lastplayed, lastplayed); 753 tagcache_update_numeric(tagcache_idx, tag_lastplayed, lastplayed);
754 }
755
756 if (global_settings.autoresume_enable)
757 {
758 unsigned long offset
759 = automatic_skip ? 0 : id3->offset;
760
761 tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);
762
763 logf("tagtree_track_finish_event: Save offset for %s: %lX",
764 str_or_empty(id3->title), offset);
765 }
726} 766}
727 767
728bool tagtree_export(void) 768bool tagtree_export(void)