diff options
| author | Michael Giacomelli <giac2000@hotmail.com> | 2011-01-02 02:49:13 +0000 |
|---|---|---|
| committer | Michael Giacomelli <giac2000@hotmail.com> | 2011-01-02 02:49:13 +0000 |
| commit | 66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3 (patch) | |
| tree | 7db19ba9c1f166c1f35e0581cd69801d7dc7e234 | |
| parent | 4048cf27a24b93e76c4262974831669e79c71da8 (diff) | |
| download | rockbox-66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3.zip rockbox-66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3.tar.gz rockbox-66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3.tar.bz2 rockbox-66e8fc0f0d05d926a90e8d9991f78b7a855eb7f3.tar.xz | |
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.lang | 28 | ||||
| -rw-r--r-- | apps/menus/settings_menu.c | 10 | ||||
| -rw-r--r-- | apps/playback.c | 40 | ||||
| -rw-r--r-- | apps/settings.h | 1 | ||||
| -rw-r--r-- | apps/settings_list.c | 3 | ||||
| -rw-r--r-- | apps/tagcache.c | 10 | ||||
| -rw-r--r-- | apps/tagcache.h | 5 | ||||
| -rw-r--r-- | apps/tagtree.c | 84 |
8 files changed, 150 insertions, 31 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index b2e54da..0fad5bf 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -12685,3 +12685,31 @@ *: "Filesize" </voice> </phrase> +<phrase> + id: LANG_AUTORESUME_ENABLE + desc: resume settings menu + user: core + <source> + *: "Enable automatic resume" + </source> + <dest> + *: "Enable automatic resume" + </dest> + <voice> + *: "Enable automatic resume" + </voice> +</phrase> +<phrase> + id: LANG_AUTORESUME_ENABLE_YES + desc: resume settings menu + user: core + <source> + *: "Yes (requires initialized database)" + </source> + <dest> + *: "Yes (requires initialized database)" + </dest> + <voice> + *: "Yes (requires initialized database)" + </voice> +</phrase> diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 5de3a30..e609a40 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, /***********************************/ /* SETTINGS MENU */ +#ifdef HAVE_TAGCACHE +MENUITEM_SETTING(autoresume_enable, &global_settings.autoresume_enable, NULL); +#endif + static struct browse_folder_info langs = { LANG_DIR, SHOW_LNG }; MENUITEM_FUNCTION(browse_langs, MENU_FUNC_USEPARAM, ID2P(LANG_LANGUAGE), @@ -436,7 +440,11 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0, &tagcache_menu, #endif &display_menu, &system_menu, - &bookmark_settings_menu, &browse_langs, &voice_settings_menu, + &bookmark_settings_menu, +#ifdef HAVE_TAGCACHE + &autoresume_enable, +#endif + &browse_langs, &voice_settings_menu, #ifdef HAVE_HOTKEY &hotkey_menu, #endif diff --git a/apps/playback.c b/apps/playback.c index b18ba14..e71e06b 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -992,13 +992,27 @@ long audio_filebufused(void) /* Update track info after successful a codec track change */ static void audio_update_trackinfo(void) { + bool resume = false; + /* Load the curent track's metadata into curtrack_id3 */ if (CUR_TI->id3_hid >= 0) copy_mp3entry(thistrack_id3, bufgetid3(CUR_TI->id3_hid)); /* Reset current position */ thistrack_id3->elapsed = 0; - thistrack_id3->offset = 0; + +#ifdef HAVE_TAGCACHE + /* Resume all manually selected tracks if so configured */ + resume = global_settings.autoresume_enable && !automatic_skip; +#endif + + if (!resume) + { + thistrack_id3->offset = 0; + } + + logf("audio_update_trackinfo: Set offset for %s to %lX\n", + thistrack_id3->title, thistrack_id3->offset); /* Update the codec API */ ci.filesize = CUR_TI->filesize; @@ -1210,6 +1224,9 @@ static bool audio_load_track(size_t offset, bool start_play) { copy_mp3entry(thistrack_id3, id3); thistrack_id3->offset = offset; + logf("audio_load_track: set offset for %s to %lX\n", + thistrack_id3->title, + offset); } else memset(thistrack_id3, 0, sizeof(struct mp3entry)); @@ -1415,8 +1432,14 @@ static void audio_finish_load_track(void) return; } - /* All required data is now available for the codec. */ - tracks[track_widx].taginfo_ready = true; + /* All required data is now available for the codec -- unless the + autoresume feature is in effect. In the latter case, the codec + must wait until after PLAYBACK_EVENT_TRACK_BUFFER, which may + generate a resume position. */ +#ifdef HAVE_TAGCACHE + if (! global_settings.autoresume_enable) +#endif + tracks[track_widx].taginfo_ready = true; if (start_play) { @@ -1424,10 +1447,17 @@ static void audio_finish_load_track(void) buf_request_buffer_handle(tracks[track_widx].audio_hid); } - track_widx = (track_widx + 1) & MAX_TRACK_MASK; - send_event(PLAYBACK_EVENT_TRACK_BUFFER, track_id3); +#ifdef HAVE_TAGCACHE + /* In case the autoresume feature has been enabled, finally all + required data is available for the codec. */ + if (global_settings.autoresume_enable) + tracks[track_widx].taginfo_ready = true; +#endif + + track_widx = (track_widx + 1) & MAX_TRACK_MASK; + /* load next track */ LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER"); queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); diff --git a/apps/settings.h b/apps/settings.h index fac2c96..4c28753 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -576,6 +576,7 @@ struct user_settings bool tagcache_ram; /* load tagcache to ram? */ #endif bool tagcache_autoupdate; /* automatically keep tagcache in sync? */ + bool autoresume_enable; /* enable autoupdate feature? */ bool runtimedb; /* runtime database active? */ #endif /* HAVE_TAGCACHE */ diff --git a/apps/settings_list.c b/apps/settings_list.c index 80000ab..3da5f1d 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -1257,6 +1257,9 @@ const struct settings_list settings[] = { ID2P(LANG_RANDOM)), #ifdef HAVE_TAGCACHE + BOOL_SETTING(0, autoresume_enable, LANG_AUTORESUME_ENABLE, false, + "autoresume enable", off_on, + LANG_AUTORESUME_ENABLE_YES, LANG_SET_BOOL_NO, NULL), OFFON_SETTING(0, runtimedb, LANG_RUNTIMEDB_ACTIVE, false, "gather runtime data", NULL), #endif diff --git a/apps/tagcache.c b/apps/tagcache.c index 0831bab..1d90eee 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -195,7 +195,7 @@ static const char *tagfile_entry_ec = "ll"; /** Note: This should be (1 + TAG_COUNT) amount of l's. */ -static const char *index_entry_ec = "lllllllllllllllllllll"; +static const char *index_entry_ec = "llllllllllllllllllllll"; static const char *tagcache_header_ec = "lll"; static const char *master_header_ec = "llllll"; @@ -1695,6 +1695,13 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename) if (id3->bitrate == 0) id3->bitrate = 1; + if (global_settings.autoresume_enable) + { + id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id); + logf("tagcache_fill_tags: Set offset for %s to %lX\n", + id3->title, id3->offset); + } + return true; } #endif @@ -2315,6 +2322,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) tmpdb_copy_tag(tag_playtime); tmpdb_copy_tag(tag_lastplayed); tmpdb_copy_tag(tag_commitid); + tmpdb_copy_tag(tag_lastoffset); /* Avoid processing this entry again. */ idx.flag |= FLAG_RESURRECTED; diff --git a/apps/tagcache.h b/apps/tagcache.h index b52da76..4fffcca 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -32,7 +32,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, - tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, + tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastoffset, /* Real tags end here, count them. */ TAG_COUNT, /* Virtual tags */ @@ -50,7 +50,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x5443480d +#define TAGCACHE_MAGIC 0x5443480e /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 @@ -103,6 +103,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \ (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \ (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \ + (1LU << tag_lastoffset) | \ (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \ (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \ (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore)) diff --git a/apps/tagtree.c b/apps/tagtree.c index 75caab0..8ebac0b 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -53,6 +53,8 @@ #include "storage.h" #include "dir.h" +#define str_or_empty(x) (x ? x : "(NULL)") + #define FILE_SEARCH_INSTRUCTIONS ROCKBOX_DIR "/tagnavi.config" static int tagtree_play_folder(struct tree_context* c); @@ -168,6 +170,8 @@ static int current_entry_count; static struct tree_context *tc; +extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */ + static int get_token_str(char *buf, int size) { /* Find the start. */ @@ -239,6 +243,7 @@ static int get_tag(int *tag) MATCH(tag, buf, "playcount", tag_playcount); MATCH(tag, buf, "rating", tag_rating); MATCH(tag, buf, "lastplayed", tag_lastplayed); + MATCH(tag, buf, "lastoffset", tag_lastoffset); MATCH(tag, buf, "commitid", tag_commitid); MATCH(tag, buf, "entryage", tag_virt_entryage); MATCH(tag, buf, "autoscore", tag_virt_autoscore); @@ -647,7 +652,7 @@ static void tagtree_buffer_event(void *data) struct mp3entry *id3 = (struct mp3entry*)data; /* Do not gather data unless proper setting has been enabled. */ - if (!global_settings.runtimedb) + if (!global_settings.runtimedb && !global_settings.autoresume_enable) return; logf("be:%s", id3->path); @@ -661,12 +666,30 @@ static void tagtree_buffer_event(void *data) return; } - id3->playcount = tagcache_get_numeric(&tcs, tag_playcount); - if (!id3->rating) - id3->rating = tagcache_get_numeric(&tcs, tag_rating); - id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed); - id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10; - id3->playtime = tagcache_get_numeric(&tcs, tag_playtime); + if (global_settings.runtimedb) + { + id3->playcount = tagcache_get_numeric(&tcs, tag_playcount); + if (!id3->rating) + id3->rating = tagcache_get_numeric(&tcs, tag_rating); + id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed); + id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10; + id3->playtime = tagcache_get_numeric(&tcs, tag_playtime); + + logf("-> %ld/%ld", id3->playcount, id3->playtime); + } + + if (global_settings.autoresume_enable) + { + /* Load current file resume offset if not already defined (by + another resume mechanism) */ + if (id3->offset == 0) + { + id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset); + + logf("tagtree_buffer_event: Set offset for %s to %lX\n", + str_or_empty(id3->title), id3->offset); + } + } /* Store our tagcache index pointer. */ id3->tagcache_idx = tcs.idx_id+1; @@ -676,16 +699,14 @@ static void tagtree_buffer_event(void *data) static void tagtree_track_finish_event(void *data) { - long playcount; - long playtime; long lastplayed; long tagcache_idx; struct mp3entry *id3 = (struct mp3entry*)data; /* Do not gather data unless proper setting has been enabled. */ - if (!global_settings.runtimedb) + if (!global_settings.runtimedb && !global_settings.autoresume_enable) { - logf("runtimedb gathering not enabled"); + logf("runtimedb gathering and autoresume not enabled"); return; } @@ -704,7 +725,6 @@ static void tagtree_track_finish_event(void *data) return; } - playcount = id3->playcount + 1; lastplayed = tagcache_increase_serial(); if (lastplayed < 0) { @@ -712,17 +732,37 @@ static void tagtree_track_finish_event(void *data) return; } - /* Ignore the last 15s (crossfade etc.) */ - playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000); - - logf("ube:%s", id3->path); - logf("-> %ld/%ld", playcount, playtime); - logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000)); + if (global_settings.runtimedb) + { + long playcount; + long playtime; + + playcount = id3->playcount + 1; + + /* Ignore the last 15s (crossfade etc.) */ + playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000); + + logf("ube:%s", id3->path); + logf("-> %ld/%ld", playcount, playtime); + logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, + MIN(id3->length, id3->elapsed + 15 * 1000)); - /* Queue the updates to the tagcache system. */ - tagcache_update_numeric(tagcache_idx, tag_playcount, playcount); - tagcache_update_numeric(tagcache_idx, tag_playtime, playtime); - tagcache_update_numeric(tagcache_idx, tag_lastplayed, lastplayed); + /* Queue the updates to the tagcache system. */ + tagcache_update_numeric(tagcache_idx, tag_playcount, playcount); + tagcache_update_numeric(tagcache_idx, tag_playtime, playtime); + tagcache_update_numeric(tagcache_idx, tag_lastplayed, lastplayed); + } + + if (global_settings.autoresume_enable) + { + unsigned long offset + = automatic_skip ? 0 : id3->offset; + + tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); + + logf("tagtree_track_finish_event: Save offset for %s: %lX", + str_or_empty(id3->title), offset); + } } bool tagtree_export(void) |