diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-07-14 07:59:39 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2014-03-10 04:12:30 +0100 |
commit | 31b712286721dd606940c7b557d03e3f714b9604 (patch) | |
tree | 8c4a4cc32e9000ea721ebb23aa3c0129ca97bf53 /apps | |
parent | dda54b85daa83b7803b4fb189ab45859f96ff3f9 (diff) | |
download | rockbox-31b712286721dd606940c7b557d03e3f714b9604.tar.gz rockbox-31b712286721dd606940c7b557d03e3f714b9604.zip |
Implement time-based resume and playback start.
This complements offset-based resume and playback start funcionality.
The implementation is global on both HWCODEC and SWCODEC.
Basically, if either the specified elapsed or offset are non-zero,
it indicates a mid-track resume.
To resume by time only, set elapsed to nonzero and offset to zero.
To resume by offset only, set offset to nonzero and elapsed to zero.
Which one the codec uses and which has priority is up to the codec;
however, using an elapsed time covers more cases:
* Codecs not able to use an offset such as VGM or other atomic
formats
* Starting playback at a nonzero elapsed time from a source that
contains no offset, such as a cuesheet
The change re-versions pretty much everything from tagcache to nvram.
Change-Id: Ic7aebb24e99a03ae99585c5e236eba960d163f38
Reviewed-on: http://gerrit.rockbox.org/516
Reviewed-by: Michael Sevakis <jethead71@rockbox.org>
Tested: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'apps')
-rw-r--r-- | apps/bookmark.c | 2 | ||||
-rw-r--r-- | apps/filetree.c | 5 | ||||
-rw-r--r-- | apps/gui/skin_engine/skin_parser.c | 6 | ||||
-rw-r--r-- | apps/gui/skin_engine/skin_touchsupport.c | 1 | ||||
-rw-r--r-- | apps/misc.c | 2 | ||||
-rw-r--r-- | apps/mpeg.c | 60 | ||||
-rw-r--r-- | apps/onplay.c | 2 | ||||
-rw-r--r-- | apps/playback.c | 137 | ||||
-rwxr-xr-x | apps/playlist.c | 21 | ||||
-rw-r--r-- | apps/playlist.h | 6 | ||||
-rw-r--r-- | apps/playlist_viewer.c | 10 | ||||
-rw-r--r-- | apps/plugin.h | 12 | ||||
-rw-r--r-- | apps/plugins/alarmclock.c | 1 | ||||
-rw-r--r-- | apps/plugins/alpine_cdc.c | 4 | ||||
-rw-r--r-- | apps/plugins/lib/playback_control.c | 1 | ||||
-rw-r--r-- | apps/plugins/lrcplayer.c | 1 | ||||
-rw-r--r-- | apps/plugins/pictureflow/pictureflow.c | 2 | ||||
-rw-r--r-- | apps/plugins/random_folder_advance_config.c | 2 | ||||
-rw-r--r-- | apps/root_menu.c | 1 | ||||
-rw-r--r-- | apps/settings.c | 11 | ||||
-rw-r--r-- | apps/settings.h | 2 | ||||
-rw-r--r-- | apps/settings_list.c | 1 | ||||
-rw-r--r-- | apps/settings_list.h | 2 | ||||
-rw-r--r-- | apps/tagcache.c | 12 | ||||
-rw-r--r-- | apps/tagcache.h | 14 | ||||
-rw-r--r-- | apps/tagtree.c | 20 | ||||
-rw-r--r-- | apps/tree.c | 8 | ||||
-rw-r--r-- | apps/tree.h | 4 |
28 files changed, 241 insertions, 109 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c index 543e89331a..3234e77d9b 100644 --- a/apps/bookmark.c +++ b/apps/bookmark.c | |||
@@ -972,7 +972,7 @@ static bool play_bookmark(const char* bookmark) | |||
972 | if (!warn_on_pl_erase()) | 972 | if (!warn_on_pl_erase()) |
973 | return false; | 973 | return false; |
974 | return bookmark_play(global_temp_buffer, bm.resume_index, | 974 | return bookmark_play(global_temp_buffer, bm.resume_index, |
975 | bm.resume_offset, bm.resume_seed, global_filename); | 975 | bm.resume_time, bm.resume_offset, bm.resume_seed, global_filename); |
976 | } | 976 | } |
977 | 977 | ||
978 | return false; | 978 | return false; |
diff --git a/apps/filetree.c b/apps/filetree.c index 2edcaf3a03..319b5f4a77 100644 --- a/apps/filetree.c +++ b/apps/filetree.c | |||
@@ -118,7 +118,7 @@ bool ft_play_playlist(char* pathname, char* dirname, char* filename) | |||
118 | playlist_shuffle(current_tick, -1); | 118 | playlist_shuffle(current_tick, -1); |
119 | } | 119 | } |
120 | 120 | ||
121 | playlist_start(0, 0); | 121 | playlist_start(0, 0, 0); |
122 | return true; | 122 | return true; |
123 | } | 123 | } |
124 | 124 | ||
@@ -498,7 +498,7 @@ int ft_enter(struct tree_context* c) | |||
498 | start_index = 0; | 498 | start_index = 0; |
499 | } | 499 | } |
500 | 500 | ||
501 | playlist_start(start_index, 0); | 501 | playlist_start(start_index, 0, 0); |
502 | play = true; | 502 | play = true; |
503 | } | 503 | } |
504 | break; | 504 | break; |
@@ -705,6 +705,7 @@ int ft_enter(struct tree_context* c) | |||
705 | global_status.resume_index = start_index; | 705 | global_status.resume_index = start_index; |
706 | global_status.resume_crc32 = | 706 | global_status.resume_crc32 = |
707 | playlist_get_filename_crc32(NULL, start_index); | 707 | playlist_get_filename_crc32(NULL, start_index); |
708 | global_status.resume_elapsed = 0; | ||
708 | global_status.resume_offset = 0; | 709 | global_status.resume_offset = 0; |
709 | status_save(); | 710 | status_save(); |
710 | rc = GO_TO_WPS; | 711 | rc = GO_TO_WPS; |
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index a76a06ac61..57153ed602 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c | |||
@@ -2414,10 +2414,12 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data, | |||
2414 | (((wps_data->last_albumart_height != aa->height) || | 2414 | (((wps_data->last_albumart_height != aa->height) || |
2415 | (wps_data->last_albumart_width != aa->width))))) | 2415 | (wps_data->last_albumart_width != aa->width))))) |
2416 | { | 2416 | { |
2417 | long offset = audio_current_track()->offset; | 2417 | struct mp3entry *id3 = audio_current_track(); |
2418 | unsigned long elapsed = id3->elapsed; | ||
2419 | unsigned long offset = id3->offset; | ||
2418 | audio_stop(); | 2420 | audio_stop(); |
2419 | if (!(status & AUDIO_STATUS_PAUSE)) | 2421 | if (!(status & AUDIO_STATUS_PAUSE)) |
2420 | audio_play(offset); | 2422 | audio_play(elapsed, offset); |
2421 | } | 2423 | } |
2422 | } | 2424 | } |
2423 | #endif | 2425 | #endif |
diff --git a/apps/gui/skin_engine/skin_touchsupport.c b/apps/gui/skin_engine/skin_touchsupport.c index dbc561500a..7a03e83c36 100644 --- a/apps/gui/skin_engine/skin_touchsupport.c +++ b/apps/gui/skin_engine/skin_touchsupport.c | |||
@@ -177,6 +177,7 @@ int skin_get_touchaction(struct wps_data *data, int* edge_offset, | |||
177 | if (playlist_resume() != -1) | 177 | if (playlist_resume() != -1) |
178 | { | 178 | { |
179 | playlist_start(global_status.resume_index, | 179 | playlist_start(global_status.resume_index, |
180 | global_status.resume_elapsed, | ||
180 | global_status.resume_offset); | 181 | global_status.resume_offset); |
181 | } | 182 | } |
182 | } | 183 | } |
diff --git a/apps/misc.c b/apps/misc.c index fdbc1fb831..6c589b99e4 100644 --- a/apps/misc.c +++ b/apps/misc.c | |||
@@ -618,6 +618,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame | |||
618 | if (resume && playlist_resume() != -1) | 618 | if (resume && playlist_resume() != -1) |
619 | { | 619 | { |
620 | playlist_start(global_status.resume_index, | 620 | playlist_start(global_status.resume_index, |
621 | global_status.resume_elapsed, | ||
621 | global_status.resume_offset); | 622 | global_status.resume_offset); |
622 | } | 623 | } |
623 | resume = false; | 624 | resume = false; |
@@ -657,6 +658,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame | |||
657 | if (playlist_resume() != -1) | 658 | if (playlist_resume() != -1) |
658 | { | 659 | { |
659 | playlist_start(global_status.resume_index, | 660 | playlist_start(global_status.resume_index, |
661 | global_status.resume_elapsed, | ||
660 | global_status.resume_offset); | 662 | global_status.resume_offset); |
661 | } | 663 | } |
662 | return event; | 664 | return event; |
diff --git a/apps/mpeg.c b/apps/mpeg.c index c0b2ae0c0e..d3e0e5c137 100644 --- a/apps/mpeg.c +++ b/apps/mpeg.c | |||
@@ -177,6 +177,13 @@ static long low_watermark; /* Dynamic low watermark level */ | |||
177 | static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ | 177 | static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ |
178 | static long lowest_watermark_level; /* Debug value to observe the buffer | 178 | static long lowest_watermark_level; /* Debug value to observe the buffer |
179 | usage */ | 179 | usage */ |
180 | |||
181 | struct audio_resume_info | ||
182 | { | ||
183 | unsigned long elapsed; | ||
184 | unsigned long offset; | ||
185 | }; | ||
186 | |||
180 | #if CONFIG_CODEC == MAS3587F | 187 | #if CONFIG_CODEC == MAS3587F |
181 | static char recording_filename[MAX_PATH]; /* argument to thread */ | 188 | static char recording_filename[MAX_PATH]; /* argument to thread */ |
182 | static char delayed_filename[MAX_PATH]; /* internal copy of above */ | 189 | static char delayed_filename[MAX_PATH]; /* internal copy of above */ |
@@ -430,10 +437,9 @@ static void set_elapsed(struct mp3entry* id3) | |||
430 | id3->elapsed = id3->offset / (id3->bitrate / 8); | 437 | id3->elapsed = id3->offset / (id3->bitrate / 8); |
431 | } | 438 | } |
432 | 439 | ||
433 | int audio_get_file_pos(void) | 440 | static int audio_get_file_pos_int(struct mp3entry *id3) |
434 | { | 441 | { |
435 | int pos = -1; | 442 | int pos = -1; |
436 | struct mp3entry *id3 = audio_current_track(); | ||
437 | 443 | ||
438 | if (id3->vbr) | 444 | if (id3->vbr) |
439 | { | 445 | { |
@@ -490,6 +496,12 @@ int audio_get_file_pos(void) | |||
490 | return pos; | 496 | return pos; |
491 | } | 497 | } |
492 | 498 | ||
499 | int audio_get_file_pos(void) | ||
500 | { | ||
501 | struct mp3entry *id3 = audio_current_track(); | ||
502 | return id3 ? audio_get_file_pos_int(id3) : 0; | ||
503 | } | ||
504 | |||
493 | unsigned long mpeg_get_last_header(void) | 505 | unsigned long mpeg_get_last_header(void) |
494 | { | 506 | { |
495 | #ifdef SIMULATOR | 507 | #ifdef SIMULATOR |
@@ -545,7 +557,13 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
545 | } | 557 | } |
546 | /* TODO: Do it without stopping playback, if possible */ | 558 | /* TODO: Do it without stopping playback, if possible */ |
547 | bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY; | 559 | bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY; |
548 | long offset = audio_current_track()->offset; | 560 | struct mp3entry *id3 = audio_current_track(); |
561 | unsigned long elapsed = 0, offset = 0; | ||
562 | if (id3) | ||
563 | { | ||
564 | elapsed = id3->elapsed; | ||
565 | offset = id3->offset; | ||
566 | } | ||
549 | /* don't call audio_hard_stop() as it frees this handle */ | 567 | /* don't call audio_hard_stop() as it frees this handle */ |
550 | if (thread_self() == audio_thread_id) | 568 | if (thread_self() == audio_thread_id) |
551 | { /* inline case MPEG_STOP (audio_stop()) response | 569 | { /* inline case MPEG_STOP (audio_stop()) response |
@@ -574,7 +592,7 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
574 | } | 592 | } |
575 | if (playing) | 593 | if (playing) |
576 | { /* safe to call even from the audio thread (due to queue_post()) */ | 594 | { /* safe to call even from the audio thread (due to queue_post()) */ |
577 | audio_play(offset); | 595 | audio_play(elapsed, offset); |
578 | } | 596 | } |
579 | 597 | ||
580 | return BUFLIB_CB_OK; | 598 | return BUFLIB_CB_OK; |
@@ -1274,7 +1292,7 @@ static void mpeg_thread(void) | |||
1274 | int unplayed_space_left; | 1292 | int unplayed_space_left; |
1275 | int amount_to_read; | 1293 | int amount_to_read; |
1276 | int t1, t2; | 1294 | int t1, t2; |
1277 | int start_offset; | 1295 | unsigned long start_elapsed, start_offset; |
1278 | #if CONFIG_CODEC == MAS3587F | 1296 | #if CONFIG_CODEC == MAS3587F |
1279 | int amount_to_save; | 1297 | int amount_to_save; |
1280 | int save_endpos = 0; | 1298 | int save_endpos = 0; |
@@ -1337,9 +1355,16 @@ static void mpeg_thread(void) | |||
1337 | break; | 1355 | break; |
1338 | } | 1356 | } |
1339 | 1357 | ||
1340 | start_offset = (int)ev.data; | 1358 | start_elapsed = ((struct audio_resume_info *)ev.data)->elapsed; |
1359 | start_offset = ((struct audio_resume_info *)ev.data)->offset; | ||
1341 | 1360 | ||
1342 | /* mid-song resume? */ | 1361 | /* mid-song resume? */ |
1362 | if (!start_offset && start_elapsed) { | ||
1363 | struct mp3entry *id3 = &get_trackdata(0)->id3; | ||
1364 | id3->elapsed = start_elapsed; | ||
1365 | start_offset = audio_get_file_pos_int(id3); | ||
1366 | } | ||
1367 | |||
1343 | if (start_offset) { | 1368 | if (start_offset) { |
1344 | struct mp3entry* id3 = &get_trackdata(0)->id3; | 1369 | struct mp3entry* id3 = &get_trackdata(0)->id3; |
1345 | lseek(mpeg_file, start_offset, SEEK_SET); | 1370 | lseek(mpeg_file, start_offset, SEEK_SET); |
@@ -1506,7 +1531,7 @@ static void mpeg_thread(void) | |||
1506 | 1531 | ||
1507 | id3->elapsed = newtime; | 1532 | id3->elapsed = newtime; |
1508 | 1533 | ||
1509 | newpos = audio_get_file_pos(); | 1534 | newpos = audio_get_file_pos_int(id3); |
1510 | if(newpos < 0) | 1535 | if(newpos < 0) |
1511 | { | 1536 | { |
1512 | id3->elapsed = oldtime; | 1537 | id3->elapsed = oldtime; |
@@ -2765,7 +2790,7 @@ static void audio_reset_buffer(void) | |||
2765 | audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize); | 2790 | audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize); |
2766 | } | 2791 | } |
2767 | 2792 | ||
2768 | void audio_play(long offset) | 2793 | void audio_play(unsigned long elapsed, unsigned long offset) |
2769 | { | 2794 | { |
2770 | audio_reset_buffer(); | 2795 | audio_reset_buffer(); |
2771 | #ifdef SIMULATOR | 2796 | #ifdef SIMULATOR |
@@ -2789,15 +2814,28 @@ void audio_play(long offset) | |||
2789 | real_mpeg_play(trackname); | 2814 | real_mpeg_play(trackname); |
2790 | #endif | 2815 | #endif |
2791 | playlist_next(steps); | 2816 | playlist_next(steps); |
2792 | taginfo.offset = offset; | 2817 | if (!offset && elapsed) |
2793 | set_elapsed(&taginfo); | 2818 | { |
2819 | /* has an elapsed time but no offset; elapsed may take | ||
2820 | precedence in this case */ | ||
2821 | taginfo.elapsed = elapsed; | ||
2822 | taginfo.offset = audio_get_file_pos_int(&taginfo); | ||
2823 | } | ||
2824 | else | ||
2825 | { | ||
2826 | taginfo.offset = offset; | ||
2827 | set_elapsed(&taginfo); | ||
2828 | } | ||
2794 | is_playing = true; | 2829 | is_playing = true; |
2795 | playing = true; | 2830 | playing = true; |
2796 | break; | 2831 | break; |
2797 | } while(1); | 2832 | } while(1); |
2798 | #else /* !SIMULATOR */ | 2833 | #else /* !SIMULATOR */ |
2834 | static struct audio_resume_info resume; | ||
2799 | is_playing = true; | 2835 | is_playing = true; |
2800 | queue_post(&mpeg_queue, MPEG_PLAY, offset); | 2836 | resume.elapsed = elapsed; |
2837 | resume.offset = offset; | ||
2838 | queue_post(&mpeg_queue, MPEG_PLAY, (intptr_t)&resume); | ||
2801 | #endif /* !SIMULATOR */ | 2839 | #endif /* !SIMULATOR */ |
2802 | 2840 | ||
2803 | mpeg_errno = 0; | 2841 | mpeg_errno = 0; |
diff --git a/apps/onplay.c b/apps/onplay.c index 9152d87bf5..7c5f517090 100644 --- a/apps/onplay.c +++ b/apps/onplay.c | |||
@@ -223,7 +223,7 @@ static bool add_to_playlist(int position, bool queue) | |||
223 | inserted */ | 223 | inserted */ |
224 | if (global_settings.playlist_shuffle) | 224 | if (global_settings.playlist_shuffle) |
225 | playlist_shuffle(current_tick, -1); | 225 | playlist_shuffle(current_tick, -1); |
226 | playlist_start(0,0); | 226 | playlist_start(0, 0, 0); |
227 | onplay_result = ONPLAY_START_PLAY; | 227 | onplay_result = ONPLAY_START_PLAY; |
228 | } | 228 | } |
229 | 229 | ||
diff --git a/apps/playback.c b/apps/playback.c index 5e234beb36..80a0585b17 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -151,6 +151,12 @@ enum audio_id3_types | |||
151 | }; | 151 | }; |
152 | static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */ | 152 | static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */ |
153 | 153 | ||
154 | struct audio_resume_info | ||
155 | { | ||
156 | unsigned long elapsed; | ||
157 | unsigned long offset; | ||
158 | }; | ||
159 | |||
154 | /* Peeking functions can yield and mess us up */ | 160 | /* Peeking functions can yield and mess us up */ |
155 | static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ | 161 | static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ |
156 | 162 | ||
@@ -325,7 +331,8 @@ enum audio_start_playback_flags | |||
325 | AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ | 331 | AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ |
326 | }; | 332 | }; |
327 | 333 | ||
328 | static void audio_start_playback(size_t offset, unsigned int flags); | 334 | static void audio_start_playback(const struct audio_resume_info *resume_info, |
335 | unsigned int flags); | ||
329 | static void audio_stop_playback(void); | 336 | static void audio_stop_playback(void); |
330 | static void buffer_event_buffer_low_callback(void *data); | 337 | static void buffer_event_buffer_low_callback(void *data); |
331 | static void buffer_event_rebuffer_callback(void *data); | 338 | static void buffer_event_rebuffer_callback(void *data); |
@@ -792,7 +799,11 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
792 | /* codec messages */ | 799 | /* codec messages */ |
793 | { Q_AUDIO_PLAY, Q_AUDIO_PLAY }, | 800 | { Q_AUDIO_PLAY, Q_AUDIO_PLAY }, |
794 | }; | 801 | }; |
802 | |||
803 | static struct audio_resume_info resume; | ||
804 | |||
795 | bool give_up = false; | 805 | bool give_up = false; |
806 | |||
796 | /* filebuflen is, at this point, the buffering.c buffer size, | 807 | /* filebuflen is, at this point, the buffering.c buffer size, |
797 | * i.e. the audiobuf except voice, scratch mem, pcm, ... */ | 808 | * i.e. the audiobuf except voice, scratch mem, pcm, ... */ |
798 | ssize_t extradata_size = old_size - filebuflen; | 809 | ssize_t extradata_size = old_size - filebuflen; |
@@ -813,7 +824,9 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
813 | 824 | ||
814 | 825 | ||
815 | /* TODO: Do it without stopping playback, if possible */ | 826 | /* TODO: Do it without stopping playback, if possible */ |
816 | long offset = audio_current_track()->offset; | 827 | struct mp3entry *id3 = audio_current_track(); |
828 | unsigned long elapsed = id3->elapsed; | ||
829 | unsigned long offset = id3->offset; | ||
817 | /* resume if playing */ | 830 | /* resume if playing */ |
818 | bool playing = (audio_status() == AUDIO_STATUS_PLAY); | 831 | bool playing = (audio_status() == AUDIO_STATUS_PLAY); |
819 | /* There's one problem with stoping and resuming: If it happens in a too | 832 | /* There's one problem with stoping and resuming: If it happens in a too |
@@ -825,10 +838,20 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
825 | * queue_post from the last call to get the correct offset. This also | 838 | * queue_post from the last call to get the correct offset. This also |
826 | * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only | 839 | * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only |
827 | * processed once. */ | 840 | * processed once. */ |
828 | bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list); | 841 | bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, |
842 | filter_list); | ||
829 | 843 | ||
830 | if (playing && offset > 0) /* current id3->offset is king */ | 844 | if (playing && ev.data != (intptr_t)&resume) |
831 | ev.data = offset; | 845 | { |
846 | resume = *(struct audio_resume_info *)ev.data; | ||
847 | |||
848 | /* current id3->elapsed/offset are king */ | ||
849 | if (elapsed > 0) | ||
850 | resume.elapsed = elapsed; | ||
851 | |||
852 | if (offset > 0) | ||
853 | resume.offset = offset; | ||
854 | } | ||
832 | 855 | ||
833 | /* don't call audio_hard_stop() as it frees this handle */ | 856 | /* don't call audio_hard_stop() as it frees this handle */ |
834 | if (thread_self() == audio_thread_id) | 857 | if (thread_self() == audio_thread_id) |
@@ -867,7 +890,7 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
867 | if (playing || play_queued) | 890 | if (playing || play_queued) |
868 | { | 891 | { |
869 | /* post, to make subsequent calls not break the resume position */ | 892 | /* post, to make subsequent calls not break the resume position */ |
870 | audio_queue_post(Q_AUDIO_PLAY, ev.data); | 893 | audio_queue_post(Q_AUDIO_PLAY, (intptr_t)&resume); |
871 | } | 894 | } |
872 | 895 | ||
873 | return BUFLIB_CB_OK; | 896 | return BUFLIB_CB_OK; |
@@ -1099,7 +1122,8 @@ static void audio_update_and_announce_next_track(const struct mp3entry *id3_next | |||
1099 | 1122 | ||
1100 | /* Bring the user current mp3entry up to date and set a new offset for the | 1123 | /* Bring the user current mp3entry up to date and set a new offset for the |
1101 | buffered metadata */ | 1124 | buffered metadata */ |
1102 | static void playing_id3_sync(struct track_info *user_info, off_t offset) | 1125 | static void playing_id3_sync(struct track_info *user_info, |
1126 | unsigned long elapsed, unsigned long offset) | ||
1103 | { | 1127 | { |
1104 | id3_mutex_lock(); | 1128 | id3_mutex_lock(); |
1105 | 1129 | ||
@@ -1113,9 +1137,14 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset) | |||
1113 | 1137 | ||
1114 | id3_write(PLAYING_ID3, id3); | 1138 | id3_write(PLAYING_ID3, id3); |
1115 | 1139 | ||
1116 | if (offset < 0) | 1140 | if (elapsed == (unsigned long)-1) |
1117 | { | 1141 | { |
1118 | playing_id3->elapsed = e; | 1142 | playing_id3->elapsed = e; |
1143 | elapsed = 0; | ||
1144 | } | ||
1145 | |||
1146 | if (offset == (unsigned long)-1) | ||
1147 | { | ||
1119 | playing_id3->offset = o; | 1148 | playing_id3->offset = o; |
1120 | offset = 0; | 1149 | offset = 0; |
1121 | } | 1150 | } |
@@ -1123,7 +1152,10 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset) | |||
1123 | pcm_play_unlock(); | 1152 | pcm_play_unlock(); |
1124 | 1153 | ||
1125 | if (id3) | 1154 | if (id3) |
1155 | { | ||
1156 | id3->elapsed = elapsed; | ||
1126 | id3->offset = offset; | 1157 | id3->offset = offset; |
1158 | } | ||
1127 | 1159 | ||
1128 | id3_mutex_unlock(); | 1160 | id3_mutex_unlock(); |
1129 | } | 1161 | } |
@@ -1299,19 +1331,16 @@ static bool audio_get_track_metadata(int offset, struct mp3entry *id3) | |||
1299 | return false; | 1331 | return false; |
1300 | } | 1332 | } |
1301 | 1333 | ||
1302 | /* Get a resume rewind adjusted offset from the ID3 */ | 1334 | /* Get resume rewind adjusted progress from the ID3 */ |
1303 | static unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3) | 1335 | static void resume_rewind_adjust_progress(const struct mp3entry *id3, |
1336 | unsigned long *elapsed, | ||
1337 | unsigned long *offset) | ||
1304 | { | 1338 | { |
1305 | unsigned long offset = id3->offset; | 1339 | unsigned int rewind = MAX(global_settings.resume_rewind, 0); |
1306 | size_t resume_rewind = global_settings.resume_rewind * | 1340 | unsigned long d_e = rewind*1000; |
1307 | id3->bitrate * (1000/8); | 1341 | *elapsed = id3->elapsed - MIN(id3->elapsed, d_e); |
1308 | 1342 | unsigned long d_o = rewind * id3->bitrate * (1000/8); | |
1309 | if (offset < resume_rewind) | 1343 | *offset = id3->offset - MIN(id3->offset, d_o); |
1310 | offset = 0; | ||
1311 | else | ||
1312 | offset -= resume_rewind; | ||
1313 | |||
1314 | return offset; | ||
1315 | } | 1344 | } |
1316 | 1345 | ||
1317 | /* Get the codec into ram and initialize it - keep it if it's ready */ | 1346 | /* Get the codec into ram and initialize it - keep it if it's ready */ |
@@ -1436,7 +1465,7 @@ static bool audio_start_codec(bool auto_skip) | |||
1436 | #ifdef HAVE_TAGCACHE | 1465 | #ifdef HAVE_TAGCACHE |
1437 | bool autoresume_enable = global_settings.autoresume_enable; | 1466 | bool autoresume_enable = global_settings.autoresume_enable; |
1438 | 1467 | ||
1439 | if (autoresume_enable && !cur_id3->offset) | 1468 | if (autoresume_enable && !(cur_id3->elapsed || cur_id3->offset)) |
1440 | { | 1469 | { |
1441 | /* Resume all manually selected tracks */ | 1470 | /* Resume all manually selected tracks */ |
1442 | bool resume = !auto_skip; | 1471 | bool resume = !auto_skip; |
@@ -1466,10 +1495,13 @@ static bool audio_start_codec(bool auto_skip) | |||
1466 | } | 1495 | } |
1467 | 1496 | ||
1468 | if (!resume) | 1497 | if (!resume) |
1498 | { | ||
1499 | cur_id3->elapsed = 0; | ||
1469 | cur_id3->offset = 0; | 1500 | cur_id3->offset = 0; |
1501 | } | ||
1470 | 1502 | ||
1471 | logf("%s: Set offset for %s to %lX\n", __func__, | 1503 | logf("%s: Set resume for %s to %lu %lX", __func__, |
1472 | cur_id3->title, cur_id3->offset); | 1504 | cur_id3->title, cur_id3->elapsed, cur_id3->offset); |
1473 | } | 1505 | } |
1474 | #endif /* HAVE_TAGCACHE */ | 1506 | #endif /* HAVE_TAGCACHE */ |
1475 | 1507 | ||
@@ -1481,7 +1513,8 @@ static bool audio_start_codec(bool auto_skip) | |||
1481 | and back again will cause accumulation of silent rewinds - that's not | 1513 | and back again will cause accumulation of silent rewinds - that's not |
1482 | our job to track directly nor could it be in any reasonable way | 1514 | our job to track directly nor could it be in any reasonable way |
1483 | */ | 1515 | */ |
1484 | cur_id3->offset = resume_rewind_adjusted_offset(cur_id3); | 1516 | resume_rewind_adjust_progress(cur_id3, &cur_id3->elapsed, |
1517 | &cur_id3->offset); | ||
1485 | 1518 | ||
1486 | /* Update the codec API with the metadata and track info */ | 1519 | /* Update the codec API with the metadata and track info */ |
1487 | id3_write(CODEC_ID3, cur_id3); | 1520 | id3_write(CODEC_ID3, cur_id3); |
@@ -1494,7 +1527,7 @@ static bool audio_start_codec(bool auto_skip) | |||
1494 | codec_go(); | 1527 | codec_go(); |
1495 | 1528 | ||
1496 | #ifdef HAVE_TAGCACHE | 1529 | #ifdef HAVE_TAGCACHE |
1497 | if (!autoresume_enable || cur_id3->offset) | 1530 | if (!autoresume_enable || cur_id3->elapsed || cur_id3->offset) |
1498 | #endif | 1531 | #endif |
1499 | { | 1532 | { |
1500 | /* Send the "buffer" event now */ | 1533 | /* Send the "buffer" event now */ |
@@ -1923,7 +1956,9 @@ static int audio_finish_load_track(struct track_info *info) | |||
1923 | 1956 | ||
1924 | /** Finally, load the audio **/ | 1957 | /** Finally, load the audio **/ |
1925 | size_t file_offset = 0; | 1958 | size_t file_offset = 0; |
1926 | track_id3->elapsed = 0; | 1959 | |
1960 | if (track_id3->elapsed > track_id3->length) | ||
1961 | track_id3->elapsed = 0; | ||
1927 | 1962 | ||
1928 | if (track_id3->offset >= info->filesize) | 1963 | if (track_id3->offset >= info->filesize) |
1929 | track_id3->offset = 0; | 1964 | track_id3->offset = 0; |
@@ -1933,7 +1968,11 @@ static int audio_finish_load_track(struct track_info *info) | |||
1933 | 1968 | ||
1934 | /* Adjust for resume rewind so we know what to buffer - starting the codec | 1969 | /* Adjust for resume rewind so we know what to buffer - starting the codec |
1935 | calls it again, so we don't save it (and they shouldn't accumulate) */ | 1970 | calls it again, so we don't save it (and they shouldn't accumulate) */ |
1936 | size_t offset = resume_rewind_adjusted_offset(track_id3); | 1971 | unsigned long elapsed, offset; |
1972 | resume_rewind_adjust_progress(track_id3, &elapsed, &offset); | ||
1973 | |||
1974 | logf("%s: Set resume for %s to %lu %lX", __func__, | ||
1975 | id3->title, elapsed, offset); | ||
1937 | 1976 | ||
1938 | enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ? | 1977 | enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ? |
1939 | TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO; | 1978 | TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO; |
@@ -2168,7 +2207,7 @@ static void audio_on_finish_load_track(int id3_hid) | |||
2168 | change otherwise */ | 2207 | change otherwise */ |
2169 | bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); | 2208 | bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); |
2170 | 2209 | ||
2171 | playing_id3_sync(info, -1); | 2210 | playing_id3_sync(info, -1, -1); |
2172 | 2211 | ||
2173 | if (!was_valid) | 2212 | if (!was_valid) |
2174 | { | 2213 | { |
@@ -2306,7 +2345,7 @@ static void audio_begin_track_change(enum pcm_track_change_type type, | |||
2306 | if (audio_start_codec(auto_skip)) | 2345 | if (audio_start_codec(auto_skip)) |
2307 | { | 2346 | { |
2308 | if (!auto_skip) | 2347 | if (!auto_skip) |
2309 | playing_id3_sync(info, -1); | 2348 | playing_id3_sync(info, -1, -1); |
2310 | return; | 2349 | return; |
2311 | } | 2350 | } |
2312 | 2351 | ||
@@ -2455,8 +2494,11 @@ static void audio_on_track_changed(void) | |||
2455 | /* Begin playback from an idle state, transition to a new playlist or | 2494 | /* Begin playback from an idle state, transition to a new playlist or |
2456 | invalidate the buffer and resume (if playing). | 2495 | invalidate the buffer and resume (if playing). |
2457 | (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */ | 2496 | (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */ |
2458 | static void audio_start_playback(size_t offset, unsigned int flags) | 2497 | static void audio_start_playback(const struct audio_resume_info *resume_info, |
2498 | unsigned int flags) | ||
2459 | { | 2499 | { |
2500 | struct audio_resume_info resume = | ||
2501 | *(resume_info ?: &(struct audio_resume_info){ 0, 0 } ); | ||
2460 | enum play_status old_status = play_status; | 2502 | enum play_status old_status = play_status; |
2461 | 2503 | ||
2462 | if (flags & AUDIO_START_NEWBUF) | 2504 | if (flags & AUDIO_START_NEWBUF) |
@@ -2469,7 +2511,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2469 | 2511 | ||
2470 | if (old_status != PLAY_STOPPED) | 2512 | if (old_status != PLAY_STOPPED) |
2471 | { | 2513 | { |
2472 | logf("%s(%lu): skipping", __func__, (unsigned long)offset); | 2514 | logf("%s(%lu, %lu): skipping", __func__, resume.elapsed, |
2515 | resume.offset); | ||
2473 | 2516 | ||
2474 | halt_decoding_track(true); | 2517 | halt_decoding_track(true); |
2475 | 2518 | ||
@@ -2481,7 +2524,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2481 | /* Clear out some stuff to resume the current track where it | 2524 | /* Clear out some stuff to resume the current track where it |
2482 | left off */ | 2525 | left off */ |
2483 | pcmbuf_play_stop(); | 2526 | pcmbuf_play_stop(); |
2484 | offset = id3_get(PLAYING_ID3)->offset; | 2527 | resume.elapsed = id3_get(PLAYING_ID3)->elapsed; |
2528 | resume.offset = id3_get(PLAYING_ID3)->offset; | ||
2485 | track_list_clear(TRACK_LIST_CLEAR_ALL); | 2529 | track_list_clear(TRACK_LIST_CLEAR_ALL); |
2486 | } | 2530 | } |
2487 | else | 2531 | else |
@@ -2505,7 +2549,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2505 | return; /* Must already be playing */ | 2549 | return; /* Must already be playing */ |
2506 | 2550 | ||
2507 | /* Cold playback start from a stopped state */ | 2551 | /* Cold playback start from a stopped state */ |
2508 | logf("%s(%lu): starting", __func__, offset); | 2552 | logf("%s(%lu, %lu): starting", __func__, resume.elapsed, |
2553 | resume.offset); | ||
2509 | 2554 | ||
2510 | /* Set audio parameters */ | 2555 | /* Set audio parameters */ |
2511 | #if INPUT_SRC_CAPS != 0 | 2556 | #if INPUT_SRC_CAPS != 0 |
@@ -2555,7 +2600,7 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2555 | if (trackstat >= LOAD_TRACK_OK) | 2600 | if (trackstat >= LOAD_TRACK_OK) |
2556 | { | 2601 | { |
2557 | /* This is the currently playing track - get metadata, stat */ | 2602 | /* This is the currently playing track - get metadata, stat */ |
2558 | playing_id3_sync(track_list_current(0), offset); | 2603 | playing_id3_sync(track_list_current(0), resume.elapsed, resume.offset); |
2559 | 2604 | ||
2560 | if (valid_mp3entry(id3_get(PLAYING_ID3))) | 2605 | if (valid_mp3entry(id3_get(PLAYING_ID3))) |
2561 | { | 2606 | { |
@@ -2892,7 +2937,9 @@ static void audio_on_ff_rewind(long time) | |||
2892 | 2937 | ||
2893 | if (!haltres) | 2938 | if (!haltres) |
2894 | { | 2939 | { |
2895 | /* If codec must be (re)started, reset the offset */ | 2940 | /* If codec must be (re)started, reset the resume info so that |
2941 | it doesn't execute resume procedures */ | ||
2942 | ci_id3->elapsed = 0; | ||
2896 | ci_id3->offset = 0; | 2943 | ci_id3->offset = 0; |
2897 | } | 2944 | } |
2898 | 2945 | ||
@@ -2970,7 +3017,7 @@ static void audio_on_audio_flush(void) | |||
2970 | not possible so a restart is required in order to continue the | 3017 | not possible so a restart is required in order to continue the |
2971 | currently playing track without the now invalid future track | 3018 | currently playing track without the now invalid future track |
2972 | playing */ | 3019 | playing */ |
2973 | audio_start_playback(0, AUDIO_START_RESTART); | 3020 | audio_start_playback(NULL, AUDIO_START_RESTART); |
2974 | break; | 3021 | break; |
2975 | 3022 | ||
2976 | default: /* Nothing else is a state */ | 3023 | default: /* Nothing else is a state */ |
@@ -3008,7 +3055,7 @@ void audio_playback_handler(struct queue_event *ev) | |||
3008 | /** Control messages **/ | 3055 | /** Control messages **/ |
3009 | case Q_AUDIO_PLAY: | 3056 | case Q_AUDIO_PLAY: |
3010 | LOGFQUEUE("playback < Q_AUDIO_PLAY"); | 3057 | LOGFQUEUE("playback < Q_AUDIO_PLAY"); |
3011 | audio_start_playback(ev->data, 0); | 3058 | audio_start_playback((struct audio_resume_info *)ev->data, 0); |
3012 | break; | 3059 | break; |
3013 | 3060 | ||
3014 | #ifdef HAVE_RECORDING | 3061 | #ifdef HAVE_RECORDING |
@@ -3082,7 +3129,7 @@ void audio_playback_handler(struct queue_event *ev) | |||
3082 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: | 3129 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: |
3083 | /* buffer needs to be reinitialized */ | 3130 | /* buffer needs to be reinitialized */ |
3084 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); | 3131 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); |
3085 | audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF); | 3132 | audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF); |
3086 | if (play_status == PLAY_STOPPED) | 3133 | if (play_status == PLAY_STOPPED) |
3087 | return; /* just need to change buffer state */ | 3134 | return; /* just need to change buffer state */ |
3088 | break; | 3135 | break; |
@@ -3368,8 +3415,8 @@ struct mp3entry * audio_next_track(void) | |||
3368 | return id3; | 3415 | return id3; |
3369 | } | 3416 | } |
3370 | 3417 | ||
3371 | /* Start playback at the specified offset */ | 3418 | /* Start playback at the specified elapsed time or offset */ |
3372 | void audio_play(long offset) | 3419 | void audio_play(unsigned long elapsed, unsigned long offset) |
3373 | { | 3420 | { |
3374 | logf("audio_play"); | 3421 | logf("audio_play"); |
3375 | 3422 | ||
@@ -3379,8 +3426,9 @@ void audio_play(long offset) | |||
3379 | talk_force_shutup(); | 3426 | talk_force_shutup(); |
3380 | #endif | 3427 | #endif |
3381 | 3428 | ||
3382 | LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset); | 3429 | LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %lu %lX", elapsed, offset); |
3383 | audio_queue_send(Q_AUDIO_PLAY, offset); | 3430 | audio_queue_send(Q_AUDIO_PLAY, |
3431 | (intptr_t)&(struct audio_resume_info){ elapsed, offset }); | ||
3384 | } | 3432 | } |
3385 | 3433 | ||
3386 | /* Stop playback if playing */ | 3434 | /* Stop playback if playing */ |
@@ -3582,11 +3630,10 @@ void playback_release_aa_slot(int slot) | |||
3582 | } | 3630 | } |
3583 | #endif /* HAVE_ALBUMART */ | 3631 | #endif /* HAVE_ALBUMART */ |
3584 | 3632 | ||
3585 | /* Would normally calculate byte offset from an elapsed time but is not | 3633 | /* Return file byte offset */ |
3586 | used on SWCODEC */ | ||
3587 | int audio_get_file_pos(void) | 3634 | int audio_get_file_pos(void) |
3588 | { | 3635 | { |
3589 | return 0; | 3636 | return id3_get(PLAYING_ID3)->offset; |
3590 | } | 3637 | } |
3591 | 3638 | ||
3592 | /* Return total file buffer length after accounting for the talk buf */ | 3639 | /* Return total file buffer length after accounting for the talk buf */ |
diff --git a/apps/playlist.c b/apps/playlist.c index 9c895bfd67..0e73781238 100755 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -621,7 +621,7 @@ static int create_and_play_dir(int direction, bool play_last) | |||
621 | #if (CONFIG_CODEC == SWCODEC) | 621 | #if (CONFIG_CODEC == SWCODEC) |
622 | current_playlist.started = true; | 622 | current_playlist.started = true; |
623 | #else | 623 | #else |
624 | playlist_start(index, 0); | 624 | playlist_start(index, 0, 0); |
625 | #endif | 625 | #endif |
626 | } | 626 | } |
627 | 627 | ||
@@ -2565,7 +2565,8 @@ unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, | |||
2565 | } | 2565 | } |
2566 | 2566 | ||
2567 | /* resume a playlist track with the given crc_32 of the track name. */ | 2567 | /* resume a playlist track with the given crc_32 of the track name. */ |
2568 | void playlist_resume_track(int start_index, unsigned int crc, int offset) | 2568 | void playlist_resume_track(int start_index, unsigned int crc, |
2569 | unsigned long elapsed, unsigned long offset) | ||
2569 | { | 2570 | { |
2570 | int i; | 2571 | int i; |
2571 | unsigned int tmp_crc; | 2572 | unsigned int tmp_crc; |
@@ -2573,7 +2574,7 @@ void playlist_resume_track(int start_index, unsigned int crc, int offset) | |||
2573 | tmp_crc = playlist_get_filename_crc32(playlist, start_index); | 2574 | tmp_crc = playlist_get_filename_crc32(playlist, start_index); |
2574 | if (tmp_crc == crc) | 2575 | if (tmp_crc == crc) |
2575 | { | 2576 | { |
2576 | playlist_start(start_index, offset); | 2577 | playlist_start(start_index, elapsed, offset); |
2577 | return; | 2578 | return; |
2578 | } | 2579 | } |
2579 | 2580 | ||
@@ -2582,17 +2583,18 @@ void playlist_resume_track(int start_index, unsigned int crc, int offset) | |||
2582 | tmp_crc = playlist_get_filename_crc32(playlist, i); | 2583 | tmp_crc = playlist_get_filename_crc32(playlist, i); |
2583 | if (tmp_crc == crc) | 2584 | if (tmp_crc == crc) |
2584 | { | 2585 | { |
2585 | playlist_start(i, offset); | 2586 | playlist_start(i, elapsed, offset); |
2586 | return; | 2587 | return; |
2587 | } | 2588 | } |
2588 | } | 2589 | } |
2589 | 2590 | ||
2590 | /* If we got here the file wasnt found, so start from the beginning */ | 2591 | /* If we got here the file wasnt found, so start from the beginning */ |
2591 | playlist_start(0,0); | 2592 | playlist_start(0, 0, 0); |
2592 | } | 2593 | } |
2593 | 2594 | ||
2594 | /* start playing current playlist at specified index/offset */ | 2595 | /* start playing current playlist at specified index/offset */ |
2595 | void playlist_start(int start_index, int offset) | 2596 | void playlist_start(int start_index, unsigned long elapsed, |
2597 | unsigned long offset) | ||
2596 | { | 2598 | { |
2597 | struct playlist_info* playlist = ¤t_playlist; | 2599 | struct playlist_info* playlist = ¤t_playlist; |
2598 | 2600 | ||
@@ -2605,7 +2607,7 @@ void playlist_start(int start_index, int offset) | |||
2605 | 2607 | ||
2606 | playlist->started = true; | 2608 | playlist->started = true; |
2607 | sync_control(playlist, false); | 2609 | sync_control(playlist, false); |
2608 | audio_play(offset); | 2610 | audio_play(elapsed, offset); |
2609 | } | 2611 | } |
2610 | 2612 | ||
2611 | /* Returns false if 'steps' is out of bounds, else true */ | 2613 | /* Returns false if 'steps' is out of bounds, else true */ |
@@ -2723,7 +2725,7 @@ int playlist_next(int steps) | |||
2723 | #if CONFIG_CODEC == SWCODEC | 2725 | #if CONFIG_CODEC == SWCODEC |
2724 | playlist->started = true; | 2726 | playlist->started = true; |
2725 | #else | 2727 | #else |
2726 | playlist_start(0, 0); | 2728 | playlist_start(0, 0, 0); |
2727 | #endif | 2729 | #endif |
2728 | playlist->index = 0; | 2730 | playlist->index = 0; |
2729 | index = 0; | 2731 | index = 0; |
@@ -2801,11 +2803,13 @@ int playlist_update_resume_info(const struct mp3entry* id3) | |||
2801 | if (id3) | 2803 | if (id3) |
2802 | { | 2804 | { |
2803 | if (global_status.resume_index != playlist->index || | 2805 | if (global_status.resume_index != playlist->index || |
2806 | global_status.resume_elapsed != id3->elapsed || | ||
2804 | global_status.resume_offset != id3->offset) | 2807 | global_status.resume_offset != id3->offset) |
2805 | { | 2808 | { |
2806 | unsigned int crc = crc_32(id3->path, strlen(id3->path), -1); | 2809 | unsigned int crc = crc_32(id3->path, strlen(id3->path), -1); |
2807 | global_status.resume_index = playlist->index; | 2810 | global_status.resume_index = playlist->index; |
2808 | global_status.resume_crc32 = crc; | 2811 | global_status.resume_crc32 = crc; |
2812 | global_status.resume_elapsed = id3->elapsed; | ||
2809 | global_status.resume_offset = id3->offset; | 2813 | global_status.resume_offset = id3->offset; |
2810 | status_save(); | 2814 | status_save(); |
2811 | } | 2815 | } |
@@ -2814,6 +2818,7 @@ int playlist_update_resume_info(const struct mp3entry* id3) | |||
2814 | { | 2818 | { |
2815 | global_status.resume_index = -1; | 2819 | global_status.resume_index = -1; |
2816 | global_status.resume_crc32 = -1; | 2820 | global_status.resume_crc32 = -1; |
2821 | global_status.resume_elapsed = -1; | ||
2817 | global_status.resume_offset = -1; | 2822 | global_status.resume_offset = -1; |
2818 | status_save(); | 2823 | status_save(); |
2819 | } | 2824 | } |
diff --git a/apps/playlist.h b/apps/playlist.h index d80d8aa2ee..6314e9a6ee 100644 --- a/apps/playlist.h +++ b/apps/playlist.h | |||
@@ -133,8 +133,10 @@ int playlist_add(const char *filename); | |||
133 | int playlist_shuffle(int random_seed, int start_index); | 133 | int playlist_shuffle(int random_seed, int start_index); |
134 | unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, | 134 | unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, |
135 | int index); | 135 | int index); |
136 | void playlist_resume_track(int start_index, unsigned int crc, int offset); | 136 | void playlist_resume_track(int start_index, unsigned int crc, |
137 | void playlist_start(int start_index, int offset); | 137 | unsigned long elapsed, unsigned long offset); |
138 | void playlist_start(int start_index, unsigned long elapsed, | ||
139 | unsigned long offset); | ||
138 | bool playlist_check(int steps); | 140 | bool playlist_check(int steps); |
139 | const char *playlist_peek(int steps, char* buf, size_t buf_size); | 141 | const char *playlist_peek(int steps, char* buf, size_t buf_size); |
140 | int playlist_next(int steps); | 142 | int playlist_next(int steps); |
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index 6a20bf1aac..d28643ab20 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c | |||
@@ -458,6 +458,7 @@ static bool update_playlist(bool force) | |||
458 | { | 458 | { |
459 | global_status.resume_index = -1; | 459 | global_status.resume_index = -1; |
460 | global_status.resume_offset = -1; | 460 | global_status.resume_offset = -1; |
461 | global_status.resume_elapsed = -1; | ||
461 | return false; | 462 | return false; |
462 | } | 463 | } |
463 | playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD, | 464 | playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD, |
@@ -466,6 +467,7 @@ static bool update_playlist(bool force) | |||
466 | { | 467 | { |
467 | global_status.resume_index = -1; | 468 | global_status.resume_index = -1; |
468 | global_status.resume_offset = -1; | 469 | global_status.resume_offset = -1; |
470 | global_status.resume_elapsed = -1; | ||
469 | return false; | 471 | return false; |
470 | } | 472 | } |
471 | } | 473 | } |
@@ -526,7 +528,7 @@ static int onplay_menu(int index) | |||
526 | if (current_track->display_index!=viewer.num_tracks || | 528 | if (current_track->display_index!=viewer.num_tracks || |
527 | global_settings.repeat_mode == REPEAT_ALL) | 529 | global_settings.repeat_mode == REPEAT_ALL) |
528 | { | 530 | { |
529 | audio_play(0); | 531 | audio_play(0, 0); |
530 | viewer.current_playing_track = -1; | 532 | viewer.current_playing_track = -1; |
531 | } | 533 | } |
532 | } | 534 | } |
@@ -773,7 +775,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename) | |||
773 | /* play new track */ | 775 | /* play new track */ |
774 | if (!global_settings.party_mode) | 776 | if (!global_settings.party_mode) |
775 | { | 777 | { |
776 | playlist_start(current_track->index, 0); | 778 | playlist_start(current_track->index, 0, 0); |
777 | update_playlist(false); | 779 | update_playlist(false); |
778 | } | 780 | } |
779 | } | 781 | } |
@@ -790,7 +792,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename) | |||
790 | goto exit; | 792 | goto exit; |
791 | if (global_settings.playlist_shuffle) | 793 | if (global_settings.playlist_shuffle) |
792 | start_index = playlist_shuffle(current_tick, start_index); | 794 | start_index = playlist_shuffle(current_tick, start_index); |
793 | playlist_start(start_index, 0); | 795 | playlist_start(start_index, 0, 0); |
794 | 796 | ||
795 | /* Our playlist is now the current list */ | 797 | /* Our playlist is now the current list */ |
796 | if (!playlist_viewer_init(&viewer, NULL, true)) | 798 | if (!playlist_viewer_init(&viewer, NULL, true)) |
@@ -937,7 +939,7 @@ bool search_playlist(void) | |||
937 | case ACTION_STD_OK: | 939 | case ACTION_STD_OK: |
938 | { | 940 | { |
939 | int sel = gui_synclist_get_sel_pos(&playlist_lists); | 941 | int sel = gui_synclist_get_sel_pos(&playlist_lists); |
940 | playlist_start(found_indicies[sel], 0); | 942 | playlist_start(found_indicies[sel], 0, 0); |
941 | exit = 1; | 943 | exit = 1; |
942 | } | 944 | } |
943 | break; | 945 | break; |
diff --git a/apps/plugin.h b/apps/plugin.h index 764af4a6b7..ffdfa8fb77 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -160,12 +160,12 @@ void* plugin_get_buffer(size_t *buffer_size); | |||
160 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 160 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
161 | 161 | ||
162 | /* increase this every time the api struct changes */ | 162 | /* increase this every time the api struct changes */ |
163 | #define PLUGIN_API_VERSION 226 | 163 | #define PLUGIN_API_VERSION 227 |
164 | 164 | ||
165 | /* update this to latest version if a change to the api struct breaks | 165 | /* update this to latest version if a change to the api struct breaks |
166 | backwards compatibility (and please take the opportunity to sort in any | 166 | backwards compatibility (and please take the opportunity to sort in any |
167 | new function which are "waiting" at the end of the function table) */ | 167 | new function which are "waiting" at the end of the function table) */ |
168 | #define PLUGIN_MIN_API_VERSION 226 | 168 | #define PLUGIN_MIN_API_VERSION 227 |
169 | 169 | ||
170 | /* plugin return codes */ | 170 | /* plugin return codes */ |
171 | /* internal returns start at 0x100 to make exit(1..255) work */ | 171 | /* internal returns start at 0x100 to make exit(1..255) work */ |
@@ -723,8 +723,10 @@ struct plugin_api { | |||
723 | /* playback control */ | 723 | /* playback control */ |
724 | int (*playlist_amount)(void); | 724 | int (*playlist_amount)(void); |
725 | int (*playlist_resume)(void); | 725 | int (*playlist_resume)(void); |
726 | void (*playlist_resume_track)(int start_index, unsigned int crc, int offset); | 726 | void (*playlist_resume_track)(int start_index, unsigned int crc, |
727 | void (*playlist_start)(int start_index, int offset); | 727 | unsigned long elapsed, unsigned long offset); |
728 | void (*playlist_start)(int start_index, unsigned long elapsed, | ||
729 | unsigned long offset); | ||
728 | int (*playlist_add)(const char *filename); | 730 | int (*playlist_add)(const char *filename); |
729 | void (*playlist_sync)(struct playlist_info* playlist); | 731 | void (*playlist_sync)(struct playlist_info* playlist); |
730 | int (*playlist_remove_all_tracks)(struct playlist_info *playlist); | 732 | int (*playlist_remove_all_tracks)(struct playlist_info *playlist); |
@@ -735,7 +737,7 @@ struct plugin_api { | |||
735 | const char *dirname, int position, bool queue, | 737 | const char *dirname, int position, bool queue, |
736 | bool recurse); | 738 | bool recurse); |
737 | int (*playlist_shuffle)(int random_seed, int start_index); | 739 | int (*playlist_shuffle)(int random_seed, int start_index); |
738 | void (*audio_play)(long offset); | 740 | void (*audio_play)(unsigned long elapsed, unsigned long offset); |
739 | void (*audio_stop)(void); | 741 | void (*audio_stop)(void); |
740 | void (*audio_pause)(void); | 742 | void (*audio_pause)(void); |
741 | void (*audio_resume)(void); | 743 | void (*audio_resume)(void); |
diff --git a/apps/plugins/alarmclock.c b/apps/plugins/alarmclock.c index 79a676003a..ecafceddc7 100644 --- a/apps/plugins/alarmclock.c +++ b/apps/plugins/alarmclock.c | |||
@@ -109,6 +109,7 @@ static void resume_audio(void) | |||
109 | if (rb->playlist_resume() != -1) { | 109 | if (rb->playlist_resume() != -1) { |
110 | rb->playlist_resume_track(rb->global_status->resume_index, | 110 | rb->playlist_resume_track(rb->global_status->resume_index, |
111 | rb->global_status->resume_crc32, | 111 | rb->global_status->resume_crc32, |
112 | rb->global_status->resume_elapsed, | ||
112 | rb->global_status->resume_offset); | 113 | rb->global_status->resume_offset); |
113 | } | 114 | } |
114 | } | 115 | } |
diff --git a/apps/plugins/alpine_cdc.c b/apps/plugins/alpine_cdc.c index 653c968ffa..28bb8d8b7f 100644 --- a/apps/plugins/alpine_cdc.c +++ b/apps/plugins/alpine_cdc.c | |||
@@ -997,8 +997,8 @@ void set_play(void) | |||
997 | } | 997 | } |
998 | else | 998 | else |
999 | { | 999 | { |
1000 | print_scroll("audio_play(0)"); | 1000 | print_scroll("audio_play(0, 0)"); |
1001 | rb->audio_play(0); | 1001 | rb->audio_play(0, 0); |
1002 | } | 1002 | } |
1003 | } | 1003 | } |
1004 | 1004 | ||
diff --git a/apps/plugins/lib/playback_control.c b/apps/plugins/lib/playback_control.c index 47921e52f2..1be234f70f 100644 --- a/apps/plugins/lib/playback_control.c +++ b/apps/plugins/lib/playback_control.c | |||
@@ -39,6 +39,7 @@ static bool play(void) | |||
39 | { | 39 | { |
40 | rb->playlist_resume_track(rb->global_status->resume_index, | 40 | rb->playlist_resume_track(rb->global_status->resume_index, |
41 | rb->global_status->resume_crc32, | 41 | rb->global_status->resume_crc32, |
42 | rb->global_status->resume_elapsed, | ||
42 | rb->global_status->resume_offset); | 43 | rb->global_status->resume_offset); |
43 | } | 44 | } |
44 | } | 45 | } |
diff --git a/apps/plugins/lrcplayer.c b/apps/plugins/lrcplayer.c index 6e0394fa51..392e78e77f 100644 --- a/apps/plugins/lrcplayer.c +++ b/apps/plugins/lrcplayer.c | |||
@@ -2684,6 +2684,7 @@ static int handle_button(void) | |||
2684 | { | 2684 | { |
2685 | rb->playlist_resume_track(rb->global_status->resume_index, | 2685 | rb->playlist_resume_track(rb->global_status->resume_index, |
2686 | rb->global_status->resume_crc32, | 2686 | rb->global_status->resume_crc32, |
2687 | rb->global_status->resume_elapsed, | ||
2687 | rb->global_status->resume_offset); | 2688 | rb->global_status->resume_offset); |
2688 | } | 2689 | } |
2689 | } | 2690 | } |
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c index 51fe5ebfc5..bb7cec888f 100644 --- a/apps/plugins/pictureflow/pictureflow.c +++ b/apps/plugins/pictureflow/pictureflow.c | |||
@@ -2580,7 +2580,7 @@ play: | |||
2580 | * if shuffle, we can't predict the playing track easily, and for either | 2580 | * if shuffle, we can't predict the playing track easily, and for either |
2581 | * case the track list doesn't get auto scrolled*/ | 2581 | * case the track list doesn't get auto scrolled*/ |
2582 | if(!append) | 2582 | if(!append) |
2583 | rb->playlist_start(position, 0); | 2583 | rb->playlist_start(position, 0, 0); |
2584 | old_playlist = center_slide.slide_index; | 2584 | old_playlist = center_slide.slide_index; |
2585 | old_shuffle = shuffle; | 2585 | old_shuffle = shuffle; |
2586 | } | 2586 | } |
diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c index 7f6018df4e..0b3532dde0 100644 --- a/apps/plugins/random_folder_advance_config.c +++ b/apps/plugins/random_folder_advance_config.c | |||
@@ -541,7 +541,7 @@ static int start_shuffled_play(void) | |||
541 | } | 541 | } |
542 | } | 542 | } |
543 | rb->splash(HZ, "Done"); | 543 | rb->splash(HZ, "Done"); |
544 | rb->playlist_start(0,0); | 544 | rb->playlist_start(0, 0, 0); |
545 | return 1; | 545 | return 1; |
546 | } | 546 | } |
547 | 547 | ||
diff --git a/apps/root_menu.c b/apps/root_menu.c index 259d9bf69c..09c7efad9d 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c | |||
@@ -306,6 +306,7 @@ static int wpsscrn(void* param) | |||
306 | { | 306 | { |
307 | playlist_resume_track(global_status.resume_index, | 307 | playlist_resume_track(global_status.resume_index, |
308 | global_status.resume_crc32, | 308 | global_status.resume_crc32, |
309 | global_status.resume_elapsed, | ||
309 | global_status.resume_offset); | 310 | global_status.resume_offset); |
310 | ret_val = gui_wps_show(); | 311 | ret_val = gui_wps_show(); |
311 | } | 312 | } |
diff --git a/apps/settings.c b/apps/settings.c index 13dcb5cca9..58d58788be 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -738,12 +738,17 @@ void settings_apply_play_freq(int value, bool playback) | |||
738 | bool changed = value != prev_setting; | 738 | bool changed = value != prev_setting; |
739 | prev_setting = value; | 739 | prev_setting = value; |
740 | 740 | ||
741 | long offset = 0; | 741 | unsigned long elapsed = 0; |
742 | unsigned long offset = 0; | ||
742 | bool playing = changed && !playback && | 743 | bool playing = changed && !playback && |
743 | audio_status() == AUDIO_STATUS_PLAY; | 744 | audio_status() == AUDIO_STATUS_PLAY; |
744 | 745 | ||
745 | if (playing) | 746 | if (playing) |
746 | offset = audio_current_track()->offset; | 747 | { |
748 | struct mp3entry *id3 = audio_current_track(); | ||
749 | elapsed = id3->elapsed; | ||
750 | offset = id3->offset; | ||
751 | } | ||
747 | 752 | ||
748 | if (changed && !playback) | 753 | if (changed && !playback) |
749 | audio_hard_stop(); | 754 | audio_hard_stop(); |
@@ -752,7 +757,7 @@ void settings_apply_play_freq(int value, bool playback) | |||
752 | mixer_set_frequency(play_sampr[value]); | 757 | mixer_set_frequency(play_sampr[value]); |
753 | 758 | ||
754 | if (playing) | 759 | if (playing) |
755 | audio_play(offset); | 760 | audio_play(elapsed, offset); |
756 | } | 761 | } |
757 | #endif /* HAVE_PLAY_FREQ */ | 762 | #endif /* HAVE_PLAY_FREQ */ |
758 | 763 | ||
diff --git a/apps/settings.h b/apps/settings.h index 5b876d3e67..60658f6857 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -266,6 +266,7 @@ struct system_status | |||
266 | { | 266 | { |
267 | int resume_index; /* index in playlist (-1 for no active resume) */ | 267 | int resume_index; /* index in playlist (-1 for no active resume) */ |
268 | uint32_t resume_crc32; /* crc32 of the name of the file */ | 268 | uint32_t resume_crc32; /* crc32 of the name of the file */ |
269 | uint32_t resume_elapsed; /* elapsed time in last file */ | ||
269 | uint32_t resume_offset; /* byte offset in mp3 file */ | 270 | uint32_t resume_offset; /* byte offset in mp3 file */ |
270 | int runtime; /* current runtime since last charge */ | 271 | int runtime; /* current runtime since last charge */ |
271 | int topruntime; /* top known runtime */ | 272 | int topruntime; /* top known runtime */ |
@@ -282,6 +283,7 @@ struct system_status | |||
282 | #ifdef HAVE_LCD_BITMAP | 283 | #ifdef HAVE_LCD_BITMAP |
283 | int font_id[NB_SCREENS]; /* font id of the settings font for each screen */ | 284 | int font_id[NB_SCREENS]; /* font id of the settings font for each screen */ |
284 | #endif | 285 | #endif |
286 | |||
285 | }; | 287 | }; |
286 | 288 | ||
287 | struct user_settings | 289 | struct user_settings |
diff --git a/apps/settings_list.c b/apps/settings_list.c index 39258dff8f..1ef9c62bf0 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c | |||
@@ -818,6 +818,7 @@ const struct settings_list settings[] = { | |||
818 | OFFON_SETTING(0, playlist_shuffle, LANG_SHUFFLE, false, "shuffle", NULL), | 818 | OFFON_SETTING(0, playlist_shuffle, LANG_SHUFFLE, false, "shuffle", NULL), |
819 | SYSTEM_SETTING(NVRAM(4), resume_index, -1), | 819 | SYSTEM_SETTING(NVRAM(4), resume_index, -1), |
820 | SYSTEM_SETTING(NVRAM(4), resume_crc32, -1), | 820 | SYSTEM_SETTING(NVRAM(4), resume_crc32, -1), |
821 | SYSTEM_SETTING(NVRAM(4), resume_elapsed, -1), | ||
821 | SYSTEM_SETTING(NVRAM(4), resume_offset, -1), | 822 | SYSTEM_SETTING(NVRAM(4), resume_offset, -1), |
822 | CHOICE_SETTING(0, repeat_mode, LANG_REPEAT, REPEAT_OFF, "repeat", | 823 | CHOICE_SETTING(0, repeat_mode, LANG_REPEAT, REPEAT_OFF, "repeat", |
823 | "off,all,one,shuffle" | 824 | "off,all,one,shuffle" |
diff --git a/apps/settings_list.h b/apps/settings_list.h index 66b20ca6ca..2e63220da1 100644 --- a/apps/settings_list.h +++ b/apps/settings_list.h | |||
@@ -142,7 +142,7 @@ struct custom_setting { | |||
142 | 142 | ||
143 | #define F_NVRAM_BYTES_MASK 0xE0000 /*0-4 bytes can be stored */ | 143 | #define F_NVRAM_BYTES_MASK 0xE0000 /*0-4 bytes can be stored */ |
144 | #define F_NVRAM_MASK_SHIFT 17 | 144 | #define F_NVRAM_MASK_SHIFT 17 |
145 | #define NVRAM_CONFIG_VERSION 7 | 145 | #define NVRAM_CONFIG_VERSION 8 |
146 | /* Above define should be bumped if | 146 | /* Above define should be bumped if |
147 | - a new NVRAM setting is added between 2 other NVRAM settings | 147 | - a new NVRAM setting is added between 2 other NVRAM settings |
148 | - number of bytes for a NVRAM setting is changed | 148 | - number of bytes for a NVRAM setting is changed |
diff --git a/apps/tagcache.c b/apps/tagcache.c index 07d8d1d7a2..3ce0247188 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c | |||
@@ -130,7 +130,7 @@ static long tempbuf_pos; | |||
130 | static const char *tags_str[] = { "artist", "album", "genre", "title", | 130 | static const char *tags_str[] = { "artist", "album", "genre", "title", |
131 | "filename", "composer", "comment", "albumartist", "grouping", "year", | 131 | "filename", "composer", "comment", "albumartist", "grouping", "year", |
132 | "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", | 132 | "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", |
133 | "playtime", "lastplayed", "commitid", "mtime", "lastoffset" }; | 133 | "playtime", "lastplayed", "commitid", "mtime", "lastelapsed", "lastoffset" }; |
134 | 134 | ||
135 | /* Status information of the tagcache. */ | 135 | /* Status information of the tagcache. */ |
136 | static struct tagcache_stat tc_stat; | 136 | static struct tagcache_stat tc_stat; |
@@ -196,7 +196,7 @@ static const char * const tagfile_entry_ec = "ll"; | |||
196 | /** | 196 | /** |
197 | Note: This should be (1 + TAG_COUNT) amount of l's. | 197 | Note: This should be (1 + TAG_COUNT) amount of l's. |
198 | */ | 198 | */ |
199 | static const char * const index_entry_ec = "llllllllllllllllllllll"; | 199 | static const char * const index_entry_ec = "lllllllllllllllllllllll"; |
200 | 200 | ||
201 | static const char * const tagcache_header_ec = "lll"; | 201 | static const char * const tagcache_header_ec = "lll"; |
202 | static const char * const master_header_ec = "llllll"; | 202 | static const char * const master_header_ec = "llllll"; |
@@ -1752,6 +1752,10 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename) | |||
1752 | #if CONFIG_CODEC == SWCODEC | 1752 | #if CONFIG_CODEC == SWCODEC |
1753 | if (global_settings.autoresume_enable) | 1753 | if (global_settings.autoresume_enable) |
1754 | { | 1754 | { |
1755 | id3->elapsed = get_tag_numeric(entry, tag_lastelapsed, idx_id); | ||
1756 | logf("tagcache_fill_tags: Set elapsed for %s to %lX\n", | ||
1757 | id3->title, id3->elapsed); | ||
1758 | |||
1755 | id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id); | 1759 | id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id); |
1756 | logf("tagcache_fill_tags: Set offset for %s to %lX\n", | 1760 | logf("tagcache_fill_tags: Set offset for %s to %lX\n", |
1757 | id3->title, id3->offset); | 1761 | id3->title, id3->offset); |
@@ -2348,6 +2352,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) | |||
2348 | tmpdb_copy_tag(tag_playtime); | 2352 | tmpdb_copy_tag(tag_playtime); |
2349 | tmpdb_copy_tag(tag_lastplayed); | 2353 | tmpdb_copy_tag(tag_lastplayed); |
2350 | tmpdb_copy_tag(tag_commitid); | 2354 | tmpdb_copy_tag(tag_commitid); |
2355 | tmpdb_copy_tag(tag_lastelapsed); | ||
2351 | tmpdb_copy_tag(tag_lastoffset); | 2356 | tmpdb_copy_tag(tag_lastoffset); |
2352 | 2357 | ||
2353 | /* Avoid processing this entry again. */ | 2358 | /* Avoid processing this entry again. */ |
@@ -3419,7 +3424,8 @@ static int parse_changelog_line(int line_n, char *buf, void *parameters) | |||
3419 | int idx_id; | 3424 | int idx_id; |
3420 | long masterfd = (long)parameters; | 3425 | long masterfd = (long)parameters; |
3421 | const int import_tags[] = { tag_playcount, tag_rating, tag_playtime, | 3426 | const int import_tags[] = { tag_playcount, tag_rating, tag_playtime, |
3422 | tag_lastplayed, tag_commitid, tag_lastoffset }; | 3427 | tag_lastplayed, tag_commitid, tag_lastelapsed, |
3428 | tag_lastoffset }; | ||
3423 | int i; | 3429 | int i; |
3424 | (void)line_n; | 3430 | (void)line_n; |
3425 | 3431 | ||
diff --git a/apps/tagcache.h b/apps/tagcache.h index dbe1c92d39..e358cc26e0 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h | |||
@@ -33,7 +33,8 @@ | |||
33 | enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, | 33 | enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, |
34 | tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, | 34 | tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, |
35 | tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, | 35 | tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, |
36 | tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastoffset, | 36 | tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastelapsed, |
37 | tag_lastoffset, | ||
37 | /* Real tags end here, count them. */ | 38 | /* Real tags end here, count them. */ |
38 | TAG_COUNT, | 39 | TAG_COUNT, |
39 | /* Virtual tags */ | 40 | /* Virtual tags */ |
@@ -51,7 +52,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, | |||
51 | #define IDX_BUF_DEPTH 64 | 52 | #define IDX_BUF_DEPTH 64 |
52 | 53 | ||
53 | /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ | 54 | /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ |
54 | #define TAGCACHE_MAGIC 0x5443480e | 55 | #define TAGCACHE_MAGIC 0x5443480f |
55 | 56 | ||
56 | /* Dump store/restore header version 'TCSxx'. */ | 57 | /* Dump store/restore header version 'TCSxx'. */ |
57 | #define TAGCACHE_STATEFILE_MAGIC 0x54435301 | 58 | #define TAGCACHE_STATEFILE_MAGIC 0x54435301 |
@@ -107,10 +108,11 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, | |||
107 | (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \ | 108 | (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \ |
108 | (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \ | 109 | (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \ |
109 | (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \ | 110 | (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \ |
110 | (1LU << tag_lastoffset) | (1LU << tag_virt_basename) | \ | 111 | (1LU << tag_lastelapsed) | (1LU << tag_lastoffset) | \ |
111 | (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \ | 112 | (1LU << tag_virt_basename) | (1LU << tag_virt_length_min) | \ |
112 | (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \ | 113 | (1LU << tag_virt_length_sec) | (1LU << tag_virt_playtime_min) | \ |
113 | (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore)) | 114 | (1LU << tag_virt_playtime_sec) | (1LU << tag_virt_entryage) | \ |
115 | (1LU << tag_virt_autoscore)) | ||
114 | 116 | ||
115 | #define TAGCACHE_IS_NUMERIC(tag) (BIT_N(tag) & TAGCACHE_NUMERIC_TAGS) | 117 | #define TAGCACHE_IS_NUMERIC(tag) (BIT_N(tag) & TAGCACHE_NUMERIC_TAGS) |
116 | 118 | ||
diff --git a/apps/tagtree.c b/apps/tagtree.c index 9eef38b5e6..ff364ec5e4 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c | |||
@@ -330,6 +330,7 @@ static int get_tag(int *tag) | |||
330 | {"playcount", tag_playcount}, | 330 | {"playcount", tag_playcount}, |
331 | {"rating", tag_rating}, | 331 | {"rating", tag_rating}, |
332 | {"lastplayed", tag_lastplayed}, | 332 | {"lastplayed", tag_lastplayed}, |
333 | {"lastelapsed", tag_lastelapsed}, | ||
333 | {"lastoffset", tag_lastoffset}, | 334 | {"lastoffset", tag_lastoffset}, |
334 | {"commitid", tag_commitid}, | 335 | {"commitid", tag_commitid}, |
335 | {"entryage", tag_virt_entryage}, | 336 | {"entryage", tag_virt_entryage}, |
@@ -841,8 +842,16 @@ static void tagtree_buffer_event(void *data) | |||
841 | #if CONFIG_CODEC == SWCODEC | 842 | #if CONFIG_CODEC == SWCODEC |
842 | if (autoresume) | 843 | if (autoresume) |
843 | { | 844 | { |
844 | /* Load current file resume offset if not already defined (by | 845 | /* Load current file resume info if not already defined (by |
845 | another resume mechanism) */ | 846 | another resume mechanism) */ |
847 | if (id3->elapsed == 0) | ||
848 | { | ||
849 | id3->elapsed = tagcache_get_numeric(&tcs, tag_lastelapsed); | ||
850 | |||
851 | logf("tagtree_buffer_event: Set elapsed for %s to %lX\n", | ||
852 | str_or_empty(id3->title), id3->elapsed); | ||
853 | } | ||
854 | |||
846 | if (id3->offset == 0) | 855 | if (id3->offset == 0) |
847 | { | 856 | { |
848 | id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset); | 857 | id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset); |
@@ -940,12 +949,13 @@ static void tagtree_track_finish_event(void *data) | |||
940 | #if CONFIG_CODEC == SWCODEC | 949 | #if CONFIG_CODEC == SWCODEC |
941 | if (autoresume) | 950 | if (autoresume) |
942 | { | 951 | { |
952 | unsigned long elapsed = auto_skip ? 0 : id3->elapsed; | ||
943 | unsigned long offset = auto_skip ? 0 : id3->offset; | 953 | unsigned long offset = auto_skip ? 0 : id3->offset; |
944 | 954 | tagcache_update_numeric(tagcache_idx, tag_lastelapsed, elapsed); | |
945 | tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); | 955 | tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); |
946 | 956 | ||
947 | logf("tagtree_track_finish_event: Save offset for %s: %lX", | 957 | logf("tagtree_track_finish_event: Save resume for %s: %lX %lX", |
948 | str_or_empty(id3->title), offset); | 958 | str_or_empty(id3->title), elapsed, offset); |
949 | } | 959 | } |
950 | #endif | 960 | #endif |
951 | } | 961 | } |
@@ -2034,7 +2044,7 @@ static int tagtree_play_folder(struct tree_context* c) | |||
2034 | c->selected_item = 0; | 2044 | c->selected_item = 0; |
2035 | gui_synclist_select_item(&tree_lists, c->selected_item); | 2045 | gui_synclist_select_item(&tree_lists, c->selected_item); |
2036 | 2046 | ||
2037 | playlist_start(c->selected_item,0); | 2047 | playlist_start(c->selected_item, 0, 0); |
2038 | playlist_get_current()->num_inserted_tracks = 0; /* make warn on playlist erase work */ | 2048 | playlist_get_current()->num_inserted_tracks = 0; /* make warn on playlist erase work */ |
2039 | return 0; | 2049 | return 0; |
2040 | } | 2050 | } |
diff --git a/apps/tree.c b/apps/tree.c index cc080ac7fa..f72774fe1e 100644 --- a/apps/tree.c +++ b/apps/tree.c | |||
@@ -1052,8 +1052,8 @@ void tree_mem_init(void) | |||
1052 | tree_get_filetypes(&filetypes, &filetypes_count); | 1052 | tree_get_filetypes(&filetypes, &filetypes_count); |
1053 | } | 1053 | } |
1054 | 1054 | ||
1055 | bool bookmark_play(char *resume_file, int index, int offset, int seed, | 1055 | bool bookmark_play(char *resume_file, int index, unsigned long elapsed, |
1056 | char *filename) | 1056 | unsigned long offset, int seed, char *filename) |
1057 | { | 1057 | { |
1058 | int i; | 1058 | int i; |
1059 | char* suffix = strrchr(resume_file, '.'); | 1059 | char* suffix = strrchr(resume_file, '.'); |
@@ -1082,7 +1082,7 @@ bool bookmark_play(char *resume_file, int index, int offset, int seed, | |||
1082 | { | 1082 | { |
1083 | if (global_settings.playlist_shuffle) | 1083 | if (global_settings.playlist_shuffle) |
1084 | playlist_shuffle(seed, -1); | 1084 | playlist_shuffle(seed, -1); |
1085 | playlist_start(index,offset); | 1085 | playlist_start(index, elapsed, offset); |
1086 | started = true; | 1086 | started = true; |
1087 | } | 1087 | } |
1088 | *slash='/'; | 1088 | *slash='/'; |
@@ -1133,7 +1133,7 @@ bool bookmark_play(char *resume_file, int index, int offset, int seed, | |||
1133 | else | 1133 | else |
1134 | return false; | 1134 | return false; |
1135 | } | 1135 | } |
1136 | playlist_start(index,offset); | 1136 | playlist_start(index, elapsed, offset); |
1137 | started = true; | 1137 | started = true; |
1138 | } | 1138 | } |
1139 | } | 1139 | } |
diff --git a/apps/tree.h b/apps/tree.h index 70494f8a88..1601447b58 100644 --- a/apps/tree.h +++ b/apps/tree.h | |||
@@ -139,8 +139,8 @@ struct tree_context* tree_get_context(void); | |||
139 | void tree_flush(void); | 139 | void tree_flush(void); |
140 | void tree_restore(void); | 140 | void tree_restore(void); |
141 | 141 | ||
142 | bool bookmark_play(char* resume_file, int index, int offset, int seed, | 142 | bool bookmark_play(char* resume_file, int index, unsigned long elapsed, |
143 | char *filename); | 143 | unsigned long offset, int seed, char *filename); |
144 | 144 | ||
145 | extern struct gui_synclist tree_lists; | 145 | extern struct gui_synclist tree_lists; |
146 | #endif | 146 | #endif |