diff options
65 files changed, 729 insertions, 302 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 |
diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 57f7981b34..08a88d6325 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h | |||
@@ -49,7 +49,7 @@ | |||
49 | 49 | ||
50 | 50 | ||
51 | void audio_init(void) INIT_ATTR; | 51 | void audio_init(void) INIT_ATTR; |
52 | void audio_play(long offset); | 52 | void audio_play(unsigned long elapsed, unsigned long offset); |
53 | void audio_stop(void); | 53 | void audio_stop(void); |
54 | /* Stops audio from serving playback and frees resources*/ | 54 | /* Stops audio from serving playback and frees resources*/ |
55 | void audio_hard_stop(void); | 55 | void audio_hard_stop(void); |
diff --git a/lib/rbcodec/codecs/a52.c b/lib/rbcodec/codecs/a52.c index 77caaf87c1..da670308b8 100644 --- a/lib/rbcodec/codecs/a52.c +++ b/lib/rbcodec/codecs/a52.c | |||
@@ -150,19 +150,28 @@ enum codec_status codec_run(void) | |||
150 | 150 | ||
151 | samplesdone = 0; | 151 | samplesdone = 0; |
152 | 152 | ||
153 | /* The main decoding loop */ | ||
154 | if (ci->id3->offset) { | 153 | if (ci->id3->offset) { |
155 | if (ci->seek_buffer(ci->id3->offset)) { | 154 | sample_loc = (ci->id3->offset / ci->id3->bytesperframe) * |
156 | samplesdone = (ci->id3->offset / ci->id3->bytesperframe) * | 155 | A52_SAMPLESPERFRAME; |
157 | A52_SAMPLESPERFRAME; | 156 | param = ci->id3->offset; |
158 | ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000)); | 157 | } |
159 | } | 158 | else if (ci->id3->elapsed) { |
159 | sample_loc = ci->id3->elapsed/1000 * ci->id3->frequency; | ||
160 | param = sample_loc/A52_SAMPLESPERFRAME*ci->id3->bytesperframe; | ||
160 | } | 161 | } |
161 | else { | 162 | else { |
162 | ci->seek_buffer(ci->id3->first_frame_offset); | 163 | sample_loc = 0; |
163 | ci->set_elapsed(0); | 164 | param = ci->id3->first_frame_offset; |
165 | } | ||
166 | |||
167 | if (ci->seek_buffer(param)) { | ||
168 | samplesdone = sample_loc; | ||
164 | } | 169 | } |
165 | 170 | ||
171 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); | ||
172 | |||
173 | /* The main decoding loop */ | ||
174 | |||
166 | while (1) { | 175 | while (1) { |
167 | enum codec_command_action action = ci->get_command(¶m); | 176 | enum codec_command_action action = ci->get_command(¶m); |
168 | 177 | ||
@@ -172,7 +181,8 @@ enum codec_status codec_run(void) | |||
172 | if (action == CODEC_ACTION_SEEK_TIME) { | 181 | if (action == CODEC_ACTION_SEEK_TIME) { |
173 | sample_loc = param/1000 * ci->id3->frequency; | 182 | sample_loc = param/1000 * ci->id3->frequency; |
174 | 183 | ||
175 | if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) { | 184 | if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)* |
185 | ci->id3->bytesperframe)) { | ||
176 | samplesdone = sample_loc; | 186 | samplesdone = sample_loc; |
177 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); | 187 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); |
178 | } | 188 | } |
diff --git a/lib/rbcodec/codecs/a52_rm.c b/lib/rbcodec/codecs/a52_rm.c index 42868437d8..3f07a43ce9 100644 --- a/lib/rbcodec/codecs/a52_rm.c +++ b/lib/rbcodec/codecs/a52_rm.c | |||
@@ -148,13 +148,15 @@ enum codec_status codec_run(void) | |||
148 | int consumed, packet_offset; | 148 | int consumed, packet_offset; |
149 | int playback_on = -1; | 149 | int playback_on = -1; |
150 | size_t resume_offset; | 150 | size_t resume_offset; |
151 | enum codec_command_action action; | ||
151 | intptr_t param; | 152 | intptr_t param; |
152 | enum codec_command_action action = CODEC_ACTION_NULL; | ||
153 | 153 | ||
154 | if (codec_init()) { | 154 | if (codec_init()) { |
155 | return CODEC_ERROR; | 155 | return CODEC_ERROR; |
156 | } | 156 | } |
157 | 157 | ||
158 | action = CODEC_ACTION_NULL; | ||
159 | param = ci->id3->elapsed; | ||
158 | resume_offset = ci->id3->offset; | 160 | resume_offset = ci->id3->offset; |
159 | 161 | ||
160 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); | 162 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); |
@@ -171,11 +173,14 @@ enum codec_status codec_run(void) | |||
171 | samplesdone = 0; | 173 | samplesdone = 0; |
172 | 174 | ||
173 | /* check for a mid-track resume and force a seek time accordingly */ | 175 | /* check for a mid-track resume and force a seek time accordingly */ |
174 | if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { | 176 | if (resume_offset) { |
175 | resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; | 177 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
176 | /* put number of subpackets to skip in resume_offset */ | 178 | /* put number of subpackets to skip in resume_offset */ |
177 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); | 179 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); |
178 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); | 180 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); |
181 | } | ||
182 | |||
183 | if (param > 0) { | ||
179 | action = CODEC_ACTION_SEEK_TIME; | 184 | action = CODEC_ACTION_SEEK_TIME; |
180 | } | 185 | } |
181 | else { | 186 | else { |
diff --git a/lib/rbcodec/codecs/aac.c b/lib/rbcodec/codecs/aac.c index c9cf737b48..015e332be2 100644 --- a/lib/rbcodec/codecs/aac.c +++ b/lib/rbcodec/codecs/aac.c | |||
@@ -72,6 +72,7 @@ enum codec_status codec_run(void) | |||
72 | uint32_t sbr_fac = 1; | 72 | uint32_t sbr_fac = 1; |
73 | unsigned char c = 0; | 73 | unsigned char c = 0; |
74 | void *ret; | 74 | void *ret; |
75 | enum codec_command_action action; | ||
75 | intptr_t param; | 76 | intptr_t param; |
76 | bool empty_first_frame = false; | 77 | bool empty_first_frame = false; |
77 | 78 | ||
@@ -82,6 +83,8 @@ enum codec_status codec_run(void) | |||
82 | return CODEC_ERROR; | 83 | return CODEC_ERROR; |
83 | } | 84 | } |
84 | 85 | ||
86 | action = CODEC_ACTION_NULL; | ||
87 | param = ci->id3->elapsed; | ||
85 | file_offset = ci->id3->offset; | 88 | file_offset = ci->id3->offset; |
86 | 89 | ||
87 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); | 90 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); |
@@ -138,11 +141,16 @@ enum codec_status codec_run(void) | |||
138 | sound_samples_done = 0; | 141 | sound_samples_done = 0; |
139 | } | 142 | } |
140 | NeAACDecPostSeekReset(decoder, i); | 143 | NeAACDecPostSeekReset(decoder, i); |
144 | elapsed_time = (sound_samples_done * 10) / | ||
145 | (ci->id3->frequency / 100); | ||
146 | } else if (param) { | ||
147 | elapsed_time = param; | ||
148 | action = CODEC_ACTION_SEEK_TIME; | ||
141 | } else { | 149 | } else { |
150 | elapsed_time = 0; | ||
142 | sound_samples_done = 0; | 151 | sound_samples_done = 0; |
143 | } | 152 | } |
144 | 153 | ||
145 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); | ||
146 | ci->set_elapsed(elapsed_time); | 154 | ci->set_elapsed(elapsed_time); |
147 | 155 | ||
148 | if (i == 0) | 156 | if (i == 0) |
@@ -152,7 +160,8 @@ enum codec_status codec_run(void) | |||
152 | 160 | ||
153 | /* The main decoding loop */ | 161 | /* The main decoding loop */ |
154 | while (i < demux_res.num_sample_byte_sizes) { | 162 | while (i < demux_res.num_sample_byte_sizes) { |
155 | enum codec_command_action action = ci->get_command(¶m); | 163 | if (action == CODEC_ACTION_NULL) |
164 | action = ci->get_command(¶m); | ||
156 | 165 | ||
157 | if (action == CODEC_ACTION_HALT) | 166 | if (action == CODEC_ACTION_HALT) |
158 | break; | 167 | break; |
@@ -180,6 +189,8 @@ enum codec_status codec_run(void) | |||
180 | ci->seek_complete(); | 189 | ci->seek_complete(); |
181 | } | 190 | } |
182 | 191 | ||
192 | action = CODEC_ACTION_NULL; | ||
193 | |||
183 | /* There can be gaps between chunks, so skip ahead if needed. It | 194 | /* There can be gaps between chunks, so skip ahead if needed. It |
184 | * doesn't seem to happen much, but it probably means that a | 195 | * doesn't seem to happen much, but it probably means that a |
185 | * "proper" file can have chunks out of order. Why one would want | 196 | * "proper" file can have chunks out of order. Why one would want |
diff --git a/lib/rbcodec/codecs/aiff.c b/lib/rbcodec/codecs/aiff.c index 3bedfa5760..9fee781c03 100644 --- a/lib/rbcodec/codecs/aiff.c +++ b/lib/rbcodec/codecs/aiff.c | |||
@@ -99,6 +99,7 @@ enum codec_status codec_run(void) | |||
99 | codec_set_replaygain(ci->id3); | 99 | codec_set_replaygain(ci->id3); |
100 | 100 | ||
101 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 101 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ |
102 | param = ci->id3->elapsed; | ||
102 | bytesdone = ci->id3->offset; | 103 | bytesdone = ci->id3->offset; |
103 | 104 | ||
104 | /* assume the AIFF header is less than 1024 bytes */ | 105 | /* assume the AIFF header is less than 1024 bytes */ |
@@ -270,10 +271,20 @@ enum codec_status codec_run(void) | |||
270 | ci->advance_buffer(firstblockposn); | 271 | ci->advance_buffer(firstblockposn); |
271 | 272 | ||
272 | /* make sure we're at the correct offset */ | 273 | /* make sure we're at the correct offset */ |
273 | if (bytesdone > (uint32_t) firstblockposn) { | 274 | if (bytesdone > (uint32_t) firstblockposn || param) { |
275 | uint32_t seek_val; | ||
276 | int seek_mode; | ||
277 | |||
278 | if (bytesdone) { | ||
279 | seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); | ||
280 | seek_mode = PCM_SEEK_POS; | ||
281 | } else { | ||
282 | seek_val = param; | ||
283 | seek_mode = PCM_SEEK_TIME; | ||
284 | } | ||
285 | |||
274 | /* Round down to previous block */ | 286 | /* Round down to previous block */ |
275 | struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, | 287 | struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, NULL); |
276 | PCM_SEEK_POS, NULL); | ||
277 | 288 | ||
278 | if (newpos->pos > format.numbytes) | 289 | if (newpos->pos > format.numbytes) |
279 | return CODEC_OK; | 290 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/alac.c b/lib/rbcodec/codecs/alac.c index 5eb6e001f7..a3a5ad43b8 100644 --- a/lib/rbcodec/codecs/alac.c +++ b/lib/rbcodec/codecs/alac.c | |||
@@ -50,7 +50,7 @@ enum codec_status codec_run(void) | |||
50 | demux_res_t demux_res; | 50 | demux_res_t demux_res; |
51 | stream_t input_stream; | 51 | stream_t input_stream; |
52 | uint32_t samplesdone; | 52 | uint32_t samplesdone; |
53 | uint32_t elapsedtime = 0; | 53 | uint32_t elapsedtime; |
54 | int samplesdecoded; | 54 | int samplesdecoded; |
55 | unsigned int i; | 55 | unsigned int i; |
56 | unsigned char* buffer; | 56 | unsigned char* buffer; |
@@ -71,9 +71,9 @@ enum codec_status codec_run(void) | |||
71 | 71 | ||
72 | stream_create(&input_stream,ci); | 72 | stream_create(&input_stream,ci); |
73 | 73 | ||
74 | /* Read from ci->id3->offset before calling qtmovie_read. */ | 74 | /* Read resume info before calling qtmovie_read. */ |
75 | samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) / | 75 | elapsedtime = ci->id3->elapsed; |
76 | (ci->id3->bitrate*128)); | 76 | samplesdone = ci->id3->offset; |
77 | 77 | ||
78 | /* if qtmovie_read returns successfully, the stream is up to | 78 | /* if qtmovie_read returns successfully, the stream is up to |
79 | * the movie data, which can be used directly by the decoder */ | 79 | * the movie data, which can be used directly by the decoder */ |
@@ -87,16 +87,24 @@ enum codec_status codec_run(void) | |||
87 | 87 | ||
88 | /* Set i for first frame, seek to desired sample position for resuming. */ | 88 | /* Set i for first frame, seek to desired sample position for resuming. */ |
89 | i=0; | 89 | i=0; |
90 | if (samplesdone > 0) { | 90 | |
91 | if (m4a_seek(&demux_res, &input_stream, samplesdone, | 91 | if (elapsedtime || samplesdone) { |
92 | if (samplesdone) { | ||
93 | samplesdone = | ||
94 | (uint32_t)((uint64_t)samplesdone*ci->id3->frequency / | ||
95 | (ci->id3->bitrate*128)); | ||
96 | } | ||
97 | else { | ||
98 | samplesdone = (elapsedtime/10) * (ci->id3->frequency/100); | ||
99 | } | ||
100 | |||
101 | if (!m4a_seek(&demux_res, &input_stream, samplesdone, | ||
92 | &samplesdone, (int*) &i)) { | 102 | &samplesdone, (int*) &i)) { |
93 | elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100); | ||
94 | ci->set_elapsed(elapsedtime); | ||
95 | } else { | ||
96 | samplesdone = 0; | 103 | samplesdone = 0; |
97 | } | 104 | } |
98 | } | 105 | } |
99 | 106 | ||
107 | elapsedtime = (samplesdone*10)/(ci->id3->frequency/100); | ||
100 | ci->set_elapsed(elapsedtime); | 108 | ci->set_elapsed(elapsedtime); |
101 | 109 | ||
102 | /* The main decoding loop */ | 110 | /* The main decoding loop */ |
@@ -106,9 +114,6 @@ enum codec_status codec_run(void) | |||
106 | if (action == CODEC_ACTION_HALT) | 114 | if (action == CODEC_ACTION_HALT) |
107 | break; | 115 | break; |
108 | 116 | ||
109 | /* Request the required number of bytes from the input buffer */ | ||
110 | buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE); | ||
111 | |||
112 | /* Deal with any pending seek requests */ | 117 | /* Deal with any pending seek requests */ |
113 | if (action == CODEC_ACTION_SEEK_TIME) { | 118 | if (action == CODEC_ACTION_SEEK_TIME) { |
114 | if (m4a_seek(&demux_res, &input_stream, | 119 | if (m4a_seek(&demux_res, &input_stream, |
diff --git a/lib/rbcodec/codecs/ape.c b/lib/rbcodec/codecs/ape.c index 577e7b65e2..a6c5254d45 100644 --- a/lib/rbcodec/codecs/ape.c +++ b/lib/rbcodec/codecs/ape.c | |||
@@ -155,6 +155,7 @@ enum codec_status codec_run(void) | |||
155 | int res; | 155 | int res; |
156 | int firstbyte; | 156 | int firstbyte; |
157 | size_t resume_offset; | 157 | size_t resume_offset; |
158 | enum codec_command_action action; | ||
158 | intptr_t param; | 159 | intptr_t param; |
159 | 160 | ||
160 | if (codec_init()) { | 161 | if (codec_init()) { |
@@ -162,8 +163,12 @@ enum codec_status codec_run(void) | |||
162 | return CODEC_ERROR; | 163 | return CODEC_ERROR; |
163 | } | 164 | } |
164 | 165 | ||
166 | action = CODEC_ACTION_NULL; | ||
167 | param = 0; | ||
168 | |||
165 | /* Remember the resume position - when the codec is opened, the | 169 | /* Remember the resume position - when the codec is opened, the |
166 | playback engine will reset it. */ | 170 | playback engine will reset it. */ |
171 | elapsedtime = ci->id3->elapsed; | ||
167 | resume_offset = ci->id3->offset; | 172 | resume_offset = ci->id3->offset; |
168 | 173 | ||
169 | ci->seek_buffer(0); | 174 | ci->seek_buffer(0); |
@@ -213,14 +218,21 @@ enum codec_status codec_run(void) | |||
213 | 218 | ||
214 | ape_resume(&ape_ctx, resume_offset, | 219 | ape_resume(&ape_ctx, resume_offset, |
215 | ¤tframe, &samplesdone, &samplestoskip, &firstbyte); | 220 | ¤tframe, &samplesdone, &samplestoskip, &firstbyte); |
216 | } else { | 221 | elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); |
222 | } | ||
223 | else { | ||
217 | currentframe = 0; | 224 | currentframe = 0; |
218 | samplesdone = 0; | 225 | samplesdone = 0; |
219 | samplestoskip = 0; | 226 | samplestoskip = 0; |
220 | firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ | 227 | firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ |
228 | |||
229 | if (elapsedtime) { | ||
230 | /* Resume by simulated seeking */ | ||
231 | param = elapsedtime; | ||
232 | action = CODEC_ACTION_SEEK_TIME; | ||
233 | } | ||
221 | } | 234 | } |
222 | 235 | ||
223 | elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); | ||
224 | ci->set_elapsed(elapsedtime); | 236 | ci->set_elapsed(elapsedtime); |
225 | 237 | ||
226 | /* Initialise the buffer */ | 238 | /* Initialise the buffer */ |
@@ -247,36 +259,44 @@ frame_start: | |||
247 | /* Decode the frame a chunk at a time */ | 259 | /* Decode the frame a chunk at a time */ |
248 | while (nblocks > 0) | 260 | while (nblocks > 0) |
249 | { | 261 | { |
250 | enum codec_command_action action = ci->get_command(¶m); | 262 | if (action == CODEC_ACTION_NULL) |
263 | action = ci->get_command(¶m); | ||
251 | 264 | ||
252 | if (action == CODEC_ACTION_HALT) | 265 | if (action != CODEC_ACTION_NULL) { |
253 | goto done; | 266 | if (action == CODEC_ACTION_HALT) |
267 | goto done; | ||
254 | 268 | ||
255 | /* Deal with any pending seek requests */ | 269 | /* Deal with any pending seek requests */ |
256 | if (action == CODEC_ACTION_SEEK_TIME) | 270 | if (action == CODEC_ACTION_SEEK_TIME) |
257 | { | ||
258 | if (ape_calc_seekpos(&ape_ctx, | ||
259 | (param/10) * (ci->id3->frequency/100), | ||
260 | ¤tframe, | ||
261 | &newfilepos, | ||
262 | &samplestoskip)) | ||
263 | { | 271 | { |
264 | samplesdone = currentframe * ape_ctx.blocksperframe; | 272 | if (ape_calc_seekpos(&ape_ctx, |
265 | 273 | (param/10) * (ci->id3->frequency/100), | |
266 | /* APE's bytestream is weird... */ | 274 | ¤tframe, |
267 | firstbyte = 3 - (newfilepos & 3); | 275 | &newfilepos, |
268 | newfilepos &= ~3; | 276 | &samplestoskip)) |
269 | 277 | { | |
270 | ci->seek_buffer(newfilepos); | 278 | samplesdone = currentframe * ape_ctx.blocksperframe; |
271 | inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); | 279 | |
280 | /* APE's bytestream is weird... */ | ||
281 | firstbyte = 3 - (newfilepos & 3); | ||
282 | newfilepos &= ~3; | ||
283 | |||
284 | ci->seek_buffer(newfilepos); | ||
285 | inbuffer = ci->request_buffer(&bytesleft, | ||
286 | INPUT_CHUNKSIZE); | ||
287 | |||
288 | elapsedtime = (samplesdone*10)/ | ||
289 | (ape_ctx.samplerate/100); | ||
290 | ci->set_elapsed(elapsedtime); | ||
291 | ci->seek_complete(); | ||
292 | action = CODEC_ACTION_NULL; | ||
293 | goto frame_start; /* Sorry... */ | ||
294 | } | ||
272 | 295 | ||
273 | elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); | ||
274 | ci->set_elapsed(elapsedtime); | ||
275 | ci->seek_complete(); | 296 | ci->seek_complete(); |
276 | goto frame_start; /* Sorry... */ | ||
277 | } | 297 | } |
278 | 298 | ||
279 | ci->seek_complete(); | 299 | action = CODEC_ACTION_NULL; |
280 | } | 300 | } |
281 | 301 | ||
282 | blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); | 302 | blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); |
diff --git a/lib/rbcodec/codecs/asap.c b/lib/rbcodec/codecs/asap.c index 19b39a44c4..2c350ba450 100644 --- a/lib/rbcodec/codecs/asap.c +++ b/lib/rbcodec/codecs/asap.c | |||
@@ -52,6 +52,8 @@ enum codec_status codec_run(void) | |||
52 | return CODEC_ERROR; | 52 | return CODEC_ERROR; |
53 | } | 53 | } |
54 | 54 | ||
55 | param = ci->id3->elapsed; | ||
56 | |||
55 | codec_set_replaygain(ci->id3); | 57 | codec_set_replaygain(ci->id3); |
56 | 58 | ||
57 | int bytes_done =0; | 59 | int bytes_done =0; |
@@ -86,8 +88,6 @@ enum codec_status codec_run(void) | |||
86 | ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); | 88 | ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); |
87 | bytesPerSample = 4; | 89 | bytesPerSample = 4; |
88 | } | 90 | } |
89 | /* reset eleapsed */ | ||
90 | ci->set_elapsed(0); | ||
91 | 91 | ||
92 | song = asap.module_info->default_song; | 92 | song = asap.module_info->default_song; |
93 | duration = asap.module_info->durations[song]; | 93 | duration = asap.module_info->durations[song]; |
@@ -100,6 +100,11 @@ enum codec_status codec_run(void) | |||
100 | ASAP_PlaySong(&asap, song, duration); | 100 | ASAP_PlaySong(&asap, song, duration); |
101 | ASAP_MutePokeyChannels(&asap, 0); | 101 | ASAP_MutePokeyChannels(&asap, 0); |
102 | 102 | ||
103 | if (param) | ||
104 | goto resume_start; | ||
105 | |||
106 | ci->set_elapsed(0); | ||
107 | |||
103 | /* The main decoder loop */ | 108 | /* The main decoder loop */ |
104 | while (1) { | 109 | while (1) { |
105 | enum codec_command_action action = ci->get_command(¶m); | 110 | enum codec_command_action action = ci->get_command(¶m); |
@@ -108,6 +113,7 @@ enum codec_status codec_run(void) | |||
108 | break; | 113 | break; |
109 | 114 | ||
110 | if (action == CODEC_ACTION_SEEK_TIME) { | 115 | if (action == CODEC_ACTION_SEEK_TIME) { |
116 | resume_start: | ||
111 | /* New time is ready in param */ | 117 | /* New time is ready in param */ |
112 | 118 | ||
113 | /* seek to pos */ | 119 | /* seek to pos */ |
diff --git a/lib/rbcodec/codecs/atrac3_oma.c b/lib/rbcodec/codecs/atrac3_oma.c index 50f7c8f163..65d9ed8b38 100644 --- a/lib/rbcodec/codecs/atrac3_oma.c +++ b/lib/rbcodec/codecs/atrac3_oma.c | |||
@@ -50,13 +50,15 @@ enum codec_status codec_run(void) | |||
50 | int elapsed = 0; | 50 | int elapsed = 0; |
51 | size_t resume_offset; | 51 | size_t resume_offset; |
52 | intptr_t param; | 52 | intptr_t param; |
53 | enum codec_command_action action = CODEC_ACTION_NULL; | 53 | enum codec_command_action action; |
54 | 54 | ||
55 | if (codec_init()) { | 55 | if (codec_init()) { |
56 | DEBUGF("codec init failed\n"); | 56 | DEBUGF("codec init failed\n"); |
57 | return CODEC_ERROR; | 57 | return CODEC_ERROR; |
58 | } | 58 | } |
59 | 59 | ||
60 | action = CODEC_ACTION_NULL; | ||
61 | param = ci->id3->elapsed; | ||
60 | resume_offset = ci->id3->offset; | 62 | resume_offset = ci->id3->offset; |
61 | 63 | ||
62 | codec_set_replaygain(ci->id3); | 64 | codec_set_replaygain(ci->id3); |
@@ -79,11 +81,13 @@ enum codec_status codec_run(void) | |||
79 | frame_counter = 0; | 81 | frame_counter = 0; |
80 | 82 | ||
81 | /* check for a mid-track resume and force a seek time accordingly */ | 83 | /* check for a mid-track resume and force a seek time accordingly */ |
82 | if(resume_offset > ci->id3->first_frame_offset) { | 84 | if (resume_offset) { |
83 | resume_offset -= ci->id3->first_frame_offset; | 85 | resume_offset -= MIN(resume_offset, ci->id3->first_frame_offset); |
84 | /* calculate resume_offset in frames */ | 86 | /* calculate resume_offset in frames */ |
85 | resume_offset = (int)resume_offset / FRAMESIZE; | 87 | param = (resume_offset/FRAMESIZE) * ((FRAMESIZE * 8)/BITRATE); |
86 | param = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE); | 88 | } |
89 | |||
90 | if ((unsigned long)param) { | ||
87 | action = CODEC_ACTION_SEEK_TIME; | 91 | action = CODEC_ACTION_SEEK_TIME; |
88 | } | 92 | } |
89 | else { | 93 | else { |
@@ -100,11 +104,9 @@ enum codec_status codec_run(void) | |||
100 | if (action == CODEC_ACTION_HALT) | 104 | if (action == CODEC_ACTION_HALT) |
101 | break; | 105 | break; |
102 | 106 | ||
103 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); | ||
104 | |||
105 | if (action == CODEC_ACTION_SEEK_TIME) { | 107 | if (action == CODEC_ACTION_SEEK_TIME) { |
106 | /* Do not allow seeking beyond the file's length */ | 108 | /* Do not allow seeking beyond the file's length */ |
107 | if ((unsigned) param > ci->id3->length) { | 109 | if ((unsigned long) param > ci->id3->length) { |
108 | ci->set_elapsed(ci->id3->length); | 110 | ci->set_elapsed(ci->id3->length); |
109 | ci->seek_complete(); | 111 | ci->seek_complete(); |
110 | break; | 112 | break; |
@@ -123,7 +125,6 @@ enum codec_status codec_run(void) | |||
123 | seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE); | 125 | seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE); |
124 | frame_counter = seek_frame_offset; | 126 | frame_counter = seek_frame_offset; |
125 | ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE); | 127 | ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE); |
126 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); | ||
127 | elapsed = param; | 128 | elapsed = param; |
128 | ci->set_elapsed(elapsed); | 129 | ci->set_elapsed(elapsed); |
129 | ci->seek_complete(); | 130 | ci->seek_complete(); |
@@ -131,6 +132,8 @@ enum codec_status codec_run(void) | |||
131 | 132 | ||
132 | action = CODEC_ACTION_NULL; | 133 | action = CODEC_ACTION_NULL; |
133 | 134 | ||
135 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); | ||
136 | |||
134 | res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE); | 137 | res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE); |
135 | 138 | ||
136 | if(res != (int)FRAMESIZE) { | 139 | if(res != (int)FRAMESIZE) { |
diff --git a/lib/rbcodec/codecs/atrac3_rm.c b/lib/rbcodec/codecs/atrac3_rm.c index 997507425e..4b528c0a8d 100644 --- a/lib/rbcodec/codecs/atrac3_rm.c +++ b/lib/rbcodec/codecs/atrac3_rm.c | |||
@@ -57,17 +57,19 @@ enum codec_status codec_run(void) | |||
57 | uint8_t *bit_buffer; | 57 | uint8_t *bit_buffer; |
58 | uint16_t fs,sps,h; | 58 | uint16_t fs,sps,h; |
59 | uint32_t packet_count; | 59 | uint32_t packet_count; |
60 | int scrambling_unit_size, num_units, elapsed = 0; | 60 | int scrambling_unit_size, num_units, elapsed; |
61 | int playback_on = -1; | 61 | int playback_on = -1; |
62 | size_t resume_offset; | 62 | size_t resume_offset; |
63 | intptr_t param; | 63 | intptr_t param; |
64 | enum codec_command_action action = CODEC_ACTION_NULL; | 64 | enum codec_command_action action; |
65 | 65 | ||
66 | if (codec_init()) { | 66 | if (codec_init()) { |
67 | DEBUGF("codec init failed\n"); | 67 | DEBUGF("codec init failed\n"); |
68 | return CODEC_ERROR; | 68 | return CODEC_ERROR; |
69 | } | 69 | } |
70 | 70 | ||
71 | action = CODEC_ACTION_NULL; | ||
72 | elapsed = ci->id3->elapsed; | ||
71 | resume_offset = ci->id3->offset; | 73 | resume_offset = ci->id3->offset; |
72 | 74 | ||
73 | codec_set_replaygain(ci->id3); | 75 | codec_set_replaygain(ci->id3); |
@@ -98,15 +100,20 @@ enum codec_status codec_run(void) | |||
98 | } | 100 | } |
99 | 101 | ||
100 | /* check for a mid-track resume and force a seek time accordingly */ | 102 | /* check for a mid-track resume and force a seek time accordingly */ |
101 | if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { | 103 | if(resume_offset) { |
102 | resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; | 104 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
103 | num_units = (int)resume_offset / scrambling_unit_size; | 105 | num_units = (int)resume_offset / scrambling_unit_size; |
104 | /* put number of subpackets to skip in resume_offset */ | 106 | /* put number of subpackets to skip in resume_offset */ |
105 | resume_offset /= (sps + PACKET_HEADER_SIZE); | 107 | resume_offset /= (sps + PACKET_HEADER_SIZE); |
106 | param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); | 108 | elapsed = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); |
109 | } | ||
110 | |||
111 | if (elapsed > 0) { | ||
112 | param = elapsed; | ||
107 | action = CODEC_ACTION_SEEK_TIME; | 113 | action = CODEC_ACTION_SEEK_TIME; |
108 | } | 114 | } |
109 | else { | 115 | else { |
116 | elapsed = 0; | ||
110 | ci->set_elapsed(0); | 117 | ci->set_elapsed(0); |
111 | } | 118 | } |
112 | 119 | ||
@@ -151,6 +158,7 @@ seek_start : | |||
151 | 158 | ||
152 | /* Seek to the start of the track */ | 159 | /* Seek to the start of the track */ |
153 | if (param == 0) { | 160 | if (param == 0) { |
161 | elapsed = 0; | ||
154 | ci->set_elapsed(0); | 162 | ci->set_elapsed(0); |
155 | ci->seek_complete(); | 163 | ci->seek_complete(); |
156 | action = CODEC_ACTION_NULL; | 164 | action = CODEC_ACTION_NULL; |
diff --git a/lib/rbcodec/codecs/au.c b/lib/rbcodec/codecs/au.c index 7ae7fe3e94..18d4296125 100644 --- a/lib/rbcodec/codecs/au.c +++ b/lib/rbcodec/codecs/au.c | |||
@@ -139,6 +139,7 @@ enum codec_status codec_run(void) | |||
139 | codec_set_replaygain(ci->id3); | 139 | codec_set_replaygain(ci->id3); |
140 | 140 | ||
141 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 141 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ |
142 | param = ci->id3->elapsed; | ||
142 | bytesdone = ci->id3->offset; | 143 | bytesdone = ci->id3->offset; |
143 | 144 | ||
144 | ci->memset(&format, 0, sizeof(struct pcm_format)); | 145 | ci->memset(&format, 0, sizeof(struct pcm_format)); |
@@ -236,10 +237,20 @@ enum codec_status codec_run(void) | |||
236 | } | 237 | } |
237 | 238 | ||
238 | /* make sure we're at the correct offset */ | 239 | /* make sure we're at the correct offset */ |
239 | if (bytesdone > (uint32_t) firstblockposn) { | 240 | if (bytesdone > (uint32_t) firstblockposn || param) { |
241 | uint32_t seek_val; | ||
242 | int seek_mode; | ||
243 | |||
244 | if (bytesdone) { | ||
245 | seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); | ||
246 | seek_mode = PCM_SEEK_POS; | ||
247 | } else { | ||
248 | seek_val = param; | ||
249 | seek_mode = PCM_SEEK_TIME; | ||
250 | } | ||
251 | |||
240 | /* Round down to previous block */ | 252 | /* Round down to previous block */ |
241 | struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, | 253 | struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, NULL); |
242 | PCM_SEEK_POS, NULL); | ||
243 | 254 | ||
244 | if (newpos->pos > format.numbytes) | 255 | if (newpos->pos > format.numbytes) |
245 | goto done; | 256 | goto done; |
diff --git a/lib/rbcodec/codecs/ay.c b/lib/rbcodec/codecs/ay.c index b11ad84294..88936df131 100644 --- a/lib/rbcodec/codecs/ay.c +++ b/lib/rbcodec/codecs/ay.c | |||
@@ -56,6 +56,7 @@ enum codec_status codec_run(void) | |||
56 | /* reset values */ | 56 | /* reset values */ |
57 | track = is_multitrack = 0; | 57 | track = is_multitrack = 0; |
58 | elapsed_time = 0; | 58 | elapsed_time = 0; |
59 | param = ci->id3->elapsed; | ||
59 | 60 | ||
60 | DEBUGF("AY: next_track\n"); | 61 | DEBUGF("AY: next_track\n"); |
61 | if (codec_init()) { | 62 | if (codec_init()) { |
@@ -87,6 +88,10 @@ enum codec_status codec_run(void) | |||
87 | is_multitrack = 1; | 88 | is_multitrack = 1; |
88 | } | 89 | } |
89 | 90 | ||
91 | if (param) { | ||
92 | goto resume_start; | ||
93 | } | ||
94 | |||
90 | next_track: | 95 | next_track: |
91 | set_codec_track(track, is_multitrack); | 96 | set_codec_track(track, is_multitrack); |
92 | 97 | ||
@@ -98,6 +103,7 @@ next_track: | |||
98 | break; | 103 | break; |
99 | 104 | ||
100 | if (action == CODEC_ACTION_SEEK_TIME) { | 105 | if (action == CODEC_ACTION_SEEK_TIME) { |
106 | resume_start: | ||
101 | if (is_multitrack) { | 107 | if (is_multitrack) { |
102 | track = param/1000; | 108 | track = param/1000; |
103 | ci->seek_complete(); | 109 | ci->seek_complete(); |
diff --git a/lib/rbcodec/codecs/cook.c b/lib/rbcodec/codecs/cook.c index 55188aad36..402d1d3fa6 100644 --- a/lib/rbcodec/codecs/cook.c +++ b/lib/rbcodec/codecs/cook.c | |||
@@ -56,14 +56,16 @@ enum codec_status codec_run(void) | |||
56 | uint32_t packet_count; | 56 | uint32_t packet_count; |
57 | int scrambling_unit_size, num_units; | 57 | int scrambling_unit_size, num_units; |
58 | size_t resume_offset; | 58 | size_t resume_offset; |
59 | intptr_t param = 0; | 59 | intptr_t param; |
60 | enum codec_command_action action = CODEC_ACTION_NULL; | 60 | enum codec_command_action action; |
61 | 61 | ||
62 | if (codec_init()) { | 62 | if (codec_init()) { |
63 | DEBUGF("codec init failed\n"); | 63 | DEBUGF("codec init failed\n"); |
64 | return CODEC_ERROR; | 64 | return CODEC_ERROR; |
65 | } | 65 | } |
66 | 66 | ||
67 | action = CODEC_ACTION_NULL; | ||
68 | param = ci->id3->elapsed; | ||
67 | resume_offset = ci->id3->offset; | 69 | resume_offset = ci->id3->offset; |
68 | 70 | ||
69 | codec_set_replaygain(ci->id3); | 71 | codec_set_replaygain(ci->id3); |
@@ -97,12 +99,15 @@ enum codec_status codec_run(void) | |||
97 | } | 99 | } |
98 | 100 | ||
99 | /* check for a mid-track resume and force a seek time accordingly */ | 101 | /* check for a mid-track resume and force a seek time accordingly */ |
100 | if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { | 102 | if(resume_offset) { |
101 | resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; | 103 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
102 | num_units = (int)resume_offset / scrambling_unit_size; | 104 | num_units = (int)resume_offset / scrambling_unit_size; |
103 | /* put number of subpackets to skip in resume_offset */ | 105 | /* put number of subpackets to skip in resume_offset */ |
104 | resume_offset /= (sps + PACKET_HEADER_SIZE); | 106 | resume_offset /= (sps + PACKET_HEADER_SIZE); |
105 | param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); | 107 | param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); |
108 | } | ||
109 | |||
110 | if (param) { | ||
106 | action = CODEC_ACTION_SEEK_TIME; | 111 | action = CODEC_ACTION_SEEK_TIME; |
107 | } | 112 | } |
108 | else { | 113 | else { |
diff --git a/lib/rbcodec/codecs/flac.c b/lib/rbcodec/codecs/flac.c index 3390c24a2c..eab6e7c2bc 100644 --- a/lib/rbcodec/codecs/flac.c +++ b/lib/rbcodec/codecs/flac.c | |||
@@ -468,7 +468,8 @@ enum codec_status codec_run(void) | |||
468 | return CODEC_ERROR; | 468 | return CODEC_ERROR; |
469 | } | 469 | } |
470 | 470 | ||
471 | /* Need to save offset for later use (cleared indirectly by flac_init) */ | 471 | /* Need to save resume for later use (cleared indirectly by flac_init) */ |
472 | elapsedtime = ci->id3->elapsed; | ||
472 | samplesdone = ci->id3->offset; | 473 | samplesdone = ci->id3->offset; |
473 | 474 | ||
474 | if (!flac_init(&fc,ci->id3->first_frame_offset)) { | 475 | if (!flac_init(&fc,ci->id3->first_frame_offset)) { |
@@ -481,9 +482,16 @@ enum codec_status codec_run(void) | |||
481 | STEREO_MONO : STEREO_NONINTERLEAVED); | 482 | STEREO_MONO : STEREO_NONINTERLEAVED); |
482 | codec_set_replaygain(ci->id3); | 483 | codec_set_replaygain(ci->id3); |
483 | 484 | ||
484 | flac_seek_offset(&fc, samplesdone); | 485 | if (samplesdone || !elapsedtime) { |
485 | samplesdone=fc.samplenumber+fc.blocksize; | 486 | flac_seek_offset(&fc, samplesdone); |
486 | elapsedtime=((uint64_t)samplesdone*1000)/(ci->id3->frequency); | 487 | samplesdone=fc.samplenumber+fc.blocksize; |
488 | elapsedtime=((uint64_t)samplesdone*1000)/(ci->id3->frequency); | ||
489 | } | ||
490 | else if (!flac_seek(&fc,(uint32_t)((uint64_t)elapsedtime | ||
491 | *ci->id3->frequency/1000))) { | ||
492 | elapsedtime = 0; | ||
493 | } | ||
494 | |||
487 | ci->set_elapsed(elapsedtime); | 495 | ci->set_elapsed(elapsedtime); |
488 | 496 | ||
489 | /* The main decoding loop */ | 497 | /* The main decoding loop */ |
diff --git a/lib/rbcodec/codecs/gbs.c b/lib/rbcodec/codecs/gbs.c index def05ed351..717f56c82f 100644 --- a/lib/rbcodec/codecs/gbs.c +++ b/lib/rbcodec/codecs/gbs.c | |||
@@ -76,6 +76,11 @@ enum codec_status codec_run(void) | |||
76 | if (gbs_emu.m3u.size > 0) | 76 | if (gbs_emu.m3u.size > 0) |
77 | gbs_emu.track_count = gbs_emu.m3u.size; | 77 | gbs_emu.track_count = gbs_emu.m3u.size; |
78 | 78 | ||
79 | if (ci->id3->elapsed) { | ||
80 | track = ci->id3->elapsed/1000; | ||
81 | if (track >= gbs_emu.track_count) return CODEC_OK; | ||
82 | } | ||
83 | |||
79 | next_track: | 84 | next_track: |
80 | set_codec_track(track); | 85 | set_codec_track(track); |
81 | 86 | ||
diff --git a/lib/rbcodec/codecs/hes.c b/lib/rbcodec/codecs/hes.c index 849fd88f12..56f49621c6 100644 --- a/lib/rbcodec/codecs/hes.c +++ b/lib/rbcodec/codecs/hes.c | |||
@@ -76,6 +76,11 @@ enum codec_status codec_run(void) | |||
76 | if (hes_emu.m3u.size > 0) | 76 | if (hes_emu.m3u.size > 0) |
77 | hes_emu.track_count = hes_emu.m3u.size; | 77 | hes_emu.track_count = hes_emu.m3u.size; |
78 | 78 | ||
79 | if (ci->id3->elapsed) { | ||
80 | track = ci->id3->elapsed/1000; | ||
81 | if (track >= hes_emu.track_count) return CODEC_OK; | ||
82 | } | ||
83 | |||
79 | next_track: | 84 | next_track: |
80 | set_codec_track(track); | 85 | set_codec_track(track); |
81 | 86 | ||
diff --git a/lib/rbcodec/codecs/kss.c b/lib/rbcodec/codecs/kss.c index 92efcd4e5f..e6cf866cdd 100644 --- a/lib/rbcodec/codecs/kss.c +++ b/lib/rbcodec/codecs/kss.c | |||
@@ -79,6 +79,11 @@ enum codec_status codec_run(void) | |||
79 | if (kss_emu.m3u.size > 0) | 79 | if (kss_emu.m3u.size > 0) |
80 | kss_emu.track_count = kss_emu.m3u.size; | 80 | kss_emu.track_count = kss_emu.m3u.size; |
81 | 81 | ||
82 | if (ci->id3->elapsed) { | ||
83 | track = ci->id3->elapsed/1000; | ||
84 | if (track >= kss_emu.track_count) return CODEC_OK; | ||
85 | } | ||
86 | |||
82 | next_track: | 87 | next_track: |
83 | set_codec_track(track); | 88 | set_codec_track(track); |
84 | 89 | ||
diff --git a/lib/rbcodec/codecs/mod.c b/lib/rbcodec/codecs/mod.c index 8bb2dc5163..4dd0cde6e5 100644 --- a/lib/rbcodec/codecs/mod.c +++ b/lib/rbcodec/codecs/mod.c | |||
@@ -1319,7 +1319,16 @@ enum codec_status codec_run(void) | |||
1319 | loadmod(modfile); | 1319 | loadmod(modfile); |
1320 | 1320 | ||
1321 | /* The main decoder loop */ | 1321 | /* The main decoder loop */ |
1322 | ci->set_elapsed(0); | 1322 | #if 0 |
1323 | /* Needs to be a bit more elaborate or critical stuff is missed */ | ||
1324 | if (ci->id3->elapsed) { | ||
1325 | modplayer.patterntableposition = ci->id3->elapsed/1000; | ||
1326 | modplayer.currentline = 0; | ||
1327 | } | ||
1328 | #endif | ||
1329 | |||
1330 | ci->set_elapsed(modplayer.patterntableposition*1000); | ||
1331 | |||
1323 | bytesdone = 0; | 1332 | bytesdone = 0; |
1324 | old_patterntableposition = 0; | 1333 | old_patterntableposition = 0; |
1325 | 1334 | ||
diff --git a/lib/rbcodec/codecs/mpa.c b/lib/rbcodec/codecs/mpa.c index 07db248099..ca12087e87 100644 --- a/lib/rbcodec/codecs/mpa.c +++ b/lib/rbcodec/codecs/mpa.c | |||
@@ -346,6 +346,11 @@ enum codec_status codec_run(void) | |||
346 | current_frequency = ci->id3->frequency; | 346 | current_frequency = ci->id3->frequency; |
347 | codec_set_replaygain(ci->id3); | 347 | codec_set_replaygain(ci->id3); |
348 | 348 | ||
349 | if (!ci->id3->offset && ci->id3->elapsed) { | ||
350 | /* Have elapsed time but not offset */ | ||
351 | ci->id3->offset = get_file_pos(ci->id3->elapsed); | ||
352 | } | ||
353 | |||
349 | if (ci->id3->offset) { | 354 | if (ci->id3->offset) { |
350 | ci->seek_buffer(ci->id3->offset); | 355 | ci->seek_buffer(ci->id3->offset); |
351 | set_elapsed(ci->id3); | 356 | set_elapsed(ci->id3); |
diff --git a/lib/rbcodec/codecs/mpc.c b/lib/rbcodec/codecs/mpc.c index 9db40242dc..79f2aa22db 100644 --- a/lib/rbcodec/codecs/mpc.c +++ b/lib/rbcodec/codecs/mpc.c | |||
@@ -108,6 +108,7 @@ enum codec_status codec_run(void) | |||
108 | * sample seek position from the file offset, the sampling frequency and | 108 | * sample seek position from the file offset, the sampling frequency and |
109 | * the bitrate. As the saved position is exactly calculated the reverse way | 109 | * the bitrate. As the saved position is exactly calculated the reverse way |
110 | * there is no loss of information except rounding. */ | 110 | * there is no loss of information except rounding. */ |
111 | elapsed_time = ci->id3->elapsed; | ||
111 | samplesdone = 100 * (((mpc_uint64_t)ci->id3->offset * frequency) / byterate); | 112 | samplesdone = 100 * (((mpc_uint64_t)ci->id3->offset * frequency) / byterate); |
112 | 113 | ||
113 | /* Set up digital signal processing for correct number of channels */ | 114 | /* Set up digital signal processing for correct number of channels */ |
@@ -122,19 +123,24 @@ enum codec_status codec_run(void) | |||
122 | 123 | ||
123 | codec_set_replaygain(ci->id3); | 124 | codec_set_replaygain(ci->id3); |
124 | 125 | ||
125 | /* Resume to saved sample offset. */ | 126 | if (samplesdone > 0 || elapsed_time) |
126 | elapsed_time = 0; | ||
127 | |||
128 | if (samplesdone > 0) | ||
129 | { | 127 | { |
130 | if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK) | 128 | mpc_int64_t new_offset = samplesdone; |
129 | |||
130 | if (new_offset <= 0) | ||
131 | new_offset = (elapsed_time/10)*frequency; /* by time */ | ||
132 | |||
133 | /* Resume to sample offset. */ | ||
134 | if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK) | ||
131 | { | 135 | { |
132 | elapsed_time = (samplesdone*10)/frequency; | 136 | samplesdone = new_offset; |
133 | } | 137 | } |
134 | else | 138 | else |
135 | { | 139 | { |
136 | samplesdone = 0; | 140 | samplesdone = 0; |
137 | } | 141 | } |
142 | |||
143 | elapsed_time = (samplesdone*10)/frequency; | ||
138 | } | 144 | } |
139 | 145 | ||
140 | ci->set_elapsed(elapsed_time); | 146 | ci->set_elapsed(elapsed_time); |
diff --git a/lib/rbcodec/codecs/nsf.c b/lib/rbcodec/codecs/nsf.c index 4c5b37c3fa..cbdf8e3ec5 100644 --- a/lib/rbcodec/codecs/nsf.c +++ b/lib/rbcodec/codecs/nsf.c | |||
@@ -57,6 +57,7 @@ enum codec_status codec_run(void) | |||
57 | 57 | ||
58 | track = is_multitrack = 0; | 58 | track = is_multitrack = 0; |
59 | elapsed_time = 0; | 59 | elapsed_time = 0; |
60 | param = ci->id3->elapsed; | ||
60 | 61 | ||
61 | DEBUGF("NSF: next_track\n"); | 62 | DEBUGF("NSF: next_track\n"); |
62 | if (codec_init()) { | 63 | if (codec_init()) { |
@@ -85,6 +86,10 @@ enum codec_status codec_run(void) | |||
85 | 86 | ||
86 | if (nsf_emu.track_count > 1) is_multitrack = 1; | 87 | if (nsf_emu.track_count > 1) is_multitrack = 1; |
87 | 88 | ||
89 | if (param) { | ||
90 | goto resume_start; | ||
91 | } | ||
92 | |||
88 | next_track: | 93 | next_track: |
89 | set_codec_track(track, is_multitrack); | 94 | set_codec_track(track, is_multitrack); |
90 | 95 | ||
@@ -96,6 +101,7 @@ next_track: | |||
96 | break; | 101 | break; |
97 | 102 | ||
98 | if (action == CODEC_ACTION_SEEK_TIME) { | 103 | if (action == CODEC_ACTION_SEEK_TIME) { |
104 | resume_start: | ||
99 | if (is_multitrack) { | 105 | if (is_multitrack) { |
100 | track = param/1000; | 106 | track = param/1000; |
101 | ci->seek_complete(); | 107 | ci->seek_complete(); |
diff --git a/lib/rbcodec/codecs/opus.c b/lib/rbcodec/codecs/opus.c index 15d96ff6fe..2c495aa8d0 100644 --- a/lib/rbcodec/codecs/opus.c +++ b/lib/rbcodec/codecs/opus.c | |||
@@ -314,6 +314,7 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
314 | enum codec_status codec_run(void) | 314 | enum codec_status codec_run(void) |
315 | { | 315 | { |
316 | int error = CODEC_ERROR; | 316 | int error = CODEC_ERROR; |
317 | enum codec_command_action action; | ||
317 | intptr_t param; | 318 | intptr_t param; |
318 | ogg_sync_state oy; | 319 | ogg_sync_state oy; |
319 | ogg_page og; | 320 | ogg_page og; |
@@ -325,13 +326,17 @@ enum codec_status codec_run(void) | |||
325 | OpusDecoder *st = NULL; | 326 | OpusDecoder *st = NULL; |
326 | OpusHeader header; | 327 | OpusHeader header; |
327 | int ret; | 328 | int ret; |
328 | unsigned long strtoffset = ci->id3->offset; | 329 | unsigned long strtoffset; |
329 | int skip = 0; | 330 | int skip = 0; |
330 | int64_t seek_target; | 331 | int64_t seek_target; |
331 | uint64_t granule_pos; | 332 | uint64_t granule_pos; |
332 | 333 | ||
333 | ogg_malloc_init(); | 334 | ogg_malloc_init(); |
334 | 335 | ||
336 | action = CODEC_ACTION_NULL; | ||
337 | param = ci->id3->elapsed; | ||
338 | strtoffset = ci->id3->offset; | ||
339 | |||
335 | global_stack = 0; | 340 | global_stack = 0; |
336 | 341 | ||
337 | #if defined(CPU_COLDFIRE) | 342 | #if defined(CPU_COLDFIRE) |
@@ -351,28 +356,40 @@ enum codec_status codec_run(void) | |||
351 | ci->seek_buffer(0); | 356 | ci->seek_buffer(0); |
352 | ci->set_elapsed(0); | 357 | ci->set_elapsed(0); |
353 | 358 | ||
359 | if (!strtoffset && param) { | ||
360 | action = CODEC_ACTION_SEEK_TIME; | ||
361 | } | ||
362 | |||
363 | goto next_page; | ||
364 | |||
354 | while (1) { | 365 | while (1) { |
355 | enum codec_command_action action = ci->get_command(¶m); | 366 | if (action == CODEC_ACTION_NULL) |
367 | action = ci->get_command(¶m); | ||
356 | 368 | ||
357 | if (action == CODEC_ACTION_HALT) | 369 | if (action != CODEC_ACTION_NULL) { |
358 | break; | 370 | if (action == CODEC_ACTION_HALT) |
371 | break; | ||
372 | |||
373 | if (action == CODEC_ACTION_SEEK_TIME) { | ||
374 | if (st != NULL) { | ||
375 | /* calculate granule to seek to (including seek rewind) */ | ||
376 | seek_target = (48LL * param) + header.preskip; | ||
377 | skip = MIN(seek_target, SEEK_REWIND); | ||
378 | seek_target -= skip; | ||
359 | 379 | ||
360 | if (action == CODEC_ACTION_SEEK_TIME) { | 380 | LOGF("Opus seek page:%lld,%lld,%ld\n", |
361 | if (st != NULL) { | 381 | seek_target, page_granule, (long)param); |
362 | /* calculate granule to seek to (including seek rewind) */ | 382 | speex_seek_page_granule(seek_target, page_granule, &oy, &os); |
363 | seek_target = (48LL * param) + header.preskip; | 383 | } |
364 | skip = MIN(seek_target, SEEK_REWIND); | ||
365 | seek_target -= skip; | ||
366 | 384 | ||
367 | LOGF("Opus seek page:%lld,%lld,%ld\n", | 385 | ci->set_elapsed(param); |
368 | seek_target, page_granule, (long)param); | 386 | ci->seek_complete(); |
369 | speex_seek_page_granule(seek_target, page_granule, &oy, &os); | ||
370 | } | 387 | } |
371 | 388 | ||
372 | ci->set_elapsed(param); | 389 | action = CODEC_ACTION_NULL; |
373 | ci->seek_complete(); | ||
374 | } | 390 | } |
375 | 391 | ||
392 | next_page: | ||
376 | /*Get the ogg buffer for writing*/ | 393 | /*Get the ogg buffer for writing*/ |
377 | if (get_more_data(&oy) < 1) { | 394 | if (get_more_data(&oy) < 1) { |
378 | goto done; | 395 | goto done; |
diff --git a/lib/rbcodec/codecs/raac.c b/lib/rbcodec/codecs/raac.c index 523560b63e..d2d3531028 100644 --- a/lib/rbcodec/codecs/raac.c +++ b/lib/rbcodec/codecs/raac.c | |||
@@ -63,14 +63,16 @@ enum codec_status codec_run(void) | |||
63 | unsigned char c = 0; /* channels */ | 63 | unsigned char c = 0; /* channels */ |
64 | int playback_on = -1; | 64 | int playback_on = -1; |
65 | size_t resume_offset; | 65 | size_t resume_offset; |
66 | enum codec_command_action action; | ||
66 | intptr_t param; | 67 | intptr_t param; |
67 | enum codec_command_action action = CODEC_ACTION_NULL; | ||
68 | 68 | ||
69 | if (codec_init()) { | 69 | if (codec_init()) { |
70 | DEBUGF("FAAD: Codec init error\n"); | 70 | DEBUGF("FAAD: Codec init error\n"); |
71 | return CODEC_ERROR; | 71 | return CODEC_ERROR; |
72 | } | 72 | } |
73 | 73 | ||
74 | action = CODEC_ACTION_NULL; | ||
75 | param = ci->id3->elapsed; | ||
74 | resume_offset = ci->id3->offset; | 76 | resume_offset = ci->id3->offset; |
75 | 77 | ||
76 | ci->memset(&rmctx,0,sizeof(RMContext)); | 78 | ci->memset(&rmctx,0,sizeof(RMContext)); |
@@ -104,15 +106,21 @@ enum codec_status codec_run(void) | |||
104 | } | 106 | } |
105 | 107 | ||
106 | /* check for a mid-track resume and force a seek time accordingly */ | 108 | /* check for a mid-track resume and force a seek time accordingly */ |
107 | if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { | 109 | if (resume_offset) { |
108 | resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; | 110 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); |
109 | /* put number of subpackets to skip in resume_offset */ | 111 | /* put number of subpackets to skip in resume_offset */ |
110 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); | 112 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); |
111 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); | 113 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); |
114 | } | ||
115 | |||
116 | if (param > 0) { | ||
112 | action = CODEC_ACTION_SEEK_TIME; | 117 | action = CODEC_ACTION_SEEK_TIME; |
113 | } | 118 | } |
114 | ci->set_elapsed(0); | 119 | else { |
115 | ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); | 120 | /* Seek to the first packet */ |
121 | ci->set_elapsed(0); | ||
122 | ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); | ||
123 | } | ||
116 | 124 | ||
117 | /* The main decoding loop */ | 125 | /* The main decoding loop */ |
118 | while (1) { | 126 | while (1) { |
@@ -124,7 +132,7 @@ enum codec_status codec_run(void) | |||
124 | 132 | ||
125 | if (action == CODEC_ACTION_SEEK_TIME) { | 133 | if (action == CODEC_ACTION_SEEK_TIME) { |
126 | /* Do not allow seeking beyond the file's length */ | 134 | /* Do not allow seeking beyond the file's length */ |
127 | if ((unsigned) param > ci->id3->length) { | 135 | if ((unsigned long)param > ci->id3->length) { |
128 | ci->set_elapsed(ci->id3->length); | 136 | ci->set_elapsed(ci->id3->length); |
129 | ci->seek_complete(); | 137 | ci->seek_complete(); |
130 | break; | 138 | break; |
@@ -164,6 +172,7 @@ enum codec_status codec_run(void) | |||
164 | 172 | ||
165 | ci->advance_buffer(pkt.length); | 173 | ci->advance_buffer(pkt.length); |
166 | } | 174 | } |
175 | |||
167 | ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE); | 176 | ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE); |
168 | buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); | 177 | buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); |
169 | NeAACDecPostSeekReset(decoder, decoder->frame); | 178 | NeAACDecPostSeekReset(decoder, decoder->frame); |
diff --git a/lib/rbcodec/codecs/sgc.c b/lib/rbcodec/codecs/sgc.c index 348a54a2d3..eb260975c5 100644 --- a/lib/rbcodec/codecs/sgc.c +++ b/lib/rbcodec/codecs/sgc.c | |||
@@ -91,6 +91,11 @@ enum codec_status codec_run(void) | |||
91 | if (sgc_emu.m3u.size > 0) | 91 | if (sgc_emu.m3u.size > 0) |
92 | sgc_emu.track_count = sgc_emu.m3u.size; | 92 | sgc_emu.track_count = sgc_emu.m3u.size; |
93 | 93 | ||
94 | if (ci->id3->elapsed) { | ||
95 | track = ci->id3->elapsed/1000; | ||
96 | if (track >= sgc_emu.track_count) return CODEC_OK; | ||
97 | } | ||
98 | |||
94 | next_track: | 99 | next_track: |
95 | set_codec_track(track); | 100 | set_codec_track(track); |
96 | 101 | ||
diff --git a/lib/rbcodec/codecs/sid.c b/lib/rbcodec/codecs/sid.c index 1a6d04155d..6e39d3f759 100644 --- a/lib/rbcodec/codecs/sid.c +++ b/lib/rbcodec/codecs/sid.c | |||
@@ -1253,6 +1253,7 @@ enum codec_status codec_run(void) | |||
1253 | unsigned char subSongsMax, subSong, song_speed; | 1253 | unsigned char subSongsMax, subSong, song_speed; |
1254 | unsigned char *sidfile = NULL; | 1254 | unsigned char *sidfile = NULL; |
1255 | intptr_t param; | 1255 | intptr_t param; |
1256 | bool resume; | ||
1256 | 1257 | ||
1257 | if (codec_init()) { | 1258 | if (codec_init()) { |
1258 | return CODEC_ERROR; | 1259 | return CODEC_ERROR; |
@@ -1269,15 +1270,10 @@ enum codec_status codec_run(void) | |||
1269 | return CODEC_ERROR; | 1270 | return CODEC_ERROR; |
1270 | } | 1271 | } |
1271 | 1272 | ||
1272 | c64Init(SAMPLE_RATE); | 1273 | param = ci->id3->elapsed; |
1273 | LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, | 1274 | resume = param != 0; |
1274 | &subSongsMax, &subSong, &song_speed, (unsigned short)filesize); | ||
1275 | sidPoke(24, 15); /* Turn on full volume */ | ||
1276 | cpuJSR(init_addr, subSong); /* Start the song initialize */ | ||
1277 | 1275 | ||
1278 | 1276 | goto sid_start; | |
1279 | /* Set the elapsed time to the current subsong (in seconds) */ | ||
1280 | ci->set_elapsed(subSong*1000); | ||
1281 | 1277 | ||
1282 | /* The main decoder loop */ | 1278 | /* The main decoder loop */ |
1283 | while (1) { | 1279 | while (1) { |
@@ -1287,20 +1283,26 @@ enum codec_status codec_run(void) | |||
1287 | break; | 1283 | break; |
1288 | 1284 | ||
1289 | if (action == CODEC_ACTION_SEEK_TIME) { | 1285 | if (action == CODEC_ACTION_SEEK_TIME) { |
1286 | sid_start: | ||
1290 | /* New time is ready in param */ | 1287 | /* New time is ready in param */ |
1291 | 1288 | ||
1292 | /* Start playing from scratch */ | 1289 | /* Start playing from scratch */ |
1293 | c64Init(SAMPLE_RATE); | 1290 | c64Init(SAMPLE_RATE); |
1294 | LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, | 1291 | LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, |
1295 | &subSongsMax, &subSong, &song_speed, (unsigned short)filesize); | 1292 | &subSongsMax, &subSong, &song_speed, |
1293 | (unsigned short)filesize); | ||
1296 | sidPoke(24, 15); /* Turn on full volume */ | 1294 | sidPoke(24, 15); /* Turn on full volume */ |
1297 | subSong = param / 1000; /* Now use the current seek time in seconds as subsong */ | 1295 | if (!resume || (resume && param)) |
1296 | subSong = param / 1000; /* Now use the current seek time in | ||
1297 | seconds as subsong */ | ||
1298 | cpuJSR(init_addr, subSong); /* Start the song initialize */ | 1298 | cpuJSR(init_addr, subSong); /* Start the song initialize */ |
1299 | nSamplesToRender = 0; /* Start the rendering from scratch */ | 1299 | nSamplesToRender = 0; /* Start the rendering from scratch */ |
1300 | 1300 | ||
1301 | /* Set the elapsed time to the current subsong (in seconds) */ | 1301 | /* Set the elapsed time to the current subsong (in seconds) */ |
1302 | ci->set_elapsed(subSong*1000); | 1302 | ci->set_elapsed(subSong*1000); |
1303 | ci->seek_complete(); | 1303 | ci->seek_complete(); |
1304 | |||
1305 | resume = false; | ||
1304 | } | 1306 | } |
1305 | 1307 | ||
1306 | nSamplesRendered = 0; | 1308 | nSamplesRendered = 0; |
diff --git a/lib/rbcodec/codecs/smaf.c b/lib/rbcodec/codecs/smaf.c index d56aa0a860..e4ec6342b2 100644 --- a/lib/rbcodec/codecs/smaf.c +++ b/lib/rbcodec/codecs/smaf.c | |||
@@ -360,7 +360,8 @@ enum codec_status codec_run(void) | |||
360 | 360 | ||
361 | codec_set_replaygain(ci->id3); | 361 | codec_set_replaygain(ci->id3); |
362 | 362 | ||
363 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 363 | /* Need to save resume for later use (cleared indirectly by advance_buffer) */ |
364 | param = ci->id3->elapsed; | ||
364 | bytesdone = ci->id3->offset; | 365 | bytesdone = ci->id3->offset; |
365 | 366 | ||
366 | decodedsamples = 0; | 367 | decodedsamples = 0; |
@@ -408,11 +409,21 @@ enum codec_status codec_run(void) | |||
408 | ci->seek_buffer(firstblockposn); | 409 | ci->seek_buffer(firstblockposn); |
409 | 410 | ||
410 | /* make sure we're at the correct offset */ | 411 | /* make sure we're at the correct offset */ |
411 | if (bytesdone > (uint32_t) firstblockposn) | 412 | if (bytesdone > (uint32_t) firstblockposn || param) { |
412 | { | 413 | uint32_t seek_val; |
414 | int seek_mode; | ||
415 | |||
416 | if (bytesdone) { | ||
417 | seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); | ||
418 | seek_mode = PCM_SEEK_POS; | ||
419 | } else { | ||
420 | seek_val = param; | ||
421 | seek_mode = PCM_SEEK_TIME; | ||
422 | } | ||
423 | |||
413 | /* Round down to previous block */ | 424 | /* Round down to previous block */ |
414 | struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, | 425 | struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, |
415 | PCM_SEEK_POS, &read_buffer); | 426 | &read_buffer); |
416 | 427 | ||
417 | if (newpos->pos > format.numbytes) | 428 | if (newpos->pos > format.numbytes) |
418 | return CODEC_OK; | 429 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/speex.c b/lib/rbcodec/codecs/speex.c index ac3bc963b1..a073151ee2 100644 --- a/lib/rbcodec/codecs/speex.c +++ b/lib/rbcodec/codecs/speex.c | |||
@@ -381,7 +381,6 @@ enum codec_status codec_run(void) | |||
381 | int error = CODEC_ERROR; | 381 | int error = CODEC_ERROR; |
382 | 382 | ||
383 | SpeexBits bits; | 383 | SpeexBits bits; |
384 | int eof = 0; | ||
385 | spx_ogg_sync_state oy; | 384 | spx_ogg_sync_state oy; |
386 | spx_ogg_page og; | 385 | spx_ogg_page og; |
387 | spx_ogg_packet op; | 386 | spx_ogg_packet op; |
@@ -403,9 +402,10 @@ enum codec_status codec_run(void) | |||
403 | int packet_count = 0; | 402 | int packet_count = 0; |
404 | int lookahead; | 403 | int lookahead; |
405 | int headerssize = 0; | 404 | int headerssize = 0; |
406 | unsigned long strtoffset = ci->id3->offset; | 405 | unsigned long strtoffset; |
407 | void *st = NULL; | 406 | void *st = NULL; |
408 | int j = 0; | 407 | int j = 0; |
408 | enum codec_command_action action; | ||
409 | intptr_t param; | 409 | intptr_t param; |
410 | 410 | ||
411 | memset(&bits, 0, sizeof(bits)); | 411 | memset(&bits, 0, sizeof(bits)); |
@@ -416,6 +416,10 @@ enum codec_status codec_run(void) | |||
416 | goto exit; | 416 | goto exit; |
417 | } | 417 | } |
418 | 418 | ||
419 | action = CODEC_ACTION_NULL; | ||
420 | param = ci->id3->elapsed; | ||
421 | strtoffset = ci->id3->offset; | ||
422 | |||
419 | ci->seek_buffer(0); | 423 | ci->seek_buffer(0); |
420 | ci->set_elapsed(0); | 424 | ci->set_elapsed(0); |
421 | 425 | ||
@@ -425,29 +429,39 @@ enum codec_status codec_run(void) | |||
425 | 429 | ||
426 | codec_set_replaygain(ci->id3); | 430 | codec_set_replaygain(ci->id3); |
427 | 431 | ||
428 | eof = 0; | 432 | if (!strtoffset && param) { |
429 | while (!eof) { | 433 | action = CODEC_ACTION_SEEK_TIME; |
430 | enum codec_command_action action = ci->get_command(¶m); | 434 | } |
431 | 435 | ||
432 | if (action == CODEC_ACTION_HALT) | 436 | goto next_page; |
433 | break; | 437 | |
434 | 438 | while (1) { | |
435 | /*seek (seeks to the page before the position) */ | 439 | if (action == CODEC_ACTION_NULL) |
436 | if (action == CODEC_ACTION_SEEK_TIME) { | 440 | action = ci->get_command(¶m); |
437 | if(samplerate!=0&&packet_count>1){ | 441 | |
438 | LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", | 442 | if (action != CODEC_ACTION_NULL) { |
439 | ((spx_int64_t)param/1000) * | 443 | if (action == CODEC_ACTION_HALT) |
440 | (spx_int64_t)samplerate, | 444 | break; |
441 | page_granule, (long)param, | 445 | |
442 | (page_granule/samplerate)*1000, samplerate); | 446 | /*seek (seeks to the page before the position) */ |
443 | 447 | if (action == CODEC_ACTION_SEEK_TIME) { | |
444 | speex_seek_page_granule(((spx_int64_t)param/1000) * | 448 | if(samplerate!=0&&packet_count>1){ |
445 | (spx_int64_t)samplerate, | 449 | LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", |
446 | page_granule, &oy, headerssize); | 450 | ((spx_int64_t)param/1000) * |
451 | (spx_int64_t)samplerate, | ||
452 | page_granule, (long)param, | ||
453 | (page_granule/samplerate)*1000, samplerate); | ||
454 | |||
455 | speex_seek_page_granule(((spx_int64_t)param/1000) * | ||
456 | (spx_int64_t)samplerate, | ||
457 | page_granule, &oy, headerssize); | ||
458 | } | ||
459 | |||
460 | ci->set_elapsed(param); | ||
461 | ci->seek_complete(); | ||
447 | } | 462 | } |
448 | 463 | ||
449 | ci->set_elapsed(param); | 464 | action = CODEC_ACTION_NULL; |
450 | ci->seek_complete(); | ||
451 | } | 465 | } |
452 | 466 | ||
453 | next_page: | 467 | next_page: |
diff --git a/lib/rbcodec/codecs/tta.c b/lib/rbcodec/codecs/tta.c index 564496a14e..b7660a920f 100644 --- a/lib/rbcodec/codecs/tta.c +++ b/lib/rbcodec/codecs/tta.c | |||
@@ -82,10 +82,20 @@ enum codec_status codec_run(void) | |||
82 | decodedsamples = 0; | 82 | decodedsamples = 0; |
83 | endofstream = 0; | 83 | endofstream = 0; |
84 | 84 | ||
85 | if (ci->id3->offset > 0) | 85 | if (ci->id3->offset || ci->id3->elapsed) |
86 | { | 86 | { |
87 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 87 | /* Need to save offset for later use (cleared indirectly by |
88 | new_pos = set_position(ci->id3->offset, TTA_SEEK_POS); | 88 | advance_buffer) */ |
89 | unsigned int pos = ci->id3->offset; | ||
90 | enum tta_seek_type type = TTA_SEEK_POS; | ||
91 | |||
92 | if (!pos) { | ||
93 | pos = ci->id3->elapsed / SEEK_STEP; | ||
94 | type = TTA_SEEK_TIME; | ||
95 | } | ||
96 | |||
97 | new_pos = set_position(pos, type); | ||
98 | |||
89 | if (new_pos >= 0) | 99 | if (new_pos >= 0) |
90 | decodedsamples = new_pos; | 100 | decodedsamples = new_pos; |
91 | } | 101 | } |
diff --git a/lib/rbcodec/codecs/vgm.c b/lib/rbcodec/codecs/vgm.c index 9f2f1b9c5e..126305944f 100644 --- a/lib/rbcodec/codecs/vgm.c +++ b/lib/rbcodec/codecs/vgm.c | |||
@@ -127,7 +127,10 @@ enum codec_status codec_run(void) | |||
127 | 127 | ||
128 | Vgm_start_track(&vgm_emu); | 128 | Vgm_start_track(&vgm_emu); |
129 | 129 | ||
130 | ci->set_elapsed(0); | 130 | if (ci->id3->elapsed != 0) |
131 | Track_seek(&vgm_emu, ci->id3->elapsed); | ||
132 | |||
133 | codec_update_elapsed(); | ||
131 | codec_update_fade(); | 134 | codec_update_fade(); |
132 | 135 | ||
133 | /* The main decoder loop */ | 136 | /* The main decoder loop */ |
diff --git a/lib/rbcodec/codecs/vorbis.c b/lib/rbcodec/codecs/vorbis.c index c09d2cea6d..ca9db9b802 100644 --- a/lib/rbcodec/codecs/vorbis.c +++ b/lib/rbcodec/codecs/vorbis.c | |||
@@ -126,7 +126,6 @@ enum codec_status codec_run(void) | |||
126 | long n; | 126 | long n; |
127 | int current_section; | 127 | int current_section; |
128 | int previous_section; | 128 | int previous_section; |
129 | int eof; | ||
130 | ogg_int64_t vf_offsets[2]; | 129 | ogg_int64_t vf_offsets[2]; |
131 | ogg_int64_t vf_dataoffsets; | 130 | ogg_int64_t vf_dataoffsets; |
132 | ogg_uint32_t vf_serialnos; | 131 | ogg_uint32_t vf_serialnos; |
@@ -193,16 +192,17 @@ enum codec_status codec_run(void) | |||
193 | if (ci->id3->offset) { | 192 | if (ci->id3->offset) { |
194 | ci->seek_buffer(ci->id3->offset); | 193 | ci->seek_buffer(ci->id3->offset); |
195 | ov_raw_seek(&vf, ci->id3->offset); | 194 | ov_raw_seek(&vf, ci->id3->offset); |
196 | ci->set_elapsed(ov_time_tell(&vf)); | ||
197 | ci->set_offset(ov_raw_tell(&vf)); | 195 | ci->set_offset(ov_raw_tell(&vf)); |
198 | } | 196 | } |
199 | else { | 197 | else if (ci->id3->elapsed) { |
200 | ci->set_elapsed(0); | 198 | ov_time_seek(&vf, ci->id3->elapsed); |
201 | } | 199 | } |
202 | 200 | ||
201 | ci->set_elapsed(ov_time_tell(&vf)); | ||
202 | |||
203 | previous_section = -1; | 203 | previous_section = -1; |
204 | eof = 0; | 204 | |
205 | while (!eof) { | 205 | while (1) { |
206 | enum codec_command_action action = ci->get_command(¶m); | 206 | enum codec_command_action action = ci->get_command(¶m); |
207 | 207 | ||
208 | if (action == CODEC_ACTION_HALT) | 208 | if (action == CODEC_ACTION_HALT) |
@@ -230,7 +230,7 @@ enum codec_status codec_run(void) | |||
230 | } | 230 | } |
231 | 231 | ||
232 | if (n == 0) { | 232 | if (n == 0) { |
233 | eof = 1; | 233 | break; |
234 | } else if (n < 0) { | 234 | } else if (n < 0) { |
235 | DEBUGF("Vorbis: Error decoding frame\n"); | 235 | DEBUGF("Vorbis: Error decoding frame\n"); |
236 | } else { | 236 | } else { |
diff --git a/lib/rbcodec/codecs/vox.c b/lib/rbcodec/codecs/vox.c index 66979e2911..d84af24cfc 100644 --- a/lib/rbcodec/codecs/vox.c +++ b/lib/rbcodec/codecs/vox.c | |||
@@ -73,7 +73,8 @@ enum codec_status codec_run(void) | |||
73 | 73 | ||
74 | codec_set_replaygain(ci->id3); | 74 | codec_set_replaygain(ci->id3); |
75 | 75 | ||
76 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 76 | /* Need to save resume for later use (cleared indirectly by advance_buffer) */ |
77 | param = ci->id3->elapsed; | ||
77 | bytesdone = ci->id3->offset; | 78 | bytesdone = ci->id3->offset; |
78 | ci->seek_buffer(0); | 79 | ci->seek_buffer(0); |
79 | 80 | ||
@@ -123,10 +124,21 @@ enum codec_status codec_run(void) | |||
123 | ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); | 124 | ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); |
124 | 125 | ||
125 | /* make sure we're at the correct offset */ | 126 | /* make sure we're at the correct offset */ |
126 | if (bytesdone > (uint32_t) firstblockposn) { | 127 | if (bytesdone > (uint32_t) firstblockposn || param) { |
128 | uint32_t seek_val; | ||
129 | int seek_mode; | ||
130 | |||
131 | if (bytesdone) { | ||
132 | seek_val = bytesdone - MIN((uint32_t )firstblockposn, bytesdone); | ||
133 | seek_mode = PCM_SEEK_POS; | ||
134 | } else { | ||
135 | seek_val = param; | ||
136 | seek_mode = PCM_SEEK_TIME; | ||
137 | } | ||
138 | |||
127 | /* Round down to previous block */ | 139 | /* Round down to previous block */ |
128 | struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, | 140 | struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, |
129 | PCM_SEEK_POS, &read_buffer); | 141 | &read_buffer); |
130 | 142 | ||
131 | if (newpos->pos > format.numbytes) { | 143 | if (newpos->pos > format.numbytes) { |
132 | return CODEC_OK; | 144 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/wav.c b/lib/rbcodec/codecs/wav.c index cc65ab83b2..3208e2b5b8 100644 --- a/lib/rbcodec/codecs/wav.c +++ b/lib/rbcodec/codecs/wav.c | |||
@@ -182,7 +182,8 @@ enum codec_status codec_run(void) | |||
182 | 182 | ||
183 | codec_set_replaygain(ci->id3); | 183 | codec_set_replaygain(ci->id3); |
184 | 184 | ||
185 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 185 | /* Need to save resume for later use (cleared indirectly by advance_buffer) */ |
186 | param = ci->id3->elapsed; | ||
186 | bytesdone = ci->id3->offset; | 187 | bytesdone = ci->id3->offset; |
187 | 188 | ||
188 | /* get RIFF chunk header */ | 189 | /* get RIFF chunk header */ |
@@ -361,10 +362,21 @@ enum codec_status codec_run(void) | |||
361 | } | 362 | } |
362 | 363 | ||
363 | /* make sure we're at the correct offset */ | 364 | /* make sure we're at the correct offset */ |
364 | if (bytesdone > (uint32_t) firstblockposn) { | 365 | if (bytesdone > (uint32_t) firstblockposn || param) { |
366 | uint32_t seek_val; | ||
367 | int seek_mode; | ||
368 | |||
369 | if (bytesdone) { | ||
370 | seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); | ||
371 | seek_mode = PCM_SEEK_POS; | ||
372 | } else { | ||
373 | seek_val = param; | ||
374 | seek_mode = PCM_SEEK_TIME; | ||
375 | } | ||
376 | |||
365 | /* Round down to previous block */ | 377 | /* Round down to previous block */ |
366 | struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, | 378 | struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, |
367 | PCM_SEEK_POS, &read_buffer); | 379 | &read_buffer); |
368 | 380 | ||
369 | if (newpos->pos > format.numbytes) | 381 | if (newpos->pos > format.numbytes) |
370 | return CODEC_OK; | 382 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/wav64.c b/lib/rbcodec/codecs/wav64.c index 9b3b2d38e4..96e605faad 100644 --- a/lib/rbcodec/codecs/wav64.c +++ b/lib/rbcodec/codecs/wav64.c | |||
@@ -191,6 +191,7 @@ enum codec_status codec_run(void) | |||
191 | codec_set_replaygain(ci->id3); | 191 | codec_set_replaygain(ci->id3); |
192 | 192 | ||
193 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ | 193 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ |
194 | param = ci->id3->elapsed; | ||
194 | bytesdone = ci->id3->offset; | 195 | bytesdone = ci->id3->offset; |
195 | 196 | ||
196 | /* get RIFF chunk header */ | 197 | /* get RIFF chunk header */ |
@@ -363,10 +364,22 @@ enum codec_status codec_run(void) | |||
363 | } | 364 | } |
364 | 365 | ||
365 | /* make sure we're at the correct offset */ | 366 | /* make sure we're at the correct offset */ |
366 | if (bytesdone > (uint32_t) firstblockposn) { | 367 | if (bytesdone > (uint32_t) firstblockposn || param) { |
368 | uint32_t seek_val; | ||
369 | int seek_mode; | ||
370 | |||
371 | /* we prefer offset resume */ | ||
372 | if (bytesdone > (uint32_t) firstblockposn) { | ||
373 | seek_val = bytesdone - firstblockposn; | ||
374 | seek_mode = PCM_SEEK_POS; | ||
375 | } else { | ||
376 | seek_val = param; | ||
377 | seek_mode = PCM_SEEK_TIME; | ||
378 | } | ||
379 | |||
367 | /* Round down to previous block */ | 380 | /* Round down to previous block */ |
368 | struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, | 381 | struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, |
369 | PCM_SEEK_POS, &read_buffer); | 382 | &read_buffer); |
370 | 383 | ||
371 | if (newpos->pos > format.numbytes) { | 384 | if (newpos->pos > format.numbytes) { |
372 | return CODEC_OK; | 385 | return CODEC_OK; |
diff --git a/lib/rbcodec/codecs/wavpack.c b/lib/rbcodec/codecs/wavpack.c index c0cdafabac..d9c294397c 100644 --- a/lib/rbcodec/codecs/wavpack.c +++ b/lib/rbcodec/codecs/wavpack.c | |||
@@ -55,12 +55,16 @@ enum codec_status codec_run(void) | |||
55 | int bps; | 55 | int bps; |
56 | */ | 56 | */ |
57 | int nchans, sr_100; | 57 | int nchans, sr_100; |
58 | unsigned long offset; | ||
58 | intptr_t param; | 59 | intptr_t param; |
59 | 60 | ||
60 | if (codec_init()) | 61 | if (codec_init()) |
61 | return CODEC_ERROR; | 62 | return CODEC_ERROR; |
62 | 63 | ||
63 | ci->seek_buffer (ci->id3->offset); | 64 | param = ci->id3->elapsed; |
65 | offset = ci->id3->offset; | ||
66 | |||
67 | ci->seek_buffer (offset); | ||
64 | 68 | ||
65 | /* Create a decoder instance */ | 69 | /* Create a decoder instance */ |
66 | wpc = WavpackOpenFileInput (read_callback, error); | 70 | wpc = WavpackOpenFileInput (read_callback, error); |
@@ -75,7 +79,12 @@ enum codec_status codec_run(void) | |||
75 | ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); | 79 | ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); |
76 | sr_100 = ci->id3->frequency / 100; | 80 | sr_100 = ci->id3->frequency / 100; |
77 | 81 | ||
78 | ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); | 82 | if (!offset && param) { |
83 | goto resume_start; /* resume by elapsed */ | ||
84 | } | ||
85 | else { | ||
86 | ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); | ||
87 | } | ||
79 | 88 | ||
80 | /* The main decoder loop */ | 89 | /* The main decoder loop */ |
81 | 90 | ||
@@ -87,6 +96,7 @@ enum codec_status codec_run(void) | |||
87 | break; | 96 | break; |
88 | 97 | ||
89 | if (action == CODEC_ACTION_SEEK_TIME) { | 98 | if (action == CODEC_ACTION_SEEK_TIME) { |
99 | resume_start:; | ||
90 | int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; | 100 | int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; |
91 | int n, d, skip; | 101 | int n, d, skip; |
92 | 102 | ||
diff --git a/lib/rbcodec/codecs/wma.c b/lib/rbcodec/codecs/wma.c index 9039f81429..9a5e0c71fa 100755 --- a/lib/rbcodec/codecs/wma.c +++ b/lib/rbcodec/codecs/wma.c | |||
@@ -52,13 +52,16 @@ enum codec_status codec_run(void) | |||
52 | int audiobufsize; | 52 | int audiobufsize; |
53 | int packetlength = 0; | 53 | int packetlength = 0; |
54 | int errcount = 0; | 54 | int errcount = 0; |
55 | enum codec_command_action action; | ||
55 | intptr_t param; | 56 | intptr_t param; |
56 | 57 | ||
57 | /* Remember the resume position - when the codec is opened, the | 58 | /* Remember the resume position - when the codec is opened, the |
58 | playback engine will reset it. */ | 59 | playback engine will reset it. */ |
60 | elapsedtime = ci->id3->elapsed; | ||
59 | resume_offset = ci->id3->offset; | 61 | resume_offset = ci->id3->offset; |
60 | 62 | ||
61 | restart_track: | 63 | restart_track: |
64 | action = CODEC_ACTION_NULL; | ||
62 | 65 | ||
63 | /* Proper reset of the decoder context. */ | 66 | /* Proper reset of the decoder context. */ |
64 | memset(&wmadec, 0, sizeof(wmadec)); | 67 | memset(&wmadec, 0, sizeof(wmadec)); |
@@ -78,13 +81,20 @@ restart_track: | |||
78 | return CODEC_ERROR; | 81 | return CODEC_ERROR; |
79 | } | 82 | } |
80 | 83 | ||
81 | if (resume_offset > ci->id3->first_frame_offset) | 84 | if (resume_offset > ci->id3->first_frame_offset || elapsedtime) |
82 | { | 85 | { |
83 | /* Get start of current packet */ | 86 | if (resume_offset) { |
84 | int packet_offset = (resume_offset - ci->id3->first_frame_offset) | 87 | /* Get start of current packet */ |
85 | % wfx.packet_size; | 88 | int packet_offset = (resume_offset - |
86 | ci->seek_buffer(resume_offset - packet_offset); | 89 | MIN(resume_offset, ci->id3->first_frame_offset)) |
87 | elapsedtime = asf_get_timestamp(&i); | 90 | % wfx.packet_size; |
91 | ci->seek_buffer(resume_offset - packet_offset); | ||
92 | elapsedtime = asf_get_timestamp(&i); | ||
93 | } | ||
94 | else { | ||
95 | param = elapsedtime; | ||
96 | action = CODEC_ACTION_SEEK_TIME; | ||
97 | } | ||
88 | } | 98 | } |
89 | else | 99 | else |
90 | { | 100 | { |
@@ -104,7 +114,8 @@ restart_track: | |||
104 | /* The main decoding loop */ | 114 | /* The main decoding loop */ |
105 | while (res >= 0) | 115 | while (res >= 0) |
106 | { | 116 | { |
107 | enum codec_command_action action = ci->get_command(¶m); | 117 | if (action == CODEC_ACTION_NULL) |
118 | action = ci->get_command(¶m); | ||
108 | 119 | ||
109 | if (action != CODEC_ACTION_NULL) { | 120 | if (action != CODEC_ACTION_NULL) { |
110 | 121 | ||
@@ -126,6 +137,7 @@ restart_track: | |||
126 | if (param == 0) { | 137 | if (param == 0) { |
127 | ci->set_elapsed(0); | 138 | ci->set_elapsed(0); |
128 | ci->seek_complete(); | 139 | ci->seek_complete(); |
140 | elapsedtime = 0; | ||
129 | goto restart_track; /* Pretend you never saw this... */ | 141 | goto restart_track; /* Pretend you never saw this... */ |
130 | } | 142 | } |
131 | 143 | ||
@@ -140,6 +152,8 @@ restart_track: | |||
140 | ci->set_elapsed(elapsedtime); | 152 | ci->set_elapsed(elapsedtime); |
141 | ci->seek_complete(); | 153 | ci->seek_complete(); |
142 | } | 154 | } |
155 | |||
156 | action = CODEC_ACTION_NULL; | ||
143 | } | 157 | } |
144 | 158 | ||
145 | errcount = 0; | 159 | errcount = 0; |
diff --git a/lib/rbcodec/codecs/wmapro.c b/lib/rbcodec/codecs/wmapro.c index d99ca1aa9e..f15f36813d 100644 --- a/lib/rbcodec/codecs/wmapro.c +++ b/lib/rbcodec/codecs/wmapro.c | |||
@@ -55,6 +55,8 @@ enum codec_status codec_run(void) | |||
55 | int size; /* Size of the input frame to the decoder */ | 55 | int size; /* Size of the input frame to the decoder */ |
56 | intptr_t param; | 56 | intptr_t param; |
57 | 57 | ||
58 | elapsedtime = ci->id3->elapsed; | ||
59 | |||
58 | restart_track: | 60 | restart_track: |
59 | if (codec_init()) { | 61 | if (codec_init()) { |
60 | LOGF("(WMA PRO) Error: Error initialising codec\n"); | 62 | LOGF("(WMA PRO) Error: Error initialising codec\n"); |
@@ -75,11 +77,17 @@ restart_track: | |||
75 | return CODEC_ERROR; | 77 | return CODEC_ERROR; |
76 | } | 78 | } |
77 | 79 | ||
78 | /* Now advance the file position to the first frame */ | 80 | if (elapsedtime) { |
79 | ci->seek_buffer(ci->id3->first_frame_offset); | 81 | elapsedtime = asf_seek(elapsedtime, &wfx); |
82 | if (elapsedtime < 1) | ||
83 | return CODEC_OK; | ||
84 | } | ||
85 | else { | ||
86 | /* Now advance the file position to the first frame */ | ||
87 | ci->seek_buffer(ci->id3->first_frame_offset); | ||
88 | } | ||
80 | 89 | ||
81 | elapsedtime = 0; | 90 | ci->set_elapsed(elapsedtime); |
82 | ci->set_elapsed(0); | ||
83 | 91 | ||
84 | /* The main decoding loop */ | 92 | /* The main decoding loop */ |
85 | 93 | ||
@@ -95,6 +103,7 @@ restart_track: | |||
95 | if (param == 0) { | 103 | if (param == 0) { |
96 | ci->set_elapsed(0); | 104 | ci->set_elapsed(0); |
97 | ci->seek_complete(); | 105 | ci->seek_complete(); |
106 | elapsedtime = 0; | ||
98 | goto restart_track; /* Pretend you never saw this... */ | 107 | goto restart_track; /* Pretend you never saw this... */ |
99 | } | 108 | } |
100 | 109 | ||
diff --git a/lib/rbcodec/codecs/wmavoice.c b/lib/rbcodec/codecs/wmavoice.c index 214e0737e7..4c89c6dc96 100644 --- a/lib/rbcodec/codecs/wmavoice.c +++ b/lib/rbcodec/codecs/wmavoice.c | |||
@@ -67,7 +67,6 @@ enum codec_status codec_run(void) | |||
67 | { | 67 | { |
68 | uint32_t elapsedtime; | 68 | uint32_t elapsedtime; |
69 | asf_waveformatex_t wfx; /* Holds the stream properties */ | 69 | asf_waveformatex_t wfx; /* Holds the stream properties */ |
70 | size_t resume_offset; | ||
71 | int res; /* Return values from asf_read_packet() and decode_packet() */ | 70 | int res; /* Return values from asf_read_packet() and decode_packet() */ |
72 | uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ | 71 | uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ |
73 | int audiobufsize; /* Payload size */ | 72 | int audiobufsize; /* Payload size */ |
@@ -76,8 +75,8 @@ enum codec_status codec_run(void) | |||
76 | int pktcnt = 0; /* Count of the packets played */ | 75 | int pktcnt = 0; /* Count of the packets played */ |
77 | intptr_t param; | 76 | intptr_t param; |
78 | 77 | ||
79 | /* Remember the resume position */ | 78 | elapsedtime = ci->id3->elapsed; |
80 | resume_offset = ci->id3->offset; | 79 | |
81 | restart_track: | 80 | restart_track: |
82 | if (codec_init()) { | 81 | if (codec_init()) { |
83 | LOGF("(WMA Voice) Error: Error initialising codec\n"); | 82 | LOGF("(WMA Voice) Error: Error initialising codec\n"); |
@@ -105,13 +104,17 @@ restart_track: | |||
105 | return CODEC_ERROR; | 104 | return CODEC_ERROR; |
106 | } | 105 | } |
107 | 106 | ||
108 | /* Now advance the file position to the first frame */ | 107 | if (elapsedtime) { |
109 | ci->seek_buffer(ci->id3->first_frame_offset); | 108 | elapsedtime = asf_seek(elapsedtime, &wfx); |
110 | 109 | if (elapsedtime < 1) | |
111 | elapsedtime = 0; | 110 | return CODEC_OK; |
112 | ci->set_elapsed(0); | 111 | } |
112 | else { | ||
113 | /* Now advance the file position to the first frame */ | ||
114 | ci->seek_buffer(ci->id3->first_frame_offset); | ||
115 | } | ||
113 | 116 | ||
114 | resume_offset = 0; | 117 | ci->set_elapsed(elapsedtime); |
115 | 118 | ||
116 | /* The main decoding loop */ | 119 | /* The main decoding loop */ |
117 | 120 | ||
@@ -129,6 +132,7 @@ restart_track: | |||
129 | if (param == 0) { | 132 | if (param == 0) { |
130 | ci->set_elapsed(0); | 133 | ci->set_elapsed(0); |
131 | ci->seek_complete(); | 134 | ci->seek_complete(); |
135 | elapsedtime = 0; | ||
132 | goto restart_track; /* Pretend you never saw this... */ | 136 | goto restart_track; /* Pretend you never saw this... */ |
133 | } | 137 | } |
134 | 138 | ||
@@ -136,7 +140,7 @@ restart_track: | |||
136 | if (elapsedtime < 1){ | 140 | if (elapsedtime < 1){ |
137 | ci->set_elapsed(0); | 141 | ci->set_elapsed(0); |
138 | ci->seek_complete(); | 142 | ci->seek_complete(); |
139 | goto next_track; | 143 | break; |
140 | } | 144 | } |
141 | 145 | ||
142 | ci->set_elapsed(elapsedtime); | 146 | ci->set_elapsed(elapsedtime); |