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 @@ *: "Filesize" + + id: LANG_AUTORESUME_ENABLE + desc: resume settings menu + user: core + + *: "Enable automatic resume" + + + *: "Enable automatic resume" + + + *: "Enable automatic resume" + + + + id: LANG_AUTORESUME_ENABLE_YES + desc: resume settings menu + user: core + + *: "Yes (requires initialized database)" + + + *: "Yes (requires initialized database)" + + + *: "Yes (requires initialized database)" + + 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, /***********************************/ /* 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 b18ba14e9f..e71e06b92c 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 fac2c9634f..4c2875392b 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 80000ab23f..3da5f1db62 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 0831bab32d..1d90eee24b 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 b52da76a0f..4fffccae2f 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 75caab01d4..8ebac0b3a5 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; - /* 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); + 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); + } + + 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)